ROS Melodic与周立功CAN卡通讯:手把手教你创建自定义消息包并编译运行

张开发
2026/4/18 0:01:20 15 分钟阅读

分享文章

ROS Melodic与周立功CAN卡通讯:手把手教你创建自定义消息包并编译运行
ROS Melodic与周立功CAN卡深度集成实战从消息定义到实时通讯在机器人操作系统ROS与工业级CAN总线设备的集成开发中周立功CAN卡以其稳定的性能和丰富的接口支持成为众多开发者的首选。本文将带您深入探索如何基于ROS Melodic构建完整的CAN通讯解决方案重点解决自定义消息包开发过程中的典型痛点。1. 开发环境准备与架构设计在开始编码之前我们需要明确整个系统的技术架构。典型的ROS-CAN集成方案包含三个核心层次硬件驱动层、消息转换层和应用逻辑层。周立功USB-CAN设备通过libusb库与系统交互而ROS节点则负责协议转换和数据分发。必备组件清单周立功CAN卡型号如USBCAN-II或MiniPCIe已安装ROS Melodic的Ubuntu 18.04系统设备驱动包通常包含libusbcan.so和测试程序基础开发工具链sudo apt-get install build-essential libusb-1.0-0-dev硬件连接验证阶段建议先用官方测试程序确认设备基本功能。若遇到权限问题可通过以下udev规则永久解决echo SUBSYSTEMSusb, ATTRS{idVendor}067b, ATTRS{idProduct}2303, MODE0666 | sudo tee /etc/udev/rules.d/99-usbcan.rules sudo udevadm control --reload-rules2. 创建专用ROS功能包正确的功能包结构是项目可维护性的基础。我们采用catkin工具链创建符合ROS规范的工作空间mkdir -p ~/can_ws/src cd ~/can_ws/src catkin_create_pkg zlgcan_bridge roscpp std_msgs message_generation关键目录结构应包含zlgcan_bridge/ ├── CMakeLists.txt ├── include/ ├── msg/ ├── src/ └── package.xml在package.xml中需要显式声明消息生成依赖build_dependmessage_generation/build_depend exec_dependmessage_runtime/exec_depend3. 设计CAN消息接口CAN帧到ROS消息的映射需要精心设计。在msg/目录下创建CANFrame.msg文件定义以下字段uint32 id uint8 dlc uint8[8] data bool is_extended bool is_rtr float64 timestamp这种设计充分保留了CAN协议的特性同时符合ROS消息规范。对比原始方案我们增加了时间戳和帧类型标识为后续数据分析提供更多维度。消息编译配置需要修改CMakeLists.txt的关键段落find_package(catkin REQUIRED COMPONENTS roscpp std_msgs message_generation ) add_message_files( FILES CANFrame.msg ) generate_messages( DEPENDENCIES std_msgs )4. 深度集成CAN驱动周立功提供的controlcan.h头文件需要特殊处理。建议将其放置在功能包的include/zlgcan_bridge目录下并在CMake中正确配置包含路径include_directories( include ${catkin_INCLUDE_DIRS} ) # 添加动态链接库路径 link_directories(/lib)驱动封装类示例部分代码#include controlcan.h #include zlgcan_bridge/CANFrame.h class CANBridge { public: CANBridge() { VCI_OpenDevice(VCI_USBCAN2, 0, 0); VCI_InitCAN(VCI_USBCAN2, 0, 0, can_config_); VCI_StartCAN(VCI_USBCAN2, 0, 0); } void publishFrames(ros::Publisher pub) { VCI_CAN_OBJ frames[100]; int count VCI_Receive(VCI_USBCAN2, 0, 0, frames, 100, 0); for(int i0; icount; i) { zlgcan_bridge::CANFrame msg; msg.id frames[i].ID; msg.dlc frames[i].DataLen; std::copy(frames[i].Data, frames[i].Data8, msg.data.begin()); pub.publish(msg); } } private: VCI_INIT_CONFIG can_config_; };5. 构建完整数据通路实际工程中需要考虑数据收发的高效实现。以下是典型的节点实现框架发送节点核心逻辑void callback(const zlgcan_bridge::CANFrame::ConstPtr msg) { VCI_CAN_OBJ frame; frame.ID msg-id; frame.DataLen msg-dlc; std::copy(msg-data.begin(), msg-data.end(), frame.Data); VCI_Transmit(VCI_USBCAN2, 0, 0, frame, 1); } int main(int argc, char** argv) { ros::init(argc, argv, can_tx_node); ros::NodeHandle nh; ros::Subscriber sub nh.subscribe(can_tx, 1000, callback); ros::spin(); return 0; }接收节点优化建议使用环形缓冲区减少内存分配开销实现零拷贝机制提升吞吐量添加硬件时间同步支持6. 高级调试技巧当系统集成出现问题时分层验证是关键硬件层检查lsusb | grep 067b:2303 dmesg | grep can驱动层测试can-utils包中的candump工具ROS层诊断rostopic echo /can_rx --noarr rosrun rqt_graph rqt_graph性能优化参数参考参数项推荐值说明接收缓冲区1024帧防止突发数据丢失发布队列1000条平衡延迟和吞吐线程数2-4个根据CPU核心数调整7. 工程化扩展建议成熟的CAN通讯模块还需要考虑动态重配置支持通过ROS参数服务器故障恢复机制自动重连等数据记录功能结合rosbag带宽监控自定义诊断消息一个完整的启动launch文件示例launch node pkgzlgcan_bridge typecan_rx_node namecan_rx outputscreen param namedevice_type valueUSBCAN2 / param namecan_index value0 / /node node pkgzlgcan_bridge typecan_tx_node namecan_tx outputscreen remap fromcan_tx tocan_outbound / /node /launch在实际自动驾驶项目中我们曾遇到CAN帧时间同步问题。最终解决方案是在驱动层添加硬件时间戳记录同时使用ROS的模拟时间机制进行补偿将时钟偏差控制在微秒级。

更多文章