目录
序言
先前采用了串口进行上下位机通讯,由于需要USB转串口,会出现通讯不上的问题。
之后了解了CAN通讯,发现相比串口通信更稳定,在编程上也相对自由些
虚拟 CAN 体验
安装 can-utils 包(主要用其中包含的 candump 工具)
sudo apt install can-utils
具体体验步骤
- 加载虚拟 CAN 模块
sudo modprobe vcan
- 添加 can0 网卡
sudo ip link add dev can0 type vcan
此时通过ifconfig -a
命令可以看到比平时多了一个 can0,但此时状态为:<NOARP> - 启动 can0
sudo ip link set dev can0 up
再次查看 can0 状态,此时为:<UP,RUNNING,NOARP> - 启动 candump 命令,监控 can0 端口的数据
candump can0
- 使用 cansend 命令,向 can0 端口发布数据:123#456789
cansend can0 123#456789
此时,candump 窗口接收到数据:can0 123 [3] 45 67 89
注意
使用 cansend 发布数据需要有一定格式,否则会报错,官方声明如下
cansend - send CAN-frames via CAN_RAW sockets.
Usage: cansend <device> <can_frame>.
<can_frame>:
<can_id>#{data} for 'classic' CAN 2.0 data frames
<can_id>#R{len} for 'classic' CAN 2.0 data frames
<can_id>##<flags>{data} for CAN FD frames
<can_id>:
3 (SFF) or 8 (EFF) hex chars
{data}:
0..8 (0..64 CAN FD) ASCII hex-values (optionally separated by '.')
{len}:
an optional 0..8 value as RTR frames can contain a valid dlc field
<flags>:
a single ASCII Hex value (0 .. F) which defines canfd_frame.flags
Examples:
5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311223344 /
1F334455#1122334455667788 / 123#R / 00000123#R3
- 关闭 can0
sudo ip link set dev can0 down
此时通过ifconfig -a
命令可以看到 can0 状态变回:<NOARP> - 删除 can0
sudo ip link del dev can0
此时使用ifconfig -a
命令已经看不到 can0 了
使用 ros can
安装相关依赖(此处以 Ubuntu18.04 为例,具体 ROS 版本号对应需要更改)
sudo apt-get install ros-melodic-can-msgs
sudo apt-get install ros-melodic-socketcan-bridge
sudo apt-get install libmuparser-dev
具体使用步骤
- 启动 master 节点
roscore
- 启动 ROS 的 CAN 数据转ROS话题节点
rosrun socketcan_bridge socketcan_to_topic_node
- 启动 ROS CAN数据转换后的话题节点
rostopic echo /received_messages
- 启动 candump 监控 can0
camdump can0
- 使用 cansend 命令发布数据
cansend can0 123#456789
- 此时可以在 3.、 4. 窗口中分别接收到 CAN 转换后的数据和 CAN 的原生数据。
在 ROS 代码中使用 CAN 通讯
涉及到的包以及话题消息
- socketcan_bridge 包:主要是两个用于转换 CAN 数据和 ROS 话题数据的节点(topic_to_socketcan_node,socketcan_to_topic_node)
- can_msgs::Frame 消息:用于存储 CAN 消息,官方数据结构如下
std_msgs/Header header
uint32 seq
time stamp
string frame_id
uint32 id
bool is_rtr
bool is_extended
bool is_error
uint8 dlc
uint8[8] data
主要成员变量解析
id:CAN 通讯的 ID
dlc:数据字节长度
data:用于 CAN 数据存储的数组
简单示例
- launch文件,用于启动数据转换节点和示例节点
<launch>
<!-- topic 转 CAN -->
<node pkg="socketcan_bridge" name="topic_to_socket_node" type="topic_to_socket_node" output="screen">
<param name="can_device" value="can0" />
</node>
<!-- CAN 转 topic -->
<node pkg="socketcan_bridge" name="socket_to_topic_node" type="socket_to_topic_node" output="screen">
<param name="can_device" value="can0" />
</node>
<!-- 示例节点 -->
<node pkg="can_test" name="can_test" type="can_test_node" output="screen" />
</launch>
- C++文件,示例节点
#include <ros/ros.h>
#include <can_msgs/Frame.h>
void canCallBack(const can_msgs::Frame::ConstPtr &msg)
{
static int times = 0;
std::cout << times++ << "ID: " << msg->id << " data: " ; for (int i = 0; i < msg->dlc; i++)
{
printf("%X ", msg->data[i]);
}
std::cout << std::endl;
}
int main(int argc, char **argv)
{
setlocale(LC_ALL, "");
ros::init(argc, argv, "can_test_node");
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<can_msgs::Frame>("sent_messages", 100);
can_msgs::Frame can_frame_msg;
can_frame_msg.id = 0x521;
can_frame_msg.dlc = 8;
// 分开赋值
can_frame_msg.data[0] = 0x00;
can_frame_msg.data[1] = 0x11;
can_frame_msg.data[2] = 0x22;
can_frame_msg.data[3] = 0x33;
can_frame_msg.data[4] = 0x44;
can_frame_msg.data[5] = 0x55;
can_frame_msg.data[6] = 0x66;
can_frame_msg.data[7] = 0x77;
// can_frame_msg.data = {00, 11, 22, 33, 44, 55, 66, 77}; // 一次性全部赋值
ros::Subscriber sub = nh.subscribe("/received_messages", 100, &canCallBack);
ros::Rate r(1);
while (ros::ok())
{
pub.publish(can_frame_msg);
r.sleep();
ros::spinOnce();
}
return 0;
}
- 使用
cansend
命令发布数据,进行 CAN 数据转 ROS 话题数据的方法验证
查看发布的数据
candump can0
:查看CAN 数据rostopic echo /received_messages
:查看话题数据
实体 CAN 使用
CAN 口回环检测
简单含义及作用
- 回环检测模式又称自检测模式,主要是 CAN 口自己发出的数据自己接收,数据不流经 CAN 总线
- 这样做可以检测 CAN 口通讯是否正常,是否存在问题,排除 CAN 总线及总线上的干扰
操作流程
- 关闭 CAN
sudo ip link set down can0
- 设置 CAN 口波特率,此处设置为 500Kbps
sudo ip link set can0 type can bitrate 500000
- 设置CAN 为回环检测模式
sudo ip link set can0 type can loopback on
- 使能 CAN
sudo ip link set up can0
- 检测并发布 CAN 数据
candump can0
cansend can0 521#010301000001
测试结果
- 可以在 candump 窗口看到在发布 CAN 数据的同时又接收到一个相同的 CAN 数据
- 如果出现上面的情况,就表示 CAN 口无误,反之需要针对输出的问题进行相应处理
当前未遇到过问题,若有朋友遇到欢迎在评论区讨论
CAN 测试
- 查看当前 CAN 口状态
ip -details -statistics link show can0
- 根据实际需求修改设置 CAN 口:波特率、是否为回环测试、时钟同步精度等,如下示例
sudo ip link set can0 type can bitrate 500000 sjw 4 restart-ms 100 berr-reporting on
命令解析:
ip link: 这是用于操作Linux内核中网络设备链接的工具。它可以用来查看、修改或操作网络接口的各种设置。
set can0 type can: 这部分命令设置can0接口的类型为CAN接口。can0是CAN接口的名字。
bitrate 500000: 这设置了CAN接口的数据传输速率为500,000比特每秒(500 kbps)。
sjw 4: 这设置了同步跳转宽度(sjw)为4。同步跳转宽度决定了时钟同步的精度,它影响时钟同步的延迟和抖动。
restart-ms 100: 这设置了在检测到错误后重新启动通信的时间间隔为100毫秒。
berr-reporting on: 这启用了位错误报告。当这个选项被启用时,如果检测到位错误,系统会发送一个错误报告。
-
关闭 CAN 回环检测模式
sudo ip link set can0 type can loopback off
-
检测并发布 CAN 数据
candump can0
cansend can0 521#010301000001
此时可以使用其他 CAN 设备向 CAN 总线发布数据,使用candump查看是否存在数据
参考文章
[1] ros_canopen使用心得
[2] ROS采用SocketCAN进行通信
[3] TX2/Linux下can总线的接收与发送详解!