ROS2-Foxy 串口通讯
环境:Ubuntu20.04 + ROS2-Foxy
时间:2023年11月
截至目前,在全网搜了搜关于ROS2-Foxy串口通信的内容,没有找到官方正式的办法,好像也并没有官方的串口包。通过综合参考几个文档,安装一个大佬修改适配的第三方包,成功实现了串口通讯。
一、环境准备
(一)安装ros2-for-serial-driver
sudo apt install ros-foxy-serial-driver
(二)安装第三方包串口包
GitHub: ZhaoXiangBox/serial: ROS2 foxy serial
1. 下载源码
git clone https://github.com/ZhaoXiangBox/serial.git
2. 编译源码
cd serial
mkdir build
cd build
cmake ..
make
3. 安装
sudo make install
(三)加载共享库缓存
sudo ldconfig
如果没有安装过第三方开源库,需要将第三方库常用安装路径写入共享库配置文件中:
sudo sh -c "echo '/usr/local/lib' >> /etc/ld.so.conf"
sudo ldconfig
(四)安装串口调试工具
sudo apt-get install cutecom
二、示例代码
串口操作包的 API 请参考:serial: Serial Library
#include "rclcpp/rclcpp.hpp"
#include "serial/serial.h"
serial::Serial ser;//数据串口
#define sBUFFERSIZE 1000// send buffer size 串口发送缓存长度
#define rBUFFERSIZE 1000// receive buffer size 串口接收缓存长度
unsigned char s_buffer[sBUFFERSIZE]; //发送缓存
unsigned char r_buffer[rBUFFERSIZE]; //接收缓存
class ExampleNode : public rclcpp::Node
{
public:
// 构造函数,有一个参数为节点名称
ExampleNode(std::string name) : Node(name)
{
RCLCPP_INFO(this->get_logger(), "大家好,我是%s.", name.c_str());
// 创建发布者
ser_pub = this->create_publisher<XXX>("ser_data", 10);
// 创建定时器,500ms为周期,定时发布
timer = this->create_wall_timer(std::chrono::milliseconds(500), std::bind(&ExampleNode::timer_callback, this));
}
private:
void timer_callback()
{
if (ser.available()) {
size_t bytes_read_r_buffer = ser.read(r_buffer, ser.available());//bytes_read_r_buffer 自己定义的r_buffer读到多少bytes
printf("bytes_read_r_buffer: %zd\n", bytes_read_r_buffer);
// 数据转换打包
...
// 发布消息
imu_data_pub->publish(imu_data);
// 日志打印
RCLCPP_INFO(this->get_logger(), "接收到串口数据,发送成功!");
}
else
{
//test
RCLCPP_INFO(this->get_logger(), "500ms内未接收到串口数据");
}
}
// 声名定时器指针
rclcpp::TimerBase::SharedPtr timer;
// 声明话题发布者指针
rclcpp::Publisher<XXX>::SharedPtr ser_pub;
};
int main(int argc, char **argv)
{
/* 初始化rclcpp */
rclcpp::init(argc, argv);
//串口初始化
try
{
ser.setPort("/dev/ttyUSB0");
ser.setBaudrate(115200);
//串口设置
serial::Timeout to = serial::Timeout::simpleTimeout(1000);
ser.setTimeout(to);
ser.setStopbits(serial::stopbits_t::stopbits_one);
ser.setBytesize(serial::bytesize_t::eightbits);
ser.setParity(serial::parity_t::parity_none); //设置校验位
//打开
ser.open();
}
catch(serial::IOException &e)
{
std::cout<<"unable to open ser"<<std::endl;
return -1;
}
catch(std::invalid_argument &e)
{
std::cout<<"std::invalid_argument"<<std::endl;
return -1;
}
catch(serial::SerialException &e)
{
std::cout<<"serial::SerialException"<<std::endl;
return -1;
}
//检查串口
if(ser.isOpen())
{
std::cout<<"ser open"<<std::endl;
}
else
{
return -1;
}
/* 产生一个的节点 */
auto node = std::make_shared<ExampleNode>("example_node");
// 打印一句自我介绍
RCLCPP_INFO(node->get_logger(), "example_node节点已经启动.");
/* 运行节点,并检测退出信号 Ctrl+C */
rclcpp::spin(node);
/* 停止运行 */
rclcpp::shutdown();
//关闭串口
ser.close();
return 0;
}
三、参考
四、【避雷】尝试失败的方法
鱼香ROS自己写的一个包FishProtocol
:安装后,运行样例代码没有跑通。