news 2026/4/18 22:37:19

保姆级教程:在Ubuntu 18.04上用ROS Melodic搞定周立功CAN卡驱动与权限问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
保姆级教程:在Ubuntu 18.04上用ROS Melodic搞定周立功CAN卡驱动与权限问题

机器人开发实战:Ubuntu 18.04下ROS Melodic与周立功CAN卡的深度集成指南

当你在机器人项目中第一次尝试让ROS系统与CAN总线设备对话时,很可能会遇到那个令人头疼的libusb_open failed错误。作为曾经花了整整一个周末才解决这个问题的过来人,我决定把完整的解决方案整理成这份避坑指南。

周立功CAN卡作为国内常见的工业级CAN通讯设备,在ROS开发社区中被广泛使用。但在Ubuntu 18.04上配置ROS Melodic环境时,从驱动安装到权限配置的每个环节都可能成为新手开发者的"拦路虎"。本文将带你一步步打通这个技术链路,特别针对那些官方文档没有明确说明的细节问题。

1. 环境准备与驱动安装

在开始之前,请确保你的Ubuntu 18.04系统已经安装了ROS Melodic完整版。如果你还没有安装,可以通过以下命令快速完成:

sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 sudo apt update sudo apt install ros-melodic-desktop-full

1.1 获取周立功CAN卡驱动

周立功官方提供了多种接口的CAN卡驱动,我们需要根据硬件型号选择对应的版本。对于常见的MiniPCIe和USB接口设备,驱动通常包含以下关键文件:

  • libusbcan.so:核心驱动库文件
  • controlcan.h:开发头文件
  • test/目录:测试程序源代码

提示:建议从官方网站下载最新驱动,如果使用网盘资源,务必核对文件的MD5校验值,避免版本不一致导致兼容性问题。

1.2 安装系统依赖

周立功CAN卡驱动依赖于libusb-1.0库,在安装驱动前需要确保系统已安装必要的依赖项:

sudo apt update sudo apt install -y libusb-1.0-0 libusb-1.0-0-dev build-essential

安装完成后,将驱动包中的libusbcan.so文件复制到系统库目录:

sudo cp libusbcan.so /usr/local/lib/ sudo ldconfig

2. 驱动测试与权限问题解决

2.1 编译测试程序

进入驱动包中的test目录,编译测试程序:

cd test make clean make

编译成功后,你会看到一个名为test的可执行文件。不带参数运行它将显示使用说明:

./test

正常输出应该类似于:

Usage: ./test [devtype] [devind] [chan] [baud] [master] [selfid] [remoteid] [count]

2.2 常见错误:USB权限问题

当你尝试实际运行测试程序时,很可能会遇到如下错误:

libusb_open failed: ret=-3

这个错误表明当前用户没有权限访问USB设备。我们可以通过以下两种方式解决:

临时解决方案(每次重启后失效):

sudo chmod -R 777 /dev/bus/usb/

永久解决方案(推荐):

  1. 创建udev规则文件:
sudo touch /etc/udev/rules.d/50-usbcan.rules sudo gedit /etc/udev/rules.d/50-usbcan.rules
  1. 在文件中添加以下内容(根据你的设备修改vendor和product ID):
SUBSYSTEMS=="usb", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", GROUP="users", MODE="0666"
  1. 重新加载udev规则并重启服务:
sudo udevadm control --reload sudo service udev restart

注意:确认你的设备vendor和product ID是否正确,可以通过lsusb命令查看已连接的USB设备信息。

2.3 验证驱动正常工作

完成上述配置后,重新插拔CAN卡设备,然后运行测试命令:

./test 4 0 3 0x1400 2 0 3 1000

如果一切正常,你应该能看到CAN消息的收发统计信息,这表示驱动已经正确安装并可以正常工作。

3. ROS工作空间配置

3.1 创建ROS功能包

首先创建一个新的ROS工作空间和功能包:

mkdir -p ~/can_ws/src cd ~/can_ws/src catkin_create_pkg ros_can roscpp rospy std_msgs cd ~/can_ws catkin_make source devel/setup.bash

3.2 添加CAN消息类型

在ROS中,我们需要定义CAN帧的消息格式。在功能包中创建msg目录并添加Frame.msg文件:

uint32 id uint8 dlc uint8[8] data

然后修改package.xml文件,添加消息依赖:

