Ubuntu16.04环境下STM32和ROS间的串口通信

本文介绍了在Ubuntu 16.04环境下,如何实现STM32单片机与ROS之间的串口通信。讲解了通信协议设计、共用体在数据传输中的应用,以及硬件连接、串口权限设置等前期准备。提供了STM32和ROS端的代码部署与测试步骤,帮助读者理解和实现STM32与ROS的串口通信。
摘要由CSDN通过智能技术生成

前言

在实际的数据采集中可以利用单片机STM32进行数据采集,然后将采集到的数据发送到电脑上,最常用的方法就是串口通信和TCP/IP通信,这里先介绍串口通信部分(在这里对串口通信协议本身不做过多的解释,想要对协议本身了解更加详细的可以去网上详细查一下,资料很多),在这里源码使用的是古月居的STM32和ROS机器人通信的源码。

介绍

<1> 最终协议的样子

我这里实现的STM32和ROS的串口通信协议如下图:
在这里插入图片描述

STM32端和ROS端都有一个数据发送函数和一个数据接收函数,发送和接收的内容就是如上图所示的数据包,该数据包含有数据头(55aa)、数据尾(0d0a)、校验(crc8),保证数据正确安全。通信协议也容易自行扩展更改。

<2> 本方案提供的API实现的功能

STM32向ROS发送左轮实时轮速、右轮实时轮速、航向角、预留控制位(一个字节可灵活使用)。
ROS向STM32发送左轮设定速度、右轮设定速度、预留控制位(一个字节可灵活使用)。

原理

<1> 简要叙述

首先明确:串口发送数据是一个字节一个字节的数据发送,串口接收数据同样是这样。一个字节最大表示的数据只是255,往往我们需要传递的传感器数据,都需要使用short\int\float数据类型的变量进行存储。

传统串口通信方法采用数据分离技术,比较复杂。如下图所示,这里将淘汰该种方法。

数据合成:将接收到的几个字节合成(short\int\float类型的)数据。
数据分离:将(short\int\float类型的)数据分解成一个个字节发送出去。
在这里插入图片描述
于是,这里发送大于一个字节的数据,就需要采用共用体的方法。
关于共用体,你只需要知道以下几点:
(1) C语言的一种机制,结构体内不同成员共享内存的机制,(即内存地址一致)
(2) 同一时刻,只能访问其中的一个成员
(3) 不同成员,按照成员类型的性质进行内存访问,这个访问机制就是咱们使用的特性

<2> 这里是如何使用共用体的?

关于该协议中发送\接收数据的原理介绍,这里利用c语言中的共用体特性,通信的两端都定义同样数据结构的共用体,该共用体中包含一个short\int\float类型的变量和一个unsigned char类型的数组,该数组的大小和short\int\float字节大小对应。这样发送和接收数据时,就只发送或者接收共用体中的unsigned char数组的元素。
在这里插入图片描述

前期准备

<1> 确保硬件连接

STM32单片机 + TTL转USB模块(CH340)+ Linux系统(这里的Linux系统可以是PC也可以是树莓派或者TX2等硬件设备)
线路连接:
在这里插入图片描述

这里有几条特别要注意的,这些是代码部署的前提
(1)确保STM32端和ROS端串口波特率一定保持一致。
(2)确保STM32串口的Tx和Rx是按照上图和TTL转USB模块连接在一起,一定不是Tx和Tx相连接,Rx同理,也要测试连接线的好坏。
(3)确保装载Linux系统的设备,具有CH340\CH341的驱动,一般都有,但是TX2板子自带的系统就没有,解决方法网上很多,也可以直接刷系统,刷系统 点击这里
我使用的是PC,在ubuntu16.04系统中安装CH340教程:ubuntu16.04使用USB转TTL(ch340)串口转usb调试过程
(4)确保自己的串口在Linux系统上具有超级用户权限(一般默认都不具有该权限),一般插上TTL转USB模块,系统会出现ttyUSB0的串口设备。
(5)一定将给大家的ROS功能包中mbot_linux_serial.cpp文件中的的串口设备名字,改为大家自己的设备名字

boost::asio::serial_port sp(iosev, "/dev/ttyUSB0"); #默认是/dev/ttyUSB0,如若不是必须更改

<2> 查看串口设备方法

Linux设备插上TTL转USB模块后,打开一个终端,输入下面命令,回车

ls -l /dev/ttyUSB*

