前言

硬件
英伟达NX
USB转串口模块
环境
Ubuntu18.04
ROS Melodic
串口助手

一、安装ROS串口驱动

安装ROS串口

sudo apt-get install ros-melodic-serial

安装完后在一个新的终端里输入

roscd serial/

如果能够正常cd到/opt/ros/melodic/share/serial,说明串口驱动安装成功.

二、新建软件包编译

mkdir -p ~/serial_ws/src
cd ~/serial_ws/src/
catkin_init_workspace
cd ~/serial_ws/
catkin_make
echo "source ~/serial_ws/devel/setup.bash">>~/.bashrc
source ~/.bashrc 
echo $ROS_PACKAGE_PATH

新建功能包:

cd ~/serial_ws/src/
catkin_create_pkg serial_test roscpp rospy std_msgs serial

三、实现串口收发

主要的逻辑是在serial_test1节点接收串口数据并解析,然后通过话题发布给serial_test2。在serial_test2中发布需要发送的数据给serial_test1进行订阅,然后在serial_test1中发送。
待续。。
自定义消息
参考:https://mbot1.blog.csdn.net/article/details/124212863?spm=1001.2014.3001.5502

cd ~/serial_ws/src/serial_test
mkdir msg
cd msg
gedit serial_test.msg

填入如下:

std_msgs/Header header
float32 test1
int32   test2

编辑package.xml文件

gedit ~/serial_ws/src/serial_test/package.xml

确保它包含以下两行且没有被注释。如果没有,添加进去:

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

修改serial_test包下面的CMakeLists.txt文件:

gedit ~/serial_ws/src/serial_test/CMakeLists.txt

message_generation添加到COMPONENTS列表中
请添加图片描述
添加运行时依赖关系CATKIN_DEPENDS message_runtime
请添加图片描述
添加msg文件

add_message_files(
  FILES
  serial_test.msg
 )

确保generate_messages()函数被调用

generate_messages(
DEPENDENCIES
 std_msgs
  )

请添加图片描述
添加完后无需编译在终端使用rosmsg show serial_test即可查看是否添加成功
在这里插入图片描述
编辑serial_test1代码

cd ~/serial_ws/src/serial_test/src
gedit serial_test1.cpp

填入以下代码并保存
serial_test1的代码的主要功能是订阅serial_test2节点中发布的话题,并将话题内容通过串口发出,同时接收串口数据并通过话题发布出去

//serial_port.cpp
#include <ros/ros.h>
#include <serial/serial.h>
#include <iostream>
#include <string>
#include <cstring>
#include "serial_test/serial_test.h"

//创建一个serial类
serial::Serial sp;
ros::Publisher pub_serial_RX;
ros::Subscriber sub_serial_TX;
serial_test::serial_test serial_RX;

void serial_tx_cb(const serial_test::serial_testConstPtr &serial_tx_ptr)
{
    uint8_t buffer[2];
    buffer[1]=serial_tx_ptr->test1;
    buffer[2]=serial_tx_ptr->test2;
    sp.write(buffer,sizeof(buffer));
}
int main(int argc, char** argv)
{
    ros::init(argc, argv, "serial_test1");
    //创建句柄
    ros::NodeHandle n;
    //创建timeout
    sub_serial_TX=n.subscribe("/serial_test_TX", 10, &serial_tx_cb);
    pub_serial_RX = n.advertise<serial_test::serial_test>("/serial_test_RX", 10);
    serial::Timeout to = serial::Timeout::simpleTimeout(100);
    //设置要打开的串口名称
    sp.setPort("/dev/ttyTHS0");
    //设置串口通信的波特率
    sp.setBaudrate(115200);
    //串口设置timeout
    sp.setTimeout(to);
    try
    {
        //打开串口
        sp.open();
    }
    catch(serial::IOException& e)
    {
        ROS_ERROR_STREAM("Unable to open port.");
        return -1;
    }

    //判断串口是否打开成功
    if(sp.isOpen())
    {
        ROS_INFO_STREAM("/dev/ttyTHS0 is opened.");
    }
    else
    {
        return -1;
    }

    ros::Rate loop_rate(50);

    while(ros::ok())
    {
        //获取缓冲区内的字节数
        size_t n = sp.available();

        uint8_t buffer[n];
        if(n!=0)
        {
            printf("n=%ld\n",n);
            sp.read(buffer, n);
            if(buffer[0]==0xfd&&buffer[1]==0x88)
            {
                serial_RX.test1=buffer[2];
                serial_RX.test2=buffer[3];
                printf("test1=%02x,test1=%02x\n",serial_RX.test1,serial_RX.test2);
            }
        }
        pub_serial_RX.publish(serial_RX);
        ros::spinOnce();
        loop_rate.sleep();
    }

    //关闭串口
    sp.close();

    return 0;
}

