最近在完成调度系统与AGV之间到通信,由于调度系统与AGV不采用ros多机通信,因此特地写了一个基于python的ROS TCP socket通信
特点:通信断线自动重连
工作流程:调度系统给AGV发送一个位置指令,需要将调度系统的通信协议通过python socket解析出数据,然后发送目标位置给底层move_base 包,让AGV自动运动起来。
难点:自动重连、数据解析、ROS action消息发布、多线程运行socket、数据处理和ROS
1.数据解析
调度系统将十六进制数打包成字符串发送,所以接收到数据后,确保帧头帧尾是对应的,接着再对字符串进行分割,如ffab变成0xff,0xab。
调度系统将10变成了十六进制0a发送过来,得到字符串'0a'先进行字符串分割
int(x,base)
- x -- 字符串或数字。
- base -- 进制数,默认十进制。
int(x,16)意思将里面的字符串或数字表示为16进制数转换成10进制,其实直接转换就好了,没必要再chr().当初在flow国外网站看见别人这样去解析,但是没有多去思考
即 int('0a',16) = 10
chr(i)
参数
- i -- 可以是10进制也可以是16进制的形式的数字。
返回值
返回值是当前整数对应的 ASCII 字符。
实例
以下展示了使用 chr() 方法的实例:
>>>print chr(0x30), chr(0x31), chr(0x61) # 十六进制
0 1 a
>>> print chr(48), chr(49), chr(97) # 十进制
0 1 a
#!/usr/bin/python
# -*- coding: utf-8 -*-
bits = ''
for x in xrange(14,30,2): #从14开始步长为2
bits += chr(int(msg[x:x+2], 16))
所以上述得到的bits是含有ASCII字符的字符串。
对于 unpack 而言,只要 fmt 对应的字节数和字节字符串 string 的字节数一致,就可以成功的进行解析,否则 unpack 函数将抛出异常
接着再用struct.unpack()函数去进行解包字符串,由于是整形解包,得到的是ASCII字符对应的整数。
#######吐槽自己######
首先,当时数据解析这里没有去细究,没有写好写精简,直接复制别人的,但是繁琐多余
直接用int()类型转换,由于之前不知道int()可以将字符串作为16进制转换int
2.简化后数据解析:
1.假设拿到字符串数据‘FF001122FF0A0B’,根据协议分割字符串得到需要的主要数据信息X,Y,假设数据是1122
X = data[4:6] Y = data[6:8]
2.使用int()函数强制类型转换,得到10进制整数
X = int(X,16) Y = int(Y,16)
3.自动重连
关于socket重连,首先要说明一点,需要一直循环, accpet()函数,当连接成功后下面语句只执行一次,等待第二次成功连接才会返回数据
4.多线程
首先ROS必须为主线程,所以别的函数开线程。 线程1是socket通信函数,线程1里面再开一个线程一直循环处理数据函数,因为需要调用到socket这个线程里面的一些参数(conn,addr) 去接收发送数据
5.发布目标位置给AGV
参考了古月居老师的博客和另一个用python写导航的博主博客。用python写发布信息和发送目标点的代码比较少,常用都是C++。主要是需要对python一些调用库,调用的模块要熟悉,可惜不好查询,因此不建议用python写ROS。
心得主要是第一次用python发送数据和写socket,但是下次的话还是建议自己比较熟悉的C/C