如果终端出现类似下面的,说明你的串口设备已经被识别,比如这里/dev/ttyUSB0为串口设备的名字

crw-rw---- 1 root dialout 188, 0 Aug  3 21:46 /dev/ttyUSB0

如果你使用的虚拟机的话,就算有驱动可能也识别不到设备,这个时候你需要对虚拟机进行设置。
点击菜单栏的编辑,然后点击首选项,出现类似下面的图
在这里插入图片描述
点击USB,出现如下图,选择,将设备连接到虚拟机,点击确定,插拔串口设备,以后每次插拔设备,都是自动连接到虚拟机上
在这里插入图片描述

<3> 串口权限设置方法

在终端中输入下面命令

sudo chmod 777 /dev/ttyUSB0 #按照自己的设备名字对ttyUSB0进行更改

如果没有返回任何字符,说明串口设备权限设置成功,但是这个方法,在每次使用串口设备前都要进行这样的操作.
工程代码下载:
https://pan.baidu.com/s/1VGIva5YhIOB5Cf_muHICjA
提取码:0v7T

工程文件包括:
(1)STM32端:STM32F103与ROS串口通信测试工程文件
(2)ROS端:ROS与STM32F103串口通信测试功能包文件

STM32程序结构:
主要包括:
(1)串口通信硬件初始化程序文件usart.c,参数为波特率设置,这里默认设置115200
(2)通信协议程序文件mbotLinuxUsart.c
(3)系统结构测试主程序文件main.c
在这里插入图片描述
STM32下位机软件使用介绍:
首先是STM32串口参数的配置:(这里配置代码和相关例程都一致)

波特率=115200
数据长度=8位
停止位=1个
奇偶校验位=无
硬件数据流控制=

其次是函数使用说明,封装函数如下图:
在这里插入图片描述
这里做简单说明:
函数usartReceiveOneData(int *p_leftSpeedSet,int *p_rightSpeedSet,unsigned char *p_crtlFlag),填入地址参数作数据获取,使用时放在相应串口的中断服务函数中即可。如这里使用的串口1,如下图所示:
在这里插入图片描述
函数usartSendData(short leftVel, short rightVel,short angle,unsigned char ctrlFlag),填入需要发送的数据变量作发送,使用时放入指定频率的循环里使用,每次发送一次数据,最好延时10-15ms,下位机发送和上位机接收都需要时间(时间和串口波特率有关)。我使用的如下图所示:
在这里插入图片描述
其余的两个函数是被上面两个函数调用的,这里就不多说了。

注意:
在外部引用函数时,注意引用头文件#include “mbotLinuxUsart.h”
小伙伴在编译时,可能出现#include "mbotLinuxUsart.h"文件下 sys.h不存在,原因是使用的不是正点原子的例程,此时将#include <sys.h> 替换为各自版本的配置头文件,如果不清楚,就在其他.h文件中复制粘贴已有的头文件,关于stm32的

ROS测试功能包程序结构:
主要包括:
(1)通信协议以及串口配置程序文件mbot_linux_serial.cpp
(2)系统结构测试主程序文件publish_node.cpp
(3)一个基础ROS功能包具备的其他程序文件
在这里插入图片描述
ROS上位机软件使用介绍:(PC)
看图说话,下面共有四个函数,看函数名和参数就可以理解用途。
在这里插入图片描述
首先是调用头文件#include “mbot_linux_serial.h”,然后进行初始化串口
在程序初始化的时候调用serialInit()函数,内置串口参数和下位机串口参数一致。
然后就是在调用writeSpeed(double RobotV, double YawRate,unsigned char ctrlFlag)函数,参数是机器人线速度和角速度,也就是/cmd_vel的数据。将机器人的需要设定的速度下发到下位机。
最后就是调用readSpeed(double &vx,double &vth,double &th,unsigned char &ctrlFlag)函数,这里使用的引用,输入存放机器人线速度、角速度、角度的变量即可。为了发布机器人里程计用的。

注意:
这里需要两个参数根据自己的机器人进行更改,ROBOT_LENGTH 机器人真实轮间距(从左侧轮子中心到右侧轮子中心的距离),ROBOT_RADIUS 机器人轮间距的一半。
文中boost::asio::serial_port sp(iosev, “/dev/mbot”);的设备名字是我的串口的设备名字,小伙伴可以根据自己的进行更改,例如,/dev/ttyUSB0。
到这里大家肯定都可以愉悦的使用了。如果想知道细节,请往下看。

