小鱼 ROS 2 新书上线!点击链接查看, 新书配套视频点击链接查看。
提问前必看的发帖注意事项—— 提问前必看!不符合要求的问题拒绝回答!!
社区使用指南—如何添加标签修改密码
serial串口通信
-
@凌云这个你问对人啦,小鱼前几天才做了一个开源库,支持在ROS2下几行代码使用串口。
在写FishBot的SDK时,小鱼打算以多种方式进行数据的通信的,包括串口、UDP、TCP等,所以就对通信模块进行了封装,实现简单的更换配置,完成协议的切换。
因为前段时间总有小伙伴问如何在ROS2中调用串口,就想着要不把这部分代码抽出来给大家,二来后续的更新和维护可以从FishBot中抽离出来,方便更多的小伙伴一起Work。同时小鱼顺手写了一个ROS2的例程,当然还有g++和CMake版本的使用样例代码。
开源地址:https://github.com/fishros/fish_protocol
FishProtocol
FishProtocol是一个方便的C++多协议(串口/UDP/TCP)通信库。
FishProtocol是从FishBot的Driver中抽离出的,采用boost库作为核心进行了二次封装,可以简单快速的通过几行代码建立串口/UDP等通信。随着FishBot的不断完善,该库也将不断的更新完善,后续将同时支持对多端进行同时连接,实现多机控制等功能。
同时该库也可以在ROS2中使用,工程中提供有相关例程,见examples文件夹。
1.快速安装
sudo apt install libboost-dev git clone https://gh.api.99988866.xyz/https://github.com/fishros/fish_protocol.git cd fish_protocol && mkdir build && cd build cmake .. && sudo make install # 将安装到系统库
2.快速使用/串口通信
fish_protocol::ProtocolConfig proto_config; proto_config.protocol_type_ = PROTOCOL_TYPE::SERIAL; proto_config.serial_baut_ = 115200; proto_config.serial_address_ = "/dev/ttyS12"; // 初始化 auto protocol = GetProtocolByConfig(proto_config); // 发送数据 protocol->ProtocolSendRawData("Hello FishBot!"); // 接收数据 protocol->SetDataRecvCallback([](const std::string& data) -> void { std::cout<<"recv"<<data<<std:endl; }); // 销毁 protocol->ProtocolDestory();
3.快速上手/UDPServer通信
fish_protocol::ProtocolConfig proto_config; proto_config.protocol_type_ = PROTOCOL_TYPE::UDP_SERVER; proto_config.udp_server_ip_ = "0.0.0.0"; proto_config.udp_server_port_ = 3474; // 初始化 auto protocol = GetProtocolByConfig(proto_config); // 发送数据 protocol->ProtocolSendRawData("Hello FishBot!"); // 接收数据 protocol->SetDataRecvCallback([](const std::string& data) -> void { std::cout<<"recv"<<data<<std:endl; }); // 销毁 protocol->ProtocolDestory();
4.在ROS2中使用-串口通信
#include "fish_protocol/fish_protocol.h" #include "rclcpp/rclcpp.hpp" int main(int argc, char** argv) { /* 初始化rclcpp */ rclcpp::init(argc, argv); /*产生一个node_01的节点*/ auto node = std::make_shared<rclcpp::Node>("example_fish_protocol"); // 打印一句自我介绍 RCLCPP_INFO(node->get_logger(), "example_fish_protocol节点已经启动."); fish_protocol::ProtocolConfig proto_config; proto_config.protocol_type_ = fish_protocol::PROTOCOL_TYPE::SERIAL; proto_config.serial_baut_ = 115200; proto_config.serial_address_ = "/dev/ttyS12"; // 初始化 auto protocol = GetProtocolByConfig(proto_config); // 发送数据 protocol->ProtocolSendRawData("Hello FishBot!"); // 接收数据 protocol->SetDataRecvCallback([](const std::string& data) -> void { std::cout << "recv" << data << std::endl; }); // 销毁 protocol->ProtocolDestory(); /* 运行节点,并检测退出信号 Ctrl+C*/ rclcpp::spin(node); /* 停止运行 */ rclcpp::shutdown(); return 0; }
-
看起来不错,我试试。谢谢。
-
谢谢你的轮子!
但是我想要通过串口发送字节数组,而非字符串,有相关的接口函数可用吗?
另外,接收回调函数如何写成独立函数的形式? -
- 字节数组和字符串可以直接互转的
- 可以直接使用std::bind将普通函数变为回调函数形式
-
@小鱼 thanks!
-
@小鱼 最近入手了一个JY_ 95t imu ,只找到了python的程序,没有c++的,这个imu在接收数据以前,需要发送一段16进制的数据:0xA4 0x03 0x08 0x23 0xD2配置imu 我看了你的程序,protocol->ProtocolSendRawData("Hello FishBot!"); 只能发送字符串,怎样才能发送16进制的数据呢?这是你的示例程序返回的结果:open with/dev/ttyUSB0
send14
start send******
0x48 0x65 0x6C 0x6C 0x6F 0x20 0x46 0x69 0x73 0x68 0x42 0x6F 0x74 0x21 -
@毛哥成山轮胎机油保养 一个字符串刚好是一个byte,8个bit。
所以bytes可以和string可以互相转换
当你想要在 C++ 中将
std::string
和字节数组之间进行转换时,可以使用reinterpret_cast
进行转换。下面是一个示例代码,展示了如何在两者之间进行互相转换:#include <iostream> #include <string> #include <vector> // 将字节数组转换为 std::string std::string ByteArrayToString(const std::vector<unsigned char>& byteArray) { return std::string(reinterpret_cast<const char*>(byteArray.data()), byteArray.size()); } // 将 std::string 转换为字节数组 std::vector<unsigned char> StringToByteArray(const std::string& str) { std::vector<unsigned char> byteArray(str.begin(), str.end()); return byteArray; } int main() { // 示例:将字节数组转换为 std::string std::vector<unsigned char> byteArray = {72, 101, 108, 108, 111, 33}; std::string str = ByteArrayToString(byteArray); std::cout << "String: " << str << std::endl; // 示例:将 std::string 转换为字节数组 std::string message = "Hello, world!"; std::vector<unsigned char> convertedArray = StringToByteArray(message); std::cout << "Byte Array: "; for (unsigned char byte : convertedArray) { std::cout << static_cast<int>(byte) << " "; } std::cout << std::endl; return 0; }
上述代码中,
ByteArrayToString
函数接收一个字节数组(std::vector<unsigned char>
),并使用reinterpret_cast
将其转换为const char*
,然后通过构造函数将其转换为std::string
。StringToByteArray
函数接收一个std::string
,并通过使用迭代器将其转换为std::vector<unsigned char>
。请注意,这种方法假设字节数组中的每个字节都对应一个有效的字符,且字符编码没有发生变化。在某些情况下,这种转换可能不是无损的,因此在实际应用中要小心处理。
-
@小鱼 在 serial串口通信 中说:
// 示例:将 std::string 转换为字节数组
std::string message = "Hello, world!";
std::vector<unsigned char> convertedArray = StringToByteArray(message);
std::cout << "Byte Array: ";
for (unsigned char byte : convertedArray) {
std::cout << static_cast<int>(byte) << " ";
}
std::cout << std::endl;#include "fish_protocol/fish_protocol.h"
//#include <iostream>
//#include <string>
//#include <vector>// 将字节数组转换为 std::string
std::string ByteArrayToString(const std::vector<unsigned char>& byteArray) {
return std::string(reinterpret_cast<const char*>(byteArray.data()), byteArray.size());
}// 将 std::string 转换为字节数组
std::vector<unsigned char> StringToByteArray(const std::string& str) {
std::vector<unsigned char> byteArray(str.begin(), str.end());
return byteArray;
}int main(int argc, char const* argv[]) {
fish_protocol::ProtocolConfig proto_config;
proto_config.protocol_type_ = fish_protocol::PROTOCOL_TYPE::SERIAL;
proto_config.serial_baut_ = 115200;
proto_config.serial_address_ = "/dev/ttyUSB0";// 初始化
auto protocol = GetProtocolByConfig(proto_config);//send_data = [0xA4,0x03,0x08,0x23,0xD2]
// 将字节数组转换为 std::string
std::vector<unsigned char> byteArray = {0xA4,0x03,0x08,0x23,0xD2};
std::string str = ByteArrayToString(byteArray);// 发送数据
protocol->ProtocolSendRawData(str);// 接收数据
protocol->SetDataRecvCallback([](const std::string& data) -> void {//将接收到的 std::string & data转换为字节数组 std::vector<unsigned char> convertedArray = StringToByteArray(data); std::cout << "Byte Array: "; for (unsigned char byte : convertedArray) { std::cout << static_cast<int>(byte) << " "; } std::cout << std::endl;
});
// 销毁
protocol->ProtocolDestory();
return 0;
}可以正常发送16进制数据了,可是为什么没有读到imu发回的数据呢?
open with/dev/ttyUSB0
send5
start send******
0xA4 0x03 0x08 0x23 0xD2
end send****** -
-
@小鱼 那我想发送一个uint8或者float型的数据该怎么办?
-
@小鱼 他只能发送一种类型?
-
@867975819 bytes可以代表一切类型
-
@小鱼 为什么在容器中安装,执行cpp文件一直显示无法找到对应的package呢
-
@3290416288 只支持ROS2