Skip to content

Commit 88a6e0e

Browse files
authored
Merge pull request #1 from kazu-321/humble
feat: support high speed communication and add temperature
2 parents f551aa1 + 52b4f1a commit 88a6e0e

File tree

7 files changed

+165
-58
lines changed

7 files changed

+165
-58
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,27 @@
11
# cxd5602pwbimu_ros2_driver
22
ROS 2 driver for Multi-IMU Add-on board for SONY SPRESENSE™
3+
High speed version up to 1.92 kHz
34

4-
[![ci_humble](https://github.com/NITKK-ROS-Team/cxd5602pwbimu_ros2_driver/actions/workflows/ci_humble.yml/badge.svg)](https://github.com/NITKK-ROS-Team/cxd5602pwbimu_ros2_driver/actions/workflows/ci_humble.yml)
5+
[![ci_humble](https://github.com/NITKK-ROS-Team/cxd5602pwbimu_ros2_driver/actions/workflows/ci_humble.yml/badge.svg)](https://github.com/NITKK-ROS-Team/cxd5602pwbimu_ros2_driver/actions/workflows/ci_humble.yml)
6+
7+
## Flash
8+
### 1. Setup Arduino IDE for SPRESENSE
9+
Follow the instructions on the official SPRESENSE Arduino IDE setup guide:
10+
[https://developer.sony.com/spresense/development-guides/arduino_set_up_ja](https://developer.sony.com/spresense/development-guides/arduino_set_up_ja)
11+
12+
### 2. Flash INO Sketch
13+
`firmware/cxd5602pwbimu/cxd5602pwbimu.ino` to SPRESENSE main board using Arduino IDE.
14+
15+
## Build
16+
```bash
17+
git clone <this repo url>
18+
cd cxd5602pwbimu_ros2_driver
19+
git clone -b humble https://github.com/HarvestX/h6x_serial_interface.git
20+
colcon build --symlink-install
21+
```
22+
23+
## Launch
24+
```bash
25+
source install/setup.bash
26+
ros2 launch cxd5602pwbimu_driver_bringup cxd5602pwbimu.launch.py
27+
```

cxd5602pwbimu_driver_bringup/launch/cxd5602pwbimu.launch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ def generate_launch_description():
99
executable='cxd5602pwbimu_driver_node_exec',
1010
name='cxd5602pwbimu_driver_node',
1111
output='screen',
12-
parameters=[{'device': '/dev/ttyUSB0'}]
12+
parameters=[{'device': '/dev/ttyUSB0', 'baudrate': 1000000}]
1313
)
1414

1515
imu_filter_node = Node(
1616
package='imu_filter_madgwick',
1717
executable='imu_filter_madgwick_node',
1818
name='imu_filter_madgwick_node',
1919
output='screen',
20-
parameters=[{'use_mag': False}]
20+
parameters=[{'use_mag': False, 'remove_gravity_vector': True}]
2121
)
2222

2323
rviz_node = Node(

cxd5602pwbimu_driver_node/include/cxd5602pwbimu_driver_node/cxd5602pwbimu_driver_node.hpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
#define ____CXD5602PWBIMU_DRIVER_NODE_CXD5602PWBIMU_DRIVER_NODE_HPP__
99

1010
#include <functional>
11+
#include <thread>
12+
#include <atomic>
1113
#include <h6x_serial_interface/h6x_serial_interface.hpp>
1214
#include <rclcpp/rclcpp.hpp>
1315
#include <sensor_msgs/msg/imu.hpp>
16+
#include <sensor_msgs/msg/temperature.hpp>
1417

1518
#include "imu_class.hpp"
1619

@@ -23,23 +26,26 @@ class Cxd5602pwbimuDriverNode : public rclcpp::Node
2326
using PortHandler = h6x_serial_interface::PortHandler;
2427
PortHandler port_handler_;
2528
uint32_t time_offset_;
26-
const char delimiter_;
27-
28-
rclcpp::TimerBase::SharedPtr read_timer_;
29+
const char delimiter_, start_byte_;
2930

3031
std::unique_ptr<ImuClass> imu_;
3132
rclcpp::Publisher<sensor_msgs::msg::Imu>::SharedPtr publisher_;
32-
rclcpp::TimerBase::SharedPtr timer_;
33+
rclcpp::Publisher<sensor_msgs::msg::Temperature>::SharedPtr temp_publisher_;
34+
35+
std::thread recv_thread_;
36+
std::atomic<bool> running_;
3337

3438
public:
3539
Cxd5602pwbimuDriverNode() = delete;
3640
explicit Cxd5602pwbimuDriverNode(const rclcpp::NodeOptions &);
3741
~Cxd5602pwbimuDriverNode();
3842

3943
private:
40-
void timerCallback();
41-
44+
void startSerialThread();
4245

46+
void processPacket(const uint8_t* data, size_t size);
4347
};
48+
4449
} // namespace cxd5602pwbimu_driver_node
50+
4551
#endif // ____CXD5602PWBIMU_DRIVER_NODE_CXD5602PWBIMU_DRIVER_NODE_HPP__

cxd5602pwbimu_driver_node/include/cxd5602pwbimu_driver_node/imu_class.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ class ImuClass
2626

2727
bool set_data(const uint8_t *, size_t);
2828
void print_data() const;
29-
std::tuple<std::array<float, 3>, std::array<float, 3>, uint32_t, uint32_t> get_data() const;
29+
std::tuple<std::array<float, 3>, std::array<float, 3>, float, uint32_t, uint32_t> get_data() const;
3030

3131
private:
3232
std::array<float, 3> linear_acceleration_;
3333
std::array<float, 3> angular_velocity_;
34+
const char delimiter_, start_byte_;
35+
float temperature_;
3436
uint32_t sec_;
3537
uint32_t msec_;
3638
};

cxd5602pwbimu_driver_node/src/cxd5602pwbimu_driver_node.cpp

Lines changed: 82 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,69 +13,117 @@ Cxd5602pwbimuDriverNode::Cxd5602pwbimuDriverNode(const rclcpp::NodeOptions & opt
1313
: rclcpp::Node("imu_publisher", options),
1414
port_handler_(this->declare_parameter<std::string>("dev", "/dev/ttyUSB0")),
1515
time_offset_(0),
16-
delimiter_(this->declare_parameter<char>("delimiter", '\n'))
16+
delimiter_(this->declare_parameter<char>("delimiter", '\n')),
17+
start_byte_(this->declare_parameter<char>("start_byte", 'X')),
18+
running_(true)
1719
{
1820
const int baudrate = this->declare_parameter<int>("baudrate", 115200);
1921
const int timeout_ms = this->declare_parameter<int>("timeout_ms", 100);
20-
const int spin_ms = this->declare_parameter<int>("spin_ms", 1);
2122

2223
imu_ = std::make_unique<ImuClass>();
23-
publisher_ = this->create_publisher<sensor_msgs::msg::Imu>(
24-
"/imu/data_raw", rclcpp::SensorDataQoS());
24+
publisher_ = this->create_publisher<sensor_msgs::msg::Imu>("/imu/data_raw", rclcpp::SensorDataQoS());
25+
temp_publisher_ = this->create_publisher<sensor_msgs::msg::Temperature>("/imu/temperature", rclcpp::SensorDataQoS());
2526

26-
if (!this->port_handler_.configure(baudrate, timeout_ms)) {
27-
RCLCPP_ERROR(this->get_logger(), "Failed to configure serial port");
27+
if (!port_handler_.configure(baudrate, timeout_ms)) {
28+
RCLCPP_ERROR(get_logger(), "Failed to configure serial port");
2829
exit(EXIT_FAILURE);
2930
}
3031

31-
if (!this->port_handler_.open()) {
32-
RCLCPP_ERROR(this->get_logger(), "Failed to open serial port");
32+
if (!port_handler_.open()) {
33+
RCLCPP_ERROR(get_logger(), "Failed to open serial port");
3334
exit(EXIT_FAILURE);
3435
}
3536

36-
this->timer_ = this->create_wall_timer(
37-
std::chrono::milliseconds(spin_ms), std::bind(&Cxd5602pwbimuDriverNode::timerCallback, this));
37+
RCLCPP_INFO(get_logger(), "Serial port opened successfully");
38+
startSerialThread();
3839
}
3940

4041
Cxd5602pwbimuDriverNode::~Cxd5602pwbimuDriverNode()
4142
{
42-
this->port_handler_.close();
43+
running_ = false;
44+
if (recv_thread_.joinable()) {
45+
recv_thread_.join();
46+
}
47+
port_handler_.close();
4348
}
4449

45-
void Cxd5602pwbimuDriverNode::timerCallback()
50+
void Cxd5602pwbimuDriverNode::startSerialThread()
4651
{
47-
this->timer_->cancel();
52+
recv_thread_ = std::thread([this]() {
53+
std::string buf;
54+
buf.reserve(39);
55+
char c;
56+
57+
while (running_) {
58+
int n = port_handler_.read(&c, 1);
59+
if (n != 1) {
60+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
61+
continue;
62+
}
63+
64+
buf.push_back(c);
65+
66+
if (buf.front() != start_byte_) {
67+
buf.erase(buf.begin());
68+
continue;
69+
}
70+
71+
if (buf.size() == 39) {
72+
if (buf.back() == delimiter_) {
73+
processPacket(reinterpret_cast<const uint8_t*>(buf.data()), buf.size());
74+
} else {
75+
char skip;
76+
do {
77+
if (port_handler_.read(&skip, 1) != 1) break;
78+
RCLCPP_DEBUG(get_logger(), "Skipping byte: %c %d", skip, skip==delimiter_);
79+
} while (skip != delimiter_);
80+
RCLCPP_WARN_THROTTLE(get_logger(), *this->get_clock(), 5000, "Resynchronized at delimiter");
81+
}
82+
buf.clear();
83+
}
84+
}
4885

49-
std::stringstream ss;
50-
this->port_handler_.readUntil(ss, delimiter_);
86+
});
87+
}
5188

52-
std::string buffer = ss.str();
89+
void Cxd5602pwbimuDriverNode::processPacket(const uint8_t* data, size_t size)
90+
{
91+
if (!imu_->set_data(data, size)) {
92+
RCLCPP_WARN(get_logger(), "Failed to parse IMU data");
93+
return;
94+
}
5395

54-
if (imu_->set_data(reinterpret_cast<const uint8_t *>(buffer.c_str()), buffer.size())) {
55-
auto [linear_acceleration, angular_velocity, sec, msec] = imu_->get_data();
96+
auto [linear_acc, angular_vel, temperature, sec, msec] = imu_->get_data();
5697

57-
auto msg = std::make_unique<sensor_msgs::msg::Imu>();
98+
auto msg = sensor_msgs::msg::Imu();
5899

59-
if (time_offset_ == 0) {
60-
time_offset_ = static_cast<uint32_t>(std::time(nullptr));
61-
}
100+
if (time_offset_ == 0) {
101+
time_offset_ = static_cast<uint32_t>(std::time(nullptr));
102+
}
62103

63-
msg->header.frame_id = "imu";
64-
msg->header.stamp.sec = sec + time_offset_;
65-
msg->header.stamp.nanosec = msec * 1000000;
104+
msg.header.frame_id = "imu";
105+
msg.header.stamp.sec = sec + time_offset_;
106+
msg.header.stamp.nanosec = msec * 1000000;
66107

67-
msg->linear_acceleration.x = linear_acceleration[0];
68-
msg->linear_acceleration.y = linear_acceleration[1];
69-
msg->linear_acceleration.z = linear_acceleration[2];
108+
msg.linear_acceleration.x = -linear_acc[0];
109+
msg.linear_acceleration.y = -linear_acc[1];
110+
msg.linear_acceleration.z = linear_acc[2];
70111

71-
msg->angular_velocity.x = angular_velocity[0] * 0.5;
72-
msg->angular_velocity.y = angular_velocity[1] * 0.5;
73-
msg->angular_velocity.z = angular_velocity[2] * 0.5;
112+
msg.angular_velocity.x = -angular_vel[0] * 0.5;
113+
msg.angular_velocity.y = -angular_vel[1] * 0.5;
114+
msg.angular_velocity.z = angular_vel[2] * 0.5;
74115

75-
publisher_->publish(std::move(msg));
76-
}
116+
msg.orientation_covariance[0] = -1;
117+
msg.linear_acceleration_covariance[0] = -1;
118+
msg.angular_velocity_covariance[0] = -1;
119+
120+
publisher_->publish(msg);
77121

78-
this->timer_->reset();
122+
auto temp_msg = sensor_msgs::msg::Temperature();
123+
temp_msg.header = msg.header;
124+
temp_msg.temperature = temperature;
125+
temp_msg.variance = -1;
126+
temp_publisher_->publish(temp_msg);
79127
}
80128

81129
}

cxd5602pwbimu_driver_node/src/imu_class.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,35 @@ namespace cxd5602pwbimu_driver_node
1212
ImuClass::ImuClass()
1313
: linear_acceleration_({0.0, 0.0, 0.0}),
1414
angular_velocity_({0.0, 0.0, 0.0}),
15+
temperature_(0.0),
1516
sec_(0),
16-
msec_(0) {}
17+
msec_(0),
18+
delimiter_('\n'),
19+
start_byte_('X') {}
1720

1821
bool ImuClass::set_data(const uint8_t * data_bytes, size_t length)
1922
{
20-
if (length != 36) {
23+
const size_t expected_length = 39;
24+
const size_t crc_index = expected_length - 2;
25+
if (length != expected_length) {
26+
std::cerr << "Invalid data length: " << length << std::endl;
2127
return false;
2228
}
23-
if (data_bytes[0] != 'X') {
29+
if (data_bytes[0] != start_byte_) {
30+
std::cerr << "Invalid start byte: " << static_cast<int>(data_bytes[0]) << std::endl;
31+
return false;
32+
}
33+
if (data_bytes[expected_length - 1] != delimiter_) {
34+
std::cerr << "Invalid end byte: " << static_cast<int>(data_bytes[expected_length - 1]) << std::endl;
2435
return false;
2536
}
2637

2738
CRC8 hash_obj(0x07);
28-
hash_obj.add(data_bytes, 33);
39+
hash_obj.add(data_bytes, crc_index);
2940

30-
if (hash_obj.calc() != data_bytes[33]) {
41+
if (hash_obj.calc() != data_bytes[crc_index]) {
42+
std::cerr << "CRC mismatch: calculated " << static_cast<int>(hash_obj.calc())
43+
<< ", received " << static_cast<int>(data_bytes[crc_index]) << std::endl;
3144
return false;
3245
}
3346

@@ -49,6 +62,10 @@ bool ImuClass::set_data(const uint8_t * data_bytes, size_t length)
4962
offset += 4;
5063
}
5164

65+
float temp;
66+
std::memcpy(&temp, &data_bytes[offset], sizeof(float));
67+
temperature_ = temp;
68+
5269
return true;
5370
}
5471

@@ -63,12 +80,13 @@ void ImuClass::print_data() const
6380
<< angular_velocity_[0] << ", "
6481
<< angular_velocity_[1] << ", "
6582
<< angular_velocity_[2] << "]" << std::endl;
83+
std::cout << "Temperature: " << temperature_ << " C" << std::endl;
6684
}
6785

68-
std::tuple<std::array<float, 3>, std::array<float, 3>, uint32_t,
86+
std::tuple<std::array<float, 3>, std::array<float, 3>, float, uint32_t,
6987
uint32_t> ImuClass::get_data() const
7088
{
71-
return {linear_acceleration_, angular_velocity_, sec_, msec_};
89+
return {linear_acceleration_, angular_velocity_, temperature_, sec_, msec_};
7290
}
7391

7492
} // namespace cxd5602pwbimu_driver_node
Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,36 +65,42 @@ static int drop_50msdata(int fd, int samprate)
6565
}
6666

6767
void setup() {
68+
Serial.begin(1000000);
69+
6870
int devfd;
6971
board_cxd5602pwbimu_initialize(5);
7072

7173
devfd = open(CXD5602PWBIMU_DRIVER_DEVPATH, O_RDONLY);
72-
start_sensing(devfd, 960, 16, 4000, MAX_NFIFO);
73-
drop_50msdata(devfd, 960);
74+
start_sensing(devfd, 1920, 16, 4000, MAX_NFIFO);
75+
drop_50msdata(devfd, 1920);
7476
delay(2000);
7577

7678
int32_t sec = 0;
7779
int32_t msec = 0;
7880

7981
float linear_acceleration[3] = {0};
8082
float angular_velocity[3] = {0};
83+
float temperature = 0;
8184
while(1) {
8285
int ret = read(devfd, g_data, sizeof(g_data[0]) * MAX_NFIFO);
8386
if(ret == sizeof(g_data[0]) * MAX_NFIFO) {
8487
for(int i=0; i<MAX_NFIFO; i++) {
85-
linear_acceleration[0] = -g_data[i].ax;
86-
linear_acceleration[1] = -g_data[i].ay;
87-
linear_acceleration[2] = -g_data[i].az;
88-
angular_velocity[0] = -g_data[i].gx;
89-
angular_velocity[1] = -g_data[i].gy;
88+
linear_acceleration[0] = g_data[i].ax;
89+
linear_acceleration[1] = g_data[i].ay;
90+
linear_acceleration[2] = g_data[i].az;
91+
angular_velocity[0] = g_data[i].gx;
92+
angular_velocity[1] = g_data[i].gy;
9093
angular_velocity[2] = g_data[i].gz;
94+
temperature = g_data[i].temp;
9195

9296
float2byte f2b_linear_acceleration[3];
9397
float2byte f2b_angular_velocity[3];
98+
float2byte f2b_temperature;
9499
for(int j=0; j<3; j++) {
95100
f2b_linear_acceleration[j].f = linear_acceleration[j];
96101
f2b_angular_velocity[j].f = angular_velocity[j];
97102
}
103+
f2b_temperature.f = temperature;
98104

99105
get_time(sec, msec);
100106

@@ -104,6 +110,7 @@ void setup() {
104110
crc.add((uint8_t*)&msec, 4);
105111
crc.add((uint8_t*)&linear_acceleration, 12);
106112
crc.add((uint8_t*)&angular_velocity, 12);
113+
crc.add((uint8_t*)&temperature, 4);
107114
uint8_t crc8 = crc.calc();
108115

109116
printf("%c", SERIAL_HEADER);
@@ -123,6 +130,9 @@ void setup() {
123130
printf("%c", f2b.b[j]);
124131
}
125132
}
133+
for(int i=0;i<4;i++) {
134+
printf("%c", f2b_temperature.b[i]);
135+
}
126136
printf("%c\n", crc8);
127137
}
128138
}

0 commit comments

Comments
 (0)