1、安装准备
1.1安装ros2-for-serial-driver
sudo apt install ros-humble-serial-driver
1.2安装ch340驱动
Linux-ubuntu22.04串口驱动安装(CH34X)
1.3安装串口库依赖
1.4串口调试工具安装
sudo apt-get install cutecom
打开调试工具
sudo cutecom
打开界面如下
可以在setting部分进行串口参数的配置
2、上位机端代码
2.1demo需求:
1、接收两个topic;
2、根据topic内容进行逻辑判断;
3、根据判断结果,发送16进制的8个byte的报文到设备;
在正式编写代码之前,首先先建立一下ros2的工作空间和工作包
mkdir -p ~/ros_ws/src
cd ~/ros_ws/src
ros2 pkg create --build-type ament_cmake demo
2.2编写发布者节点
2.2.1编写talker节点
cd ~/ros_ws/src/demo/src
touch talker.cpp
之后编写代码,talker节点会根据键盘的指令输入0或者1
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "sensor_msgs/msg/image.hpp"
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
class MinimalPublisher : public rclcpp::Node
{
public:
MinimalPublisher()
: Node("minimal_publisher"), count_(0)
{
publisher_ = this->create_publisher<sensor_msgs::msg::Image>("topic", 10);
timer_ = this->create_wall_timer(
500ms, std::bind(&MinimalPublisher::timer_callback, this));
}
private:
void timer_callback()
{
int a = 0;
auto message = sensor_msgs::msg::Image();
int func(0);
std::cout << "请输入数字";
std::cin >> func;
switch (func)
{
case 0:
a = 0;
break;
case 1:
a = 4;
break;
}
message.height = a;
publisher_->publish(message);
// std::cout << message.height << std::endl;
RCLCPP_INFO(get_logger(), "参数1:%d", message.height);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr publisher_;
size_t count_;
};
int main(int argc, char *argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalPublisher>());
rclcpp::shutdown();
return 0;
}
2.2.2编写talker1节点
talker1会持续发送数字4
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "sensor_msgs/msg/image.hpp"
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
class MinimalPublisher : public rclcpp::Node
{
public:
MinimalPublisher()
: Node("minimal_publisher1"), count_(0)
{
publisher_ = this->create_publisher<sensor_msgs::msg::Image>("topic1", 10);
timer_ = this->create_wall_timer(
500ms, std::bind(&MinimalPublisher::timer_callback, this));
}
private:
void timer_callback()
{
// int a = 0;
auto message = sensor_msgs::msg::Image();
message.height = 4;
publisher_->publish(message);
std::cout << message.height << std::endl;
RCLCPP_INFO(get_logger(),"参数2:%d",message.height);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr publisher_;
size_t count_;
};
int main(int argc, char *argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalPublisher>());
rclcpp::shutdown();
return 0;
}
两个发布节点编写完毕
2.3编写接收者节点
首先需要接受两个节点的话题,并作逻辑处理,之后使用serial库文件的函数进行数据的发送,目前我们的设备可以通过hex数据包显示两种不同报文,发送报文:
第一种 0xFF、0x05、0x00、0x02、0x00、0x01、0x6A、0x6A、0x6A、0xFE,其中0xFF为包头,0xFE为包尾。
第二种0xFF、0x05、0x00、 0x02、 0xff、0x00、0x2B、0x6B、0x6C、0xFE,其中0xFF为包头,0xFE为包尾。
建立可执行文件
cd ~/ros_ws/src/demo/src
touch lis.cpp
以下是具体代码
#include <functional>
#include <memory>
#include <string>
#include "serial/serial.h"
#include "rclcpp/rclcpp.hpp"
#include "message_filters/subscriber.h"
#include "message_filters/time_synchronizer.h"
#include "sensor_msgs/msg/image.hpp"
using std::placeholders::_1;
using std::placeholders::_2;
serial::Serial ros_ser;
class MinimalSubscriber : public rclcpp::Node
{
public:
MinimalSubscriber()
: Node("minimal_sync_subscriber")
{
sub1_.subscribe(this, "topic");
sub2_.subscribe(this, "topic1");
sync_ = std::make_shared<message_filters::TimeSynchronizer<sensor_msgs::msg::Image, sensor_msgs::msg::Image>>(sub1_, sub2_, 10);
sync_->registerCallback(std::bind(&MinimalSubscriber::topic_callback, this, _1, _2));
}
private:
void topic_callback(const sensor_msgs::msg::Image::ConstSharedPtr msg1,
const sensor_msgs::msg::Image::ConstSharedPtr msg2) const
{
int c = 0;
unsigned char buffer[10] = {0};
c = (msg1->height) * (msg2->height);
// std::cout << c << ","
// << msg1->height << ","
// << msg2->height << std::endl;
if (c != 0)
{
buffer[0] = 0xFF;
buffer[1] = 0x05;
buffer[2] = 0x00;
buffer[3] = 0x02;
buffer[4] = 0x00;
buffer[5] = 0x01;
buffer[6] = 0x6A;
buffer[7] = 0x6A;
buffer[8] = 0x6A;
buffer[9] = 0xFE;
}
else
{
buffer[0] = 0xFF;
buffer[1] = 0x05;
buffer[2] = 0x00;
buffer[3] = 0x02;
buffer[4] = 0xff;
buffer[5] = 0x00;
buffer[6] = 0x2B;
buffer[7] = 0x6B;
buffer[8] = 0x6C;
buffer[9] = 0xFE;
}
// RCLCPP_INFO(get_logger(), "结果:%d", c);
for (int i = 0; i < 10; i++)
{
std::cout << std::hex << (buffer[i] &0xff)<< " ";
}
std::cout<<std::endl;
ros_ser.write(buffer,10);
}
message_filters::Subscriber<sensor_msgs::msg::Image> sub1_;
message_filters::Subscriber<sensor_msgs::msg::Image> sub2_;
std::shared_ptr<message_filters::TimeSynchronizer<sensor_msgs::msg::Image, sensor_msgs::msg::Image>> sync_;
};
int main(int argc, char *argv[])
{
rclcpp::init(argc, argv);
ros_ser.setPort("/dev/ttyUSB0");
//ros_ser.BaudRate(9600);
ros_ser.setBaudrate(9600);
serial::Timeout to =serial::Timeout::simpleTimeout(1000);
ros_ser.setTimeout(to);
try
{
ros_ser.open();
}
catch(serial::IOException &e)
{
std::cout<<"unable to open"<<std::endl;
return -1;
}
if(ros_ser.isOpen())
{
std::cout<<"open"<<std::endl;
}
else
{
return -1;
}
rclcpp::spin(std::make_shared<MinimalSubscriber>());
rclcpp::shutdown();
ros_ser.close();
return 0;
}
3、下位端开发代码
下位机采用最小开发板
3.1接线图
3.2下位机代码
链接:https://pan.baidu.com/s/1IyXGR2hXfNVme_wgcwpGSQ?pwd=RMSR 提取码:RMSR
4、代码效果展示
使用方法
source install/setup.bash
ros2 run demo talker_node
ros2 run demo talker1_node
sudo chmod 777 /dev/ttyUSB0
ros2 run demo lis_node
4.1报文一
上位机端:
下位机端:
4.1报文二
上位机端:
下位机端:
5、可能遇到的问题
5.1程序编译无误,但端口无法打开
解决方法:
1)输入命令
查看是否存在串口,或检查串口是否被占用。
ls -l /dev/ttyUSB0
2)存在空闲的USB口,请检查/dev/ttyUSB0的权限,放开所有权限。
sudo chmod 777 /dev/ttyUSB0
5.2 error while loading shared libraries错误解决
Linux中运行代码时,找不到libserial.so动态链接库。
出现这个问题时,常常是自己写的.so文件,代码可以编译成功,但是运行的话会出现error while loading shared libraries错误。原因是,Linux 运行的时候,共享库的寻找和加载是由 /lib/ld.so 实现的。默认配置下,ld.so 在标准路经(/) 中寻找应用程序用到的共享库。
一般来说,使用make install会将自己编译的共享库放在在非标准路经中,比如/usr/local/lib中,而不是标准的动态库路径(/usr/lib)。此次需要修改配置,将*.so的路径写入配置中。
解决方法有两个:
1)临时方案:
(重新打开terminal后失效)在Terminal中输入以下命令
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
2)长期方案:
(a)打开 ld.so.conf 文件
sudo gedit /etc/ld.so.conf
(b)在下面加入非标准的动态共享库路径:一般为/src/local/lib。 保存ld.so.conf 文件
(c) 记得执行ldconfig一下,添加的文件夹内容才能在程序运行时被找到。
sudo ldconfig
5.3部分新版本Ubuntu需要签名的问题Key was rejected by service
参考:解决Ubuntu22.04.1上安装ch34x串口驱动报 Key was rejected by service 需要签名的问题