方案的原理解释:
此方案用的是共用体的思路,上面小伙伴们也都对共用有个大致的了解。这是一种按照共用体内成员的数据类型进行内存访问的特性,不同数据类型按照自己的类型访问内存。上位机和下位机的原理是一致的。都定义了数据头、数据尾的常量,和收发共用体。

下位机发送的数据协议: 上位机发送的数据协议:
在这里插入图片描述

STM32的串口接收原理:每接收到一个字节就会触发一次中断,我这里采用在串口的中断服务函数中进行数据接收的解析,具体函数体现在receiveTo103()
根据上位机发送的协议进行判断解析,详见代码,注释清晰。
Linux上位机采用ASIO,ASIO不仅支持网络通信,还能支持串口通信。
这里采用boost::asio::write(sp, boost::asio::buffer(buf));发送数据
使用boost::asio::read_until(sp, response, “\r\n”,err);
copy(istream_iterator(istream(&response)>>noskipws),
istream_iterator(),buf);

获取数据,再具体的细节需要见源码解释了。脑子里的思想就是把相应的数据放到相应的位置,没有数据解析概念,对应的字符数据存好后,就可以通过另外一个成员访问了。

代码部署

<1> STM32端

STM32端的为工程文件,下载之后就可以进行编译。如果是103的板子直接下载测试就好了。如果不是F103的板子,可以将mbotLinuxUsart.c和mbotLinuxUsart.h移植到对应的工程中即可。函数调用参照main.c即可。

#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "mbotLinuxUsart.h"//引用该头文件是使用,通信协议的前提

//测试发送变量
short testSend1   =5000;
short testSend2   =2000;
short testSend3   =1000;
unsigned char testSend4 = 0x05;

//测试接收变量
int testRece1     =0;
int testRece2     =0;
unsigned char testRece3 = 0x00;

int main(void)
{    
//======================================硬件初始化====================================================
    delay_init();                                    //延时函数初始化    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断优先级分组2
    uart_init(115200);                                //串口初始化为115200

//=======================================循环程序=====================================================
    while(1)
    {
        //将需要发送到ROS的数据,从该函数发出,前三个数据范围(-32768 - +32767),第四个数据的范围(0 - 255)
        usartSendData(testSend1,testSend2,testSend3,testSend4);
        //必须的延时
        delay_ms(13);
    } 
}

//====================================串口中断服务程序=================================================
void USART1_IRQHandler()
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
      {
         USART_ClearITPendingBit(USART1,USART_IT_RXNE);//首先清除中断标志位
         //从ROS接收到的数据,存放到下面三个变量中
         usartReceiveOneData(&testRece1,&testRece2,&testRece3);
     }
}
//===========================================END=======================================================

<2>ROS端

前提:已成功安装ROS
第一步:创建工作空间,并编译(已经创建过工作空间的直接跳到第二步)
打开一个终端,依次执行下面命令

mkdir -p ~/catkin_ws_test/src
cd catkin_ws_test
catkin_make

第二步:将下载的topic_example功能包复制到src目录下

cd src
手动复制即可
cd ..
catkin_make

出现下图即编译成功
在这里插入图片描述

代码测试

<1>确保设备连接:

上面的前期准备,没有问题的话,就通电连接将设备连接在一起就行了,如果有问题,请先解决再进行下面的步骤

<2>打开新终端,启动ros master

roscore

<3>打开新终端,启动测试功能包

#查看串口设备
ls -l /dev/ttyUSB*

终端打印下面信息

crw-rw---- 1 root dialout 188, 0 Aug  3 21:46 /dev/ttyUSB0

如果这里不是/dev/ttyUSB0,一定要更改ROS功能包中mbot_linux_serial.cpp文件中的的串口设备名字

#添加设备权限
sudo chmod 777 /dev/ttyUSB0  #根据自己的设备名自行改变
#source
cd catkin_ws_test
source devel/setup.bash
#启动功能包节点
rosrun topic_example publish_node

终端出现下面的图,打印的是从STM32接收的测试数据
在这里插入图片描述
同时可以使用keil仿真,查看ROS向STM32发送的测试数据,出现下图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考文献

https://zhuanlan.zhihu.com/p/166496656
https://zhuanlan.zhihu.com/p/165162578

  • 7
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值