前幾日有學弟問我,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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}