转自:http://blog.csdn.net/heyijia0327/article/details/41831529
在这一篇文章中,将主要介绍如何将DSP上采集到的速度转化为Odom,即左右轮速度转化为机器人离起点的x,y坐标和机器人的朝向角yaw,让move_base可以订阅到这个信息并做出相应的路径规划。在wiki论坛上有一个很详细的例程是关于如何发布Odometry信息的,希望大家先仔细阅读。在这个程序里,它把转化好的Odom信息发布到了两个地方,第一个是广播了tf关系,即每次机器人移动以后,/odom坐标系和/base_linke的关系,(关于为什么要发布这tf关系,见第三篇博文);第二个是将消息发布到odom
topic上。这两个东西都将是move_base需要的。
但是它的那段演示程序里,将机器人x轴方向的速度,y轴方向速度,以及旋转速度设置为常数了,实际中肯定是变化的。因此我们只需要将两轮的速度转化为x轴的速度(即前进方向的速度)和绕z轴旋转的速度,再套用到那个程序里去,就能发布机器人的位姿给move_base了。
下面这段程序就是我的转换方法:
[python] view
plain copy
-
def speed_to_odom(self, Lspeed = 0, Rspeed = 0):
-
delta_speed = Rspeed - Lspeed
-
if delta_speed < 0:
-
theta_to_speed = 0.0077
-
else:
-
theta_to_speed = 0.0076
-
-
-
v_th = delta_speed * theta_to_speed / 0.02
-
v_x = (Rspeed + Lspeed)/2.0
-
v_y = 0.0
-
return v_x, v_y, v_th
程序中20ms为速度采样的周期。在这个转换关系,我是把y轴速度设为0,左右轮速度的平均就是前进速度(即x轴速度),左右轮速度的差转化为旋转速度。请注意:将y轴速度设为0这种转换时可行,也就是假定20ms内,机器人没有在垂直于轮子的方向上发生位移。
将左右轮速度转化完以后,就可以用官网的例程发布Odom消息了。
下面总结下思路,再贴出这段的完整源程序。在我的程序中,也就是前面所说的中间通信层程序,首先用pyserial监听串口,一旦收到左右轮的速度信息,马上将左右轮的速度信息转化为x轴方向的前进速度,和绕z轴的旋转速度,然后将这个信息发布到一个主题上(我程序中为car_speed主题)。对官网那段程序进行改进,订阅这个car_speed消息,一旦收到各轴速度,由其速度转化机器人的坐标以及航向角yaw,这些信息作为Odom
topic发布。
首先看如何将左右轮速度值转变为前进速度linear.x和转向速度angular.z的程序,有了linear.x和angular.z以后再来考虑发布odom:
[python] view
plain copy
-
-
-
import roslib;roslib.load_manifest('beginner_tutorials')
-
import rospy
-
from beginner_tutorials.msg import Num, carOdom
-
from geometry_msgs.msg import Twist
-
-
import serial_lisenning as COM_ctr
-
import glob
-
from math import sqrt, atan2, pow
-
-
-
class bluetooth_cmd():
-
def __init__(self):
-
rospy.init_node('robot_driver', anonymous=True)
-
-
def callback(self,msg ):
-
-
cmd_twist_rotation = msg.angular.z
-
cmd_twist_x = msg.linear.x * 10.0
-
cmd_twist_y = msg.linear.y * 10.0
-
-
wheelspeed = self.odom_to_speed(cmd_twist_x, cmd_twist_y,cmd_twist_rotation)
-
print 'msg:', msg
-
print wheelspeed
-
self.blue_tooth_send([wheelspeed[0], self.speed_kp, self.speed_ki, wheelspeed[1]])
-
-
def odom_to_speed(self, cmd_twist_x =0, cmd_twist_y=0,cmd_twist_rotation=0):
-
-
cent_speed = sqrt(pow(cmd_twist_x, 2) + pow(cmd_twist_y, 2))
-
yawrate2 = self.yawrate_to_speed(cmd_twist_rotation)
-
-
Lwheelspeed = cent_speed - yawrate2/2
-
Rwheelspeed = cent_speed + yawrate2/2
-
-
return Lwheelspeed, Rwheelspeed
-
-
def yawrate_to_speed(self, yawrate):
-
if yawrate > 0:
-
theta_to_speed = 0.0077
-
else:
-
theta_to_speed = 0.0076
-
-
x = (yawrate * 0.02) / theta_to_speed
-
return x
-
-
def talker(self):
-
self.rec_data = COM_ctr.SerialData( datalen = 2)
-
allport = glob.glob('/dev/ttyU*')
-
port = allport[0]
-
baud = 115200
-
openflag = self.rec_data.open_com(port, baud)
-
-
rospy.Subscriber("/cmd_vel", Twist, self.callback)
-
-
pub = rospy.Publisher('car_speed', carOdom)
-
pub_wheel = rospy.Publisher('wheel_speed', Num)
-
-
r = rospy.Rate(500)
-
Lwheelpwm= 0
-
-
sumL = 0
-
sumR = 0
-
-
while not rospy.is_shutdown():
-
all_data = []
-
if self.rec_data.com_isopen():
-
all_data = self.rec_data.next()
-
-
if all_data != []:
-
wheelspeed = Num()
-
car_speed = carOdom()
-