然后编辑serial_test2.cpp

cd ~/serial_ws/src/serial_test/src
gedit serial_test2.cpp

填入以下内容
serial_test2的主要作用是订阅serial_test1接受到的串口数据并打印出来,同时将需要串口发送的数据通过话题发布出去

//serial_port.cpp
#include <ros/ros.h>
#include <serial/serial.h>
#include <iostream>
#include <string>
#include <cstring>
#include "serial_test/serial_test.h"

ros::Publisher pub_serial_TX;
ros::Subscriber sub_serial_RX;
serial_test::serial_test serial_TX;
void serial_rx_cb(const serial_test::serial_testConstPtr &serial_rx_ptr)
{
    printf("test1=%02x,test1=%02x\n",serial_rx_ptr->test1,serial_rx_ptr->test2);
}
int main(int argc, char** argv)
{
    ros::init(argc, argv, "serial_test2");
    //创建句柄
    ros::NodeHandle n;
    //创建timeout
    sub_serial_RX=n.subscribe("/serial_test_RX", 10, &serial_rx_cb);
    pub_serial_TX = n.advertise<serial_test::serial_test>("/serial_test_TX", 10);

    ros::Rate loop_rate(50);

    while(ros::ok())
    {
        serial_TX.test1++;
        serial_TX.test2++;
        pub_serial_TX.publish(serial_TX);
        ros::spinOnce();
        loop_rate.sleep();
}
     return 0;
}

修改~/serial_ws/src/serial_test/下的CmakeLists.txt.

cd ~/serial_ws/src/serial_test/
gedit CMakeLists.txt

在文件的最后加上:

add_executable(serial_test1 src/serial_test1.cpp)
add_dependencies(serial_test1 ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(serial_test1  ${catkin_LIBRARIES})
add_executable(serial_test2 src/serial_test2.cpp)
add_dependencies(serial_test2 ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(serial_test2  ${catkin_LIBRARIES})

编译

cd ~/serial_ws
catkin_make
. ~/serial_ws/devel/setup.bash

四、测试

NX上有三个板载串口,我这里使用ttyTHS0.
对应的引脚如下:
在这里插入图片描述
其中ttyTHS0的TX对应上图引脚8,RX对应上图引脚10.
将ttyTHS0的TX接到USB转串口模块的RX,将tyTHS0的RX接到USB转串口模块的TX,同时将USB转串口模块的GND接到NX上的GND,我这里接的是6号引脚.

在这里插入图片描述
接好线后,将USB转串口模块接到电脑的串口助手上.

可以在NX的终端上查看一下串口的端口号

cd /dev
ls

ttyTHS开头的就是板载串口
在这里插入图片描述

在NX上先执行如下命令赋予权限,否则无法打开串口

sudo chmod 777 /dev/ttyTHS0

然后运行节点

roscore

先打开一个终端,执行:

rosrun serial_test serial_test1

再打开一个终端,执行:

rosrun serial_test serial_test2

执行

rqt_graph

如下:
在这里插入图片描述

打开串口助手,连接上USB转串口模块,设置波特率为115200,数据位8位,无校验位,1位停止位,无流控,打开串口后,以16进制显示,可以看到串口收到递增的数据,
在这里插入图片描述

然后向NX发送一些数据进行测试,以16进制发送,发送数据头为0xfd和0x88,例如以16进制发送数据fd885678,可以在运行serial_test2的终端中显示接收到的数据
在这里插入图片描述

代码地址:
https://gitee.com/Mbot/serial_test.git

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