前几日有学弟问我,ros如何跟下位机通信呢?
我的第一反应就是rosserial通信协议,rosserail是用于非ROS设备与ROS设备进行通信的一种协议。它为非ROS设备的应用程序提供了ROS节点和服务的发布/订阅功能,使在非ROS环境中运行的应用能够通过串口或网络能够轻松地与ROS应用进行数据交互。 学弟听后兴高采烈地就去找资料学习去了,不过过了几个小时回来就对我说:学长,你说的这个也太麻烦了,有没有一下就学会的速成宝典之类的。我不敢说自己有什么速成宝典,但确实有所谓好理解的东西。 因为我们知道,在接手一个新的通信协议后肯定会花一点时间去研究,上手,理解之后才能掌握。但是如果使用我们自己之前学过的协议来实现,那会大大减少工作的难度。 串口通信协议是我们常见的通信协议,在学单片机时这也是作为一个很重要很基础的部分,因此像这种通信协议对我们而言是比较熟悉方便的。
首先介绍一下Serial, Serial is a cross-platform, simple to use library for using serial ports on computers. This library provides a C++, object oriented interface for interacting with RS-232 like devices on Linux and Windows. Want to use it with ROS(Robot Operating System)? No problem, it compiles as a unary stack. 用到的主类就是Serial
serial::Serial Stm32_Serial; //声明串口对象
Stm32_Serial.setPort("/dev/sensor");//选择哪个口,如果选择的口没有接串口外设初始化会失败
Stm32_Serial.setBaudrate(9600);//设置波特率
serial::Timeout _time = serial::Timeout::simpleTimeout(2000);//超时等待
Stm32_Serial.setTimeout(_time);
Stm32_Serial.open();//串口开启
以上就是相应的串口初始化 然后我们再看看要发送的内容以及确定的格式
unsigned char *a; //定义unsigned char*类型
a=(unsigned char *)malloc(sizeof(unsigned char)*3); //大小
a[0]='1';
a[1]=0x0d;
a[2]=0x0a;
Stm32_Serial.write(a,3); //发送函数
这个是Serial::serial类的成员,我们用到的就是建图所指,第一个参数是a指针,第二个为大小。a[1]和a[2]是32usart接收函数需要的,默认我们只发1这个字符,这样发送某个字符就完成了。 那么接下来说一下接收代码
char x,y,m,n;
string rec_buffer; //string类型
const char *Receive_Data_Pr; //
rec_buffer=Stm32_Serial.readline(4,"\n");//读串口数据
Receive_Data_Pr=rec_buffer.data(); //转换类型
for(i=0;i<4;i++)
{
if(i==0) x=Receive_Data_Pr[i];
if(i==1) y=Receive_Data_Pr[i];
if(i==2) n=Receive_Data_Pr[i];
if(i==3) m=Receive_Data_Pr[i];
}
首先将接受的数据转换成string类型,紧接着将数据转换成char类型,从而完成了字符串的接收以及分离出字符。之后将字符进行处理无论转换成那种格式都会比较方便了。 这里我贴一下源码(这个是当时做的一个工程文件里的一部分,大家根据自己实际需求自行修改)
#include "ros/ros.h"
#include <iostream>
#include <string.h>
#include <string>
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <serial/serial.h>
#include <fcntl.h>
#include <stdbool.h>
#include <std_msgs/String.h>
#include <std_msgs/Float32.h>
using std::string;
string rec_buffer; //串口数据接收变量
int main()
{
FILE *pf=NULL;
int i;
char x,y,m,n;
unsigned char *a;
a=(unsigned char *)malloc(sizeof(unsigned char)*3);
serial::Serial Stm32_Serial; //声明串口对象
const char *Receive_Data_Pr;
float num;
Stm32_Serial.setPort("/dev/sensor");//选择哪个口,如果选择的口没有接串口外设初始化会失败
Stm32_Serial.setBaudrate(9600);//设置波特率
serial::Timeout _time = serial::Timeout::simpleTimeout(2000);//超时等待
Stm32_Serial.setTimeout(_time);
Stm32_Serial.open();//串口开启
a[0]='1';
a[1]=0x0d;
a[2]=0x0a;
Stm32_Serial.write(a,3);
for(i=0;i<1;i++)
{
Stm32_Serial.write(a,3);
sleep(1);
rec_buffer=Stm32_Serial.readline(4,"\n");//读串口数据
Receive_Data_Pr=rec_buffer.data();
for(i=0;i<4;i++)
{
if(i==0) x=Receive_Data_Pr[i];
if(i==1) y=Receive_Data_Pr[i];
if(i==2) n=Receive_Data_Pr[i];
if(i==3) m=Receive_Data_Pr[i];
}
pf=fopen("/home/tcuzel/FBIwenjian/1.txt", "w" );//假设test.txt文件为空
if(!pf)
{
printf("打开文件失败,程序退出!");
exit(1);
}
fprintf(pf,"%c%c.%c%c\n",x,y,n,m);//写入,test.txt文件内容为10 12.345000 testinfo
sleep(1);
}
Stm32_Serial.close();//关闭串口
ROS_INFO_STREAM("Shutting down");//close
return 0;
}