<build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend>

更新CMakeLists.txt中的相关配置:

find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation ) add_message_files( FILES Frame.msg ) generate_messages( DEPENDENCIES std_msgs ) catkin_package( CATKIN_DEPENDS message_runtime roscpp rospy std_msgs )

重新编译工作空间:

cd ~/can_ws catkin_make

4. ROS与CAN卡的深度集成

4.1 编写CAN节点代码

src目录下创建can_node.cpp文件,实现基本的CAN消息收发功能。以下是核心代码框架:

#include "ros/ros.h" #include "ros_can/Frame.h" #include "controlcan.h" class CanNode { public: CanNode() { // 初始化CAN设备 if(VCI_OpenDevice(VCI_USBCAN2, 0, 0) != STATUS_OK) { ROS_ERROR("Failed to open CAN device!"); ros::shutdown(); } // 配置CAN参数 VCI_INIT_CONFIG config; config.AccCode = 0x00000000; config.AccMask = 0xFFFFFFFF; config.Filter = 1; config.Mode = 0; config.Timing0 = 0x00; config.Timing1 = 0x1C; if(VCI_InitCAN(VCI_USBCAN2, 0, 0, &config) != STATUS_OK) { ROS_ERROR("Failed to init CAN!"); ros::shutdown(); } // 启动CAN设备 if(VCI_StartCAN(VCI_USBCAN2, 0, 0) != STATUS_OK) { ROS_ERROR("Failed to start CAN!"); ros::shutdown(); } // 创建ROS发布者和订阅者 pub_ = nh_.advertise<ros_can::Frame>("can_rx", 1000); sub_ = nh_.subscribe("can_tx", 1000, &CanNode::canTxCallback, this); } void canTxCallback(const ros_can::Frame::ConstPtr& msg) { // 处理发送CAN消息的逻辑 } void spin() { ros::Rate rate(100); while(ros::ok()) { // 处理接收CAN消息的逻辑 ros::spinOnce(); rate.sleep(); } } private: ros::NodeHandle nh_; ros::Publisher pub_; ros::Subscriber sub_; }; int main(int argc, char** argv) { ros::init(argc, argv, "can_node"); CanNode node; node.spin(); return 0; }

4.2 编译与运行

更新CMakeLists.txt添加可执行文件:

add_executable(can_node src/can_node.cpp) target_link_libraries(can_node ${catkin_LIBRARIES})

编译并运行节点:

cd ~/can_ws catkin_make rosrun ros_can can_node

4.3 调试技巧

当CAN通讯出现问题时,可以按照以下步骤排查:

  1. 检查物理连接

    • 确认CAN线缆正确连接
    • 检查终端电阻是否安装(通常需要120Ω)
  2. 验证驱动状态

    dmesg | grep usb lsmod | grep usb
  3. 测试底层通讯

    • 使用candumpcansend工具测试原始CAN通讯
    • 安装can-utils工具包:
      sudo apt install can-utils
  4. ROS层调试

    • 使用rostopic echo查看CAN消息
    • 使用rqt_graph检查节点连接情况

5. 高级配置与性能优化

5.1 多线程处理

对于高频率CAN消息处理,建议使用多线程模型:

#include <thread> void receiveThread() { while(ros::ok()) { // CAN消息接收处理 } } int main(int argc, char** argv) { ros::init(argc, argv, "can_node"); CanNode node; std::thread t(receiveThread); ros::spin(); t.join(); return 0; }

5.2 消息过滤与处理

在ROS中实现高效的消息过滤:

void canTxCallback(const ros_can::Frame::ConstPtr& msg) { // 只处理特定ID的消息 if(msg->id == 0x123) { // 处理逻辑 } }

5.3 实时性优化

对于实时性要求高的应用,可以考虑以下优化措施:

  1. 提高ROS节点的调度优先级:

    #include <sched.h> void setRealtimePriority() { struct sched_param param; param.sched_priority = sched_get_priority_max(SCHED_FIFO); sched_setscheduler(0, SCHED_FIFO, &param); }
  2. 使用零拷贝消息传递:

    typedef boost::shared_ptr<ros_can::Frame const> FrameConstPtr; void canTxCallback(const FrameConstPtr& msg) { // 零拷贝处理 }
  3. 优化ROS参数服务器配置:

    rosparam set /rosdistro __name:=can_node __ns:=/ rosparam set /roslaunch/uris/host_ubuntu__12345 http://localhost:12345/

6. 实际应用案例:CAN总线控制机械臂

让我们看一个实际应用场景:通过CAN总线控制六轴机械臂。这个案例展示了如何将CAN通讯集成到完整的机器人系统中。

6.1 系统架构

[ROS Master] | |-- [CAN Interface Node] -- [CAN Bus] -- [Motor Controller 1] | -- [Motor Controller 2] | -- [...] | |-- [Motion Planning Node] | |-- [User Interface Node]

6.2 机械臂控制消息定义

扩展之前的Frame.msg,添加机械臂专用消息:

uint32 id uint8 dlc uint8[8] data --- uint8 axis_id float32 position float32 velocity float32 torque

6.3 核心控制逻辑

void sendJointCommand(uint8_t axis_id, float position, float velocity, float torque) { VCI_CAN_OBJ send[1]; send[0].ID = 0x100 + axis_id; send[0].SendType = 0; send[0].RemoteFlag = 0; send[0].ExternFlag = 0; send[0].DataLen = 8; // 将浮点数转换为字节数组 memcpy(&send[0].Data[0], &position, 4); memcpy(&send[0].Data[4], &velocity, 4); if(VCI_Transmit(VCI_USBCAN2, 0, 0, send, 1) != 1) { ROS_ERROR("Failed to send CAN message!"); } }

6.4 状态反馈处理

void processFeedback(const VCI_CAN_OBJ& frame) { ros_can::Frame msg; msg.id = frame.ID; msg.dlc = frame.DataLen; memcpy(&msg.data[0], frame.Data, frame.DataLen); // 解析具体数据 if(frame.ID >= 0x200 && frame.ID <= 0x20F) { uint8_t axis_id = frame.ID - 0x200; float position, velocity, current; memcpy(&position, &frame.Data[0], 4); memcpy(&velocity, &frame.Data[4], 4); // 发布ROS消息 feedback_pub_.publish(msg); } }

7. 常见问题解决方案

在实际项目中,我遇到了许多关于周立功CAN卡与ROS集成的问题。以下是几个最典型的案例及其解决方案:

7.1 驱动加载失败

症状VCI_OpenDevice返回失败,dmesg显示usb 1-1: device descriptor read/64, error -110

解决方案

  1. 检查USB供电是否充足,尝试更换USB端口
  2. 更新固件版本:
    sudo apt install fxload sudo fxload -t fx2 -I /path/to/firmware.hex
  3. 禁用USB自动挂起:
    echo 'options usbcore autosuspend=-1' | sudo tee /etc/modprobe.d/usb-autosuspend.conf sudo update-initramfs -u

7.2 CAN消息丢失

症状:高频率发送时部分消息丢失

优化措施

  1. 增加发送缓冲区:
    VCI_INIT_CONFIG config; config.Timing0 = 0x01; // 提高波特率 config.Timing1 = 0x1C;
  2. 使用批处理发送:
    #define MAX_CAN_FRAMES 100 VCI_CAN_OBJ frames[MAX_CAN_FRAMES]; // 填充多个帧 VCI_Transmit(VCI_USBCAN2, 0, 0, frames, count);
  3. 调整ROS参数:
    rosparam set /can_node/queue_size 1000

7.3 实时性不稳定

症状:消息延迟波动大

调优方案

  1. 设置CPU亲和性:
    cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(2, &cpuset); // 绑定到特定核心 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
  2. 禁用CPU频率调节:
    sudo apt install cpufrequtils echo 'GOVERNOR="performance"' | sudo tee /etc/default/cpufrequtils sudo systemctl restart cpufrequtils
  3. 优化内核参数:
    echo 'vm.swappiness = 10' | sudo tee -a /etc/sysctl.conf echo 'fs.inotify.max_user_watches = 524288' | sudo tee -a /etc/sysctl.conf sudo sysctl -p

8. 扩展应用:CAN总线网络管理

对于需要多个CAN节点协同工作的复杂系统,实现总线网络管理至关重要。以下是基于周立功CAN卡的高级应用示例:

8.1 总线监控与统计

void monitorBusHealth() { VCI_ERR_INFO errInfo; VCI_ReadErrInfo(VCI_USBCAN2, 0, 0, &errInfo); ROS_INFO("CAN Bus Status: ErrCode=%u, PassiveErr=%u, ArbLost=%u", errInfo.ErrCode, errInfo.PassiveErr, errInfo.ArbLost); VCI_CAN_STATUS status; VCI_ReadCANStatus(VCI_USBCAN2, 0, 0, &status); ROS_INFO("Buffer Status: Send=%u/%u, Recv=%u/%u", status.SendNum, status.SendSize, status.RecvNum, status.RecvSize); }

8.2 节点心跳检测

实现一个简单的网络管理协议:

struct HeartbeatMsg { uint32_t node_id; uint32_t timestamp; uint8_t state; }; void sendHeartbeat() { HeartbeatMsg hb; hb.node_id = 0x01; hb.timestamp = ros::Time::now().toNSec(); hb.state = 0x01; // 运行状态 VCI_CAN_OBJ frame; frame.ID = 0x700; // 网络管理地址 frame.DataLen = sizeof(HeartbeatMsg); memcpy(frame.Data, &hb, sizeof(HeartbeatMsg)); VCI_Transmit(VCI_USBCAN2, 0, 0, &frame, 1); }

8.3 总线负载计算

float calculateBusLoad() { static uint32_t last_frame_count = 0; static ros::Time last_time = ros::Time::now(); VCI_CAN_STATUS status; VCI_ReadCANStatus(VCI_USBCAN2, 0, 0, &status); uint32_t current_count = status.RecvNum; ros::Time current_time = ros::Time::now(); float interval = (current_time - last_time).toSec(); float frame_rate = (current_count - last_frame_count) / interval; last_frame_count = current_count; last_time = current_time; // 假设标准CAN帧(11-bit ID + 8 bytes data) float bit_rate = frame_rate * (47 + 8 * 8); // 47位开销 + 数据位 float load_percentage = bit_rate / 500000 * 100; // 500kbps总线 return load_percentage; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 22:29:56

Redis 持久化策略对性能的影响

Redis持久化策略对性能的影响 Redis作为高性能的内存数据库&#xff0c;持久化机制是其核心特性之一&#xff0c;但不同的持久化策略会对性能产生显著影响。理解这些影响&#xff0c;有助于开发者在数据安全性与系统性能之间找到平衡点。本文将围绕Redis的RDB、AOF及混合持久化…

作者头像 李华
网站建设 2026/4/18 22:29:56

CMOS图像传感器核心技术解析:从像素结构到曝光控制

1. CMOS图像传感器的基础结构解析 当你用手机拍下一张照片时&#xff0c;光线首先穿过镜头&#xff0c;然后到达一个比指甲盖还小的芯片上——这就是CMOS图像传感器。这块小小的芯片内部其实是个精密的"光信号收集工厂"&#xff0c;每个像素点都像是一个独立的"…

作者头像 李华
网站建设 2026/4/18 22:29:56

软件测试验证管理化的质量检查与确认

软件测试验证管理化的质量检查与确认 在当今快速发展的软件行业中&#xff0c;确保软件质量已成为企业成功的关键因素之一。软件测试验证管理化通过系统化的方法对质量进行检查与确认&#xff0c;不仅能够提升软件可靠性&#xff0c;还能降低开发成本与风险。随着敏捷开发与De…

作者头像 李华
网站建设 2026/4/18 22:28:28

用STC15F2K60S2单片机复现蓝桥杯省赛题:一个PWM控制LED亮度的实战案例

基于STC15F2K60S2的蓝桥杯省赛PWM调光项目实战 在嵌入式系统开发领域&#xff0c;蓝桥杯竞赛一直是检验学生单片机应用能力的重要平台。2016年第七届蓝桥杯单片机省赛题目中&#xff0c;PWM调光控制作为核心考点之一&#xff0c;至今仍具有很高的教学价值。本文将带您从零开始&…

作者头像 李华
网站建设 2026/4/18 21:45:16

[嵌入式系统-259]:RT-Thread消息队列与邮箱的区别

在 RT-Thread 中&#xff0c;消息队列 (Message Queue) 和 邮箱 (Mailbox) 都是用于线程间通信&#xff08;IPC&#xff09;的机制&#xff0c;但它们在数据传输方式、效率和适用场景上有显著区别。简单来说&#xff0c;邮箱是轻量级的“指针/整数”传递工具&#xff0c;而消息…

作者头像 李华