-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhancement/new thruster interface #179
Open
vincent554
wants to merge
28
commits into
development
Choose a base branch
from
enhancement/new-thruster-interface
base: development
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
d7efbc7
vincent is testing stuff jesjes
cd11fee
Committing clang-format changes
87e55d7
Worked on the new library, program exits when there is a problem, sen…
62231b4
Committing clang-format changes
800638b
Worked on 2-way communication
cd69302
Committing clang-format changes
82f499a
finished up on the 2way i2c communication
60adccc
Committing clang-format changes
c4d1f0d
added interpolation of force values into pwm values
c4f7366
Committing clang-format changes
142ae2d
Started working on the ros part. Created a listening node that uses f…
1111cc6
Committing clang-format changes
c51f1c4
worked on the reading part of the ros node
da7a9cd
Committing clang-format changes
c905e47
tested the reading and I2C sending part, cleaned up a little bit
RoseKapps 20da2fd
Committing clang-format changes
cc516d7
added publishing of temperature and status, not connected to i2c yet
361ca46
Committing clang-format changes
db77559
Added publishing of 2 more temperatures, and subscribed to an interna…
RoseKapps 3219836
Committing clang-format changes
f1e1116
cleanup and added ros2 parameters for the timer and pwm min/max
4afa343
Committing clang-format changes
80e36f5
Added exception handling and changed message type from vortex msg to …
b68956e
Committing clang-format changes
b336ed5
forgot smth
df35b2c
Merge branch 'enhancement/new-thruster-interface' of https://github.c…
6359b5e
Done!
vortexuser 193708a
Committing clang-format changes
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 37 additions & 16 deletions
53
motion/thruster_interface/include/thruster_interface/thruster_interface.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,52 @@ | ||
#pragma once | ||
|
||
#include <chrono> | ||
#include <cmath> | ||
#include <cstdint> | ||
#include <cstring> // Include for memcpy | ||
#include <fcntl.h> | ||
#include <fstream> | ||
#include <iostream> | ||
#include <linux/i2c-dev.h> | ||
#include <map> | ||
#include <sstream> | ||
#include <string> | ||
#include <sys/ioctl.h> | ||
#include <thread> | ||
#include <unistd.h> | ||
#include <vector> | ||
using namespace std; | ||
|
||
class ThrusterInterface { | ||
private: | ||
std::map<double, double> pwm_table; | ||
const int I2C_BUS = 1; | ||
const int I2C_ADDRESS = 0x21; | ||
const char *I2C_DEVICE = "/dev/i2c-1"; | ||
#ifndef PWM_TABLE_HPP | ||
#define PWM_TABLE_HPP | ||
extern const char *I2C_DEVICE; | ||
extern int8_t i2c_slave_addr; | ||
extern std::map<float, float> pwm_table; | ||
#endif | ||
|
||
//--------------------------INITIALISATION-------------------------- | ||
void init(int &file); | ||
|
||
//--------------------------SENDING-------------------------- | ||
void send_status(int8_t status, int file); | ||
std::vector<uint8_t> pwm_to_bytes(std::vector<uint16_t> pwm_values); | ||
void send_pwm(std::vector<uint16_t> pwm_values, int file); | ||
|
||
//--------------------------RECEIVING-------------------------- | ||
std::vector<float> readFloatsFromI2C(int file); | ||
uint8_t read_hardware_statusFromI2C(int file); | ||
|
||
std::vector<uint8_t> pwm_to_bytes(const std::vector<int> &pwm_values); | ||
//--------------------------INTERPOLATION-------------------------- | ||
void get_pwm_table(); | ||
uint16_t interpolate(double force, int PWM_min, int PWM_max); | ||
std::vector<uint16_t> interpolate_all(std::vector<double> &force_values, | ||
int PWM_min = 1100, int PWM_max = 1900); | ||
|
||
class I2C_Exception : public std::exception { | ||
private: | ||
string message = " "; | ||
|
||
public: | ||
ThrusterInterface(std::string mapping_file); | ||
void publish_thrust_to_escs(std::vector<double> forces); | ||
float interpolate(float force); | ||
}; | ||
I2C_Exception(string msg) { message = msg; } | ||
|
||
const char *what() const | ||
|
||
noexcept override { | ||
return message.c_str(); | ||
} | ||
}; |
31 changes: 0 additions & 31 deletions
31
motion/thruster_interface/include/thruster_interface/thruster_interface_node.hpp
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,111 +1,160 @@ | ||
#include <thruster_interface/thruster_interface.hpp> | ||
|
||
ThrusterInterface::ThrusterInterface(std::string mapping_file) { | ||
// Open the data file | ||
std::ifstream data(mapping_file); | ||
|
||
if (!data.is_open()) { | ||
std::cerr << "Unable to open file\n"; | ||
exit(1); | ||
} | ||
|
||
std::string line; | ||
// Ignore the header line | ||
std::getline(data, line); | ||
const char *I2C_DEVICE = "/dev/i2c-1"; | ||
int8_t i2c_slave_addr = 0x21; // change later to 0x21 | ||
std::map<float, float> pwm_table; | ||
|
||
while (std::getline(data, line)) { | ||
std::istringstream stream(line); | ||
|
||
std::string force_str, pwm_str; | ||
//--------------------------FUNCTIONS-------------------------- | ||
|
||
std::getline(stream, force_str, '\t'); | ||
std::getline(stream, pwm_str); | ||
//--------------------------INITIALISATION-------------------------- | ||
|
||
double force = std::stod(force_str); | ||
double pwm = std::stod(pwm_str); | ||
void init(int &file) { | ||
if ((file = open(I2C_DEVICE, O_RDWR)) < 0) { | ||
throw I2C_Exception("error, could not connect to i2c bus"); | ||
} else { | ||
std::cout << "connected to i2c bus!!" << std::endl; | ||
} | ||
|
||
pwm_table[force] = pwm; | ||
if (ioctl(file, I2C_SLAVE, i2c_slave_addr) < 0) { | ||
throw I2C_Exception("error, could not set address"); | ||
} else { | ||
std::cout << "i2c adress set" << std::endl; | ||
} | ||
} | ||
|
||
float ThrusterInterface::interpolate(float force) { | ||
auto upper_bound = pwm_table.upper_bound(force); | ||
if (upper_bound == pwm_table.end()) { | ||
--upper_bound; | ||
} | ||
auto lower_bound = std::prev(upper_bound); | ||
//--------------------------SENDING-------------------------- | ||
|
||
if (lower_bound == pwm_table.end()) { | ||
return upper_bound->second; | ||
void send_status(int8_t status, int file) { | ||
if (write(file, &status, 1) != 1) { | ||
throw I2C_Exception("error, could not send status"); | ||
} else { | ||
std::cout << "status data has been sent" << std::endl; | ||
} | ||
} | ||
|
||
float force1 = lower_bound->first; | ||
float force2 = upper_bound->first; | ||
|
||
float pwm1 = lower_bound->second; | ||
float pwm2 = upper_bound->second; | ||
|
||
if (force1 == force2) { | ||
return pwm1; | ||
void send_pwm(std::vector<uint16_t> pwm_values, int file) { | ||
std::vector<uint8_t> bytes = pwm_to_bytes(pwm_values); | ||
if (static_cast<size_t>(write(file, bytes.data(), bytes.size())) != | ||
bytes.size()) { | ||
throw I2C_Exception("error, could not send PWM data"); | ||
} else { | ||
std::cout << "PWM data has been sent" << std::endl; | ||
} | ||
|
||
int pwm_signal = std::round( | ||
pwm1 + ((force - force1) * (pwm2 - pwm1)) / (force2 - force1) + 0.5); | ||
|
||
return pwm_signal; | ||
} | ||
|
||
std::vector<uint8_t> | ||
ThrusterInterface::pwm_to_bytes(const std::vector<int> &pwm_values) { | ||
std::vector<uint8_t> pwm_to_bytes(std::vector<uint16_t> pwm_values) { | ||
|
||
std::vector<uint8_t> bytes; | ||
for (const auto &val : pwm_values) { | ||
// Ensure the value is in the correct range and cast to an integer | ||
int pwm_int = static_cast<int>( | ||
std::min(std::max(val, 1400), 1600)); // min 1100, max 1900 | ||
|
||
for (size_t i = 0; i < pwm_values.size(); ++i) { | ||
// Split the integer into most significant byte (MSB) and least significant | ||
// byte (LSB) | ||
uint8_t msb = (pwm_int >> 8) & 0xFF; | ||
uint8_t lsb = pwm_int & 0xFF; | ||
|
||
uint8_t msb = (pwm_values[i] >> 8) & 0xFF; | ||
uint8_t lsb = pwm_values[i] & 0xFF; | ||
// Add MSB and LSB to the bytes vector | ||
bytes.push_back(msb); | ||
bytes.push_back(lsb); | ||
} | ||
return bytes; | ||
} | ||
|
||
void ThrusterInterface::publish_thrust_to_escs(std::vector<double> forces) { | ||
std::vector<int> pwm_values; | ||
for (auto force : forces) { | ||
pwm_values.push_back(interpolate(force)); | ||
//--------------------------RECEIVING-------------------------- | ||
|
||
std::vector<float> readFloatsFromI2C(int file) { | ||
// Define byte length | ||
int num_floats = 6; | ||
int byte_length = num_floats * sizeof(float); | ||
std::vector<float> floats(num_floats); | ||
|
||
// Read a block of bytes from the I2C device | ||
std::vector<uint8_t> data(byte_length); | ||
if (read(file, data.data(), byte_length) != byte_length) { | ||
throw I2C_Exception("Failed to read data from the I2C device"); | ||
return floats; // Returns empty vector if reading fails | ||
} | ||
// Convert the byte array to a list of floats | ||
memcpy(floats.data(), data.data(), byte_length); | ||
return floats; | ||
} | ||
|
||
std::vector<uint8_t> pwm_bytes = pwm_to_bytes(pwm_values); | ||
int data_size = pwm_bytes.size(); | ||
uint8_t read_hardware_statusFromI2C(int file) { | ||
uint8_t hardware_status; | ||
if (read(file, &hardware_status, 1) != 1) { | ||
throw I2C_Exception("Failed to read hardware status from the I2C device"); | ||
} | ||
return hardware_status; | ||
} | ||
|
||
// DEBUG | ||
// for (auto pwm : pwm_values) { | ||
// std::cout << pwm << " "; | ||
//} | ||
// std::cout << std::endl; | ||
//--------------------------INTERPOLATION-------------------------- | ||
|
||
int file = open(I2C_DEVICE, O_RDWR); | ||
if (file < 0) { | ||
std::cerr << "Error opening device\n"; | ||
void get_pwm_table() { | ||
// Open the data file | ||
std::ifstream file("src/vortex-asv/motion/thruster_interface/config/" | ||
"ThrustMe_P1000_force_mapping.csv"); | ||
if (!file.is_open()) { | ||
std::cerr << "Unable to open PWM table\n"; | ||
exit(1); | ||
} | ||
|
||
if (ioctl(file, I2C_SLAVE, I2C_ADDRESS) < 0) { | ||
std::cerr << "Error setting I2C address\n"; | ||
exit(1); | ||
std::string line; | ||
// Ignore the header line | ||
std::getline(file, line); | ||
// read line by line | ||
while (std::getline(file, line)) { | ||
std::istringstream stream(line); | ||
std::string force_str, pwm_str; | ||
std::getline(stream, force_str, '\t'); // read the line until a tab is found | ||
std::getline(stream, pwm_str); // read the rest of the line | ||
// convert into float | ||
float force = std::stod(force_str); | ||
float pwm = std::stod(pwm_str); | ||
// add values to the the table | ||
pwm_table[force] = pwm; | ||
} | ||
file.close(); | ||
} | ||
|
||
uint16_t interpolate(double force, int PWM_min, int PWM_max) { | ||
uint16_t pwm; | ||
if (pwm_table.empty()) { | ||
get_pwm_table(); | ||
} | ||
// Find the first element with a key not less than force | ||
auto it = pwm_table.lower_bound(force); | ||
if (it == pwm_table.begin()) { // If the force is less than or equal to the | ||
// smallest force in the table | ||
pwm = it->second; | ||
} else if (it == pwm_table.end()) { // If the force is greater than or equal | ||
// to the largest force in the table | ||
--it; | ||
pwm = it->second; | ||
} else { | ||
// Linear interpolation | ||
auto prev = std::prev(it); // Get the element with the next smaller key | ||
double force1 = prev->first; | ||
double force2 = it->first; | ||
double pwm1 = prev->second; | ||
double pwm2 = it->second; | ||
pwm = pwm1 + (pwm2 - pwm1) * (force - force1) / (force2 - force1); | ||
} | ||
// check if the calculated pwm values are within the defined limits [PWM_min, | ||
// PWM_max]. | ||
if (pwm < PWM_min) { | ||
return PWM_min; | ||
} else if (pwm > PWM_max) { | ||
return PWM_max; | ||
} else { | ||
return pwm; | ||
} | ||
} | ||
|
||
// Send the I2C message | ||
if (write(file, pwm_bytes.data(), data_size) != data_size) { | ||
std::cerr << "Error sending data, ignoring message...\n"; | ||
std::vector<uint16_t> interpolate_all(std::vector<double> &force_values, | ||
int PWM_min, int PWM_max) { | ||
std::vector<uint16_t> interpolatedVector; | ||
// Interpolate each value in the input vector | ||
for (const auto &force : force_values) { | ||
interpolatedVector.push_back(interpolate(force, PWM_min, PWM_max)); | ||
} | ||
|
||
close(file); | ||
return interpolatedVector; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use
join(get_package_share_directory('asv_setup'),'config','robots','freya.yaml')
instead