我是靠谱客的博主 幸福导师,最近开发中收集的这篇文章主要介绍move_base 对机器人的控制,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

转载学习:https://www.cnblogs.com/arbain/p/7850838.html

这里我主要画一下重要的知识点(以黑体描述):

 本教程将具体涉及如下问题:

    系列(1):move_base发出的控制指令是什么?该如何转化为移动机器人左右轮的速度。

    系列(2):移动机器人的左右轮的编码器信息如何转化为ROS的/odom;

    系列(3):navigation的几个坐标系(/map frame , /odom frame , /base_link frame)是什么,他们之间该如何建立tf转换;如何使用move_base在一个空白的地图(blank map)上完成对实际机器人的控制。

    

控制系统的架构:

    关于机器人导航与定位的系统架构,这里按照自己的理解以及开发经验给出三个层次。

    最底层:机器人本身的电机驱动部分,该部分通过串口接收电脑端输出的左右轮期望速度对左右轮分别进行PID控速。同时,定时采样电机码盘值并转化为左右轮速度值通过串口上传给电脑当然PID控速这一部分也可以放到电脑ROS端,这样的话,电脑串口输出的是直接的PWM值而不是之前的期望速度了

   中间通信层电脑端和底层电机的控制通信以及将传感器信息发布给ROS的通信。这一层主要通过串口(ROS已经集成了pyserial 用python操作这个模块进行串口控制)收集左右轮速度值,用航迹推演法将左右轮速度转化为机器人的x轴方向速度和机器人的旋转速度,然后发布/odom主题,好让ROS的相应package收到这个消息,进行机器人位置的估计。同时,这一部分还要关注ROS相应部分发出的机器人控制指令,转化为左右轮的期望速度,再通过串口传给DSP。这一层是自己写程序完成。

   决策层:就是与导航有关的了,建立地图和定位,然后用move_base根据你发布的传感器信息做出路径规划以及机器人的速度和转向控制。这一部分为ROS相应的package已经完成,我们只需要调用即可。

   在这个系列里,我们只关注如何用 move_base package 做出的控制对机器人进行实际控制。文章接下来的部分将按照从上到下的顺序,一个问题接一个问题的来介绍如何使用move_base控制实际机器人。

 

1. move_base package的系统介绍:

     ROS提供的move_base 包让我们能够在已建立好的地图中指定目标位置和方向后,move_base根据机器人的传感器信息控制机器人到达我们想要的目标位置。它主要功能包括:结合机器人码盘推算出的odometry信息,作出路径规划,输出前进速度和转向速度。这两个速度是根据你在配置文件里设定的最大速度和最小速度而自动作出的加减速决策。下面的白色底色方框内就是move_base的内容:

 

在此框架中白色和灰色的都是ROS已经封装好的功能包

  • map_server
    • gmapping:根据激光数据+里程odom数据构建地图http://wiki.ros.org/gmapping
    • hector:根据激光数据构建地图http://wiki.ros.org/hector_slam
  • acml:根据激光数据在已有的地图上定位http://wiki.ros.org/amcl
  • move_base:路径规划,根据地图,激光数据,使得机器人从一个位置到达另外一个位置,可以避开障碍物http://wiki.ros.org/move_base

这其中gmapping 和hector的功能是一样的,都是用来构建地图的,区别在于gmapping在构建过程中依赖于机器人的里程odom数据,hector则不需要odom,算法不同,在实际使用中选用其中的一个就可以了。

而蓝色标识的功能包则需要根据选用硬件平台的不同来定制。

图中我们可以看到move_base package 的输入和输出。要使得它能运行起来,我们就得构建好这些输入和输出。

必要的输入

      goal : 期望机器人在地图中的目标位置。

      tf : 各个坐标系之间的转换关系。(具体/map frame --> /odom frame ,/odom frame --> /base_link frame)      

     odom:根据机器人左右轮速度推算出的航向信息(即/odom 坐标系中机器人x,y坐标以及航向角yaw,下面会具体介绍)

     激光传感器的信息,用于定位。

输出

     cmd_vel:在cmd_vel这个主题上发布Twist消息,这个消息包含的就是机器人的期望前进速度和转向速度。

      再整理下思路:move_base收到goal以后,将目标goal通过基于actionlib的client(客户端)向服务器发送,服务器根据你的tf关系以及发布的odom消息不断反馈机器人的状态(feedbackcall)到客户端, 让move_base做路径规划和控制twist。

重点还是TF关系。

     知道了move_base的这些外围消息接口以后,move_base的运行还需要一些内部的配置参数,如机器人的最大最小速度,已经路径规划时的最大转弯半径等等(机器人过弯的能力),这些参数配置在《Ros by Example 1》的8.1.2节有详细介绍。关于move_base更详细的介绍请点击官网wiki教程。

     至此,我们已经熟悉了move_base的各种接口,它订阅了什么消息,会发布什么消息都已经清楚了。因此让move_base控制实际的机器人最主要的就是要解决实际机器人如何发布这些消息给move_base,以及如何接受move_base发出的消息。

 

2. Twist 消息转化为机器人左右轮期望速度。

    首先,假设move_base能够正常工作了,它将把控制命令Twist发布到cmd_vel这个主题上。我们现在来解决如何利用这个Twist消息来对机器人进行控制。 (怎样使用这个Twist 消息控制机器人)

    在ROS by example 一书中的第七章开头就规定了机器人自身的坐标系系统,如下图。注意两个坐标系的建立都是右手坐标系,左图中的右手就是机器人本身,x轴就是前进的方向垂直于两轮之间的轴连线Y轴就是两个轮之间的轴连线。右图表示机器人的旋转坐标系,大拇指指向Z轴,逆时针方向为正值。

清楚了坐标系以后,再来看看Twist这个消息里包含的是什么东西。

       使用ctrl + alt + t 打开一个新的终端以后,输入如下命令,就可以查看Twist的消息类型了。

rosmsg show geometry_msgs/Twist  

其中linear 的x就是代表前进方向的速度,单位为m/s。angular 的z就代表机器人的绕中心旋转的角速度,单位为 弧度/s (rad/s)。

     因此,我们只要在自己写的中间通信层程序中订阅cmd_twist这个主题(topic),就可以收到move_base发出的命令了。 下面给出一个如何订阅cmd_twist主题的demo。

     首先在你之前建立的package的scripts文件夹下,笔者的是 beginner_tutorials/scripts文件夹,将下列代码复制进去,保存为your_filename.py。保存以后记得要chmod一下,让这个文件成为可执行的节点,具体操作如下。

roscd beginner_tutorials  
cd scripts  
chmod +x lis_cmdvel.py  

程序代码:

复制代码

#!/usr/bin/env python  
#refernence: http://answers.ros.org/question/29706/twist-message-example-and-cmd_vel/  
import roslib; roslib.load_manifest('beginner_tutorials')  
import rospy  
import tf.transformations  
from geometry_msgs.msg import Twist  
  
def callback(msg):  
    rospy.loginfo("Received a /cmd_vel message!")  
    rospy.loginfo("Linear Components: [%f, %f, %f]"%(msg.linear.x, msg.linear.y, msg.linear.z))  
    rospy.loginfo("Angular Components: [%f, %f, %f]"%(msg.angular.x, msg.angular.y, msg.angular.z))  
  
    # Do velocity processing here:  
    # Use the kinematics of your robot to map linear and angular velocities into motor commands  
#    v_l = ...  
#    v_r = ...  
  
    # Then set your wheel speeds (using wheel_left and wheel_right as examples)  
#    wheel_left.set_speed(v_l)  
#    wheel_right.set_speed(v_r)  
  
def listener():  
    rospy.init_node('cmd_vel_listener')  
    rospy.Subscriber("/cmd_vel", Twist, callback)#/cmd_vel  
    rospy.spin()  
      
if __name__ == '__main__':  
    listener()  

复制代码

执行这些操作以后,这个文件就可以用rosrun指令执行了。

rosrun beginner_tutorials lis_cmdvel.py  

注意这个demo里的每当有Twist消息时,就会调用callback这个函数,callback这个函数里就是我们要处理的内容。这里只是简单的打印收到的消息,还没有对消息进行处理。

      机器人期望的前进速度linear.x和转弯速度angular.z都由move_base输出了,那么如何将他们转化成机器人左右轮的期望速度呢?关于如何转化为左右轮的期望速度,我先贴出自己程序中的源代码部分,下面这三个函数是一个属于同一个类:

复制代码

def callback(self,msg ):  
  
    cmd_twist_rotation =  msg.angular.z #  
    cmd_twist_x  = msg.linear.x   
    cmd_twist_y =  msg.linear.y #这个一般为0  
      
    #将twist消息转化为左右轮各自的期望速度  
    wheelspeed = self.odom_to_speed(cmd_twist_x, cmd_twist_y,cmd_twist_rotation)          
    print 'msg:', msg                #打印得到的twist消息  
    print wheelspeed                 #打印转化后的速度   
      
    #蓝牙串口发送到DSP  wheelspeed[0]左轮速度, wheelspeed[1]右轮速度          
    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):  
    '一般情况下,linear_y = 0 所以只需关注twist.linear.x 和 twist.angle.z的转换'  
    #这部分本来还有一段,关于twist.linear.y不为0时,如何转化的程序,Lz自己写的,实际可运行,但是不知道是否正确,所以这里删掉了。  
      
    cent_speed = cmd_twist_x        #前进的速度,即两轮的中心速度  
    #将 指定的转速twist.angular.z 转化为左右轮的差速  
    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  #左转系数  
      
    #yawrate :rad/s *0.02表示 20ms内应该转多少弧度,/0.0076是把 要转的弧度转化为左右轮速度差      
    x = (yawrate * 0.02) / theta_to_speed     
    return   x  

复制代码

这一段程序里最主要的是如何将指定的转速转化为两轮的差速。主程序中订阅了cmd_vel主题,一旦收到move_base发出的twist消息,就调用callback函数进行转化。如果linear.y 不为0,说明小车要沿着y轴运动,这会导致两轮的差速,但是对于两轮控制的移动机器人twist.linear.y = 0 是在move_base的配置文件base_local_planner_params.yaml中有明确指定,所以不需关注linear.y的转换:

max_vel_y = 0.0 #zero for a differential drive robot  
min_vel_y = 0.0  

也就是只要关注前进速度linear.x和旋转速度angular.z的转换。

       在直线行驶时,前进速度linear.x就是左右轮的期望速度。最主要的是将转速转化为左右轮的差速,一个轮子转的快,一个轮子转的慢,就有了转速。

       下面介绍如何将指定的转速转化为两轮差速

       1.dsp采样的是单位时间内的码盘值,将码盘值转化为左右轮速度值后(Lwheelspeed,Rwheelspeed)通过串口发送给电脑端。

       2.关于航迹推演(Odometry) 的公式中有一个关于如何有左右轮差速转化为旋转速度的计算公式。即yaw_rate = (Rwheelspeed - Lwheelspeed) / d .其中d为两轮间的间距,得到的转速单位rad/s。(如果不知道什么是Odometry 方法,可以点击这里。)或者也可以看看这个,还有这个链接。直接用这个公式可以计算,但是在测量这个公式中的d的时候有测量误差。因此,楼主这里采用的拟合的方法得到这个差速到转速之间的转换系数。具体操作如下:

       先从0度开始逆时钟旋转小车(角速度为正),分别记下转到pi/2,pi,pi*3/2,2pi时两轮差速的累计值,(即右轮速度减去左轮速度的累计值)。思路是:两轮差速乘以系数为转速,两轮差速累计值乘以系数就是旋转的角度。因此多次记下这些数据后,拟合就能得到得到特定的差速值到对应角度之间的转换关系。

       如楼主的数据如下:

          角度                 pi/2          pi             3/2*pi       2*pi

       差速累计和       209.21      415          620.54     825.6

                                208.8       414.1       611.49     812.39

由于是线性关系,我们进行拟合以后得到这个转换系数为0.0077,拟合曲线如图,在实际操作中我记录了5组数据:

   顺时针也可以采用这个系数,但是笔者,了防止左右轮机械上的差异导致这个系数不同,对顺时针也单独拟合了一次,得到0.0076。

右轮减去左轮的差速转化为角速度或者角度的系数有了,反过来,就可以将指定的旋转速度得到左右轮差速。

上面可以称为轮子间距系数的标定;

      将指定的转速twist.angular.z * 0.02得到一个速度控制周期内(DSP底层设定的速度采样时间为20ms)应该旋转的角度量,这个角度量除以前面的系数就得到了单位控制周期内两轮之间速度的差异值。这就是上面程序中yawrate_to_speed()函数的计算思路。最后将这个速度的差异值/2,分别添加在中心速度上就分别得到了左右轮的期望速度。

 

       现在完成了从cmd_vel twist 发送到电机这一部分的程序,在下一篇博客中,将介绍如何将介绍如何将电机左右轮的速度发布出来,让move_base接收到。

=================================================================================================

在这一篇文章中,将主要介绍如何将DSP上采集到的速度转化为Odom,即左右轮速度转化为机器人离起点的x,y坐标和机器人的朝向角yaw,让move_base可以订阅到这个信息并做出相应的路径规划。在wiki论坛上有一个很详细的例程是关于如何发布Odometry信息的,希望大家先仔细阅读。在这个程序里,它把转化好的Odom信息发布到了两个地方,第一个是广播了tf关系,即每次机器人移动以后,/odom坐标系和/base_link的关系,(关于为什么要发布这tf关系,见第三篇博文);第二个是将消息发布到odom topic上这两个东西都将是move_base需要的。

       但是它的那段演示程序里,将机器人x轴方向的速度,y轴方向速度,以及旋转速度设置为常数了,实际中肯定是变化的。因此我们只需要将两轮的速度转化为x轴的速度(即前进方向的速度)和绕z轴旋转的速度,再套用到那个程序里去,就能发布机器人的位姿给move_base了。

      下面这段程序就是我的转换方法:

复制代码

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  #左转系数  
          
    #*比例系数是将单位时间内的左右轮位移差(速度差)转化旋转的角度增量,再除以20ms,得到旋转角速度  
    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 #返回x,y轴速度,以及旋转速度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:

复制代码

#!/usr/bin/env python  
# -*- coding: utf-8 -*-  
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 #yawrate :rad/s  *0.02表示 20ms内应该转多少弧度,/0.0076是把 要转的弧度转化为左右轮速度差  
        return   x  
          
    def talker(self):  
        self.rec_data = COM_ctr.SerialData( datalen = 2)  #启动监听COM 线程  
        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)#订阅move_base发出的控制指令  
          
        pub = rospy.Publisher('car_speed', carOdom)  
        pub_wheel = rospy.Publisher('wheel_speed', Num) #左右轮速度  
          
        r = rospy.Rate(500) # 100hz  
        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()  
                leftspeed = all_data[0][0]  
                rightspeed = all_data[1][0]  
                wheelspeed.leftspeed = leftspeed  
                wheelspeed.rightspeed = rightspeed  
                #左右轮速度转化为机器人x轴前进速度和绕Z轴旋转的速度  
                resluts = self.speed_to_odom(leftspeed, rightspeed)  
                car_speed.x = resluts[0]  
                car_speed.y = resluts[1]  
                car_speed.vth = resluts[2]  
  
                pub.publish(car_speed)  
                pub_wheel.publish(wheelspeed)  
                  
            r.sleep()  
           
        if openflag:  
            self.rec_data.close_lisen_com()    
      
    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    # first : transform delta_speed to  delta_theta .   second: dived by delta_t (20ms), get the yawrate  
        v_x = (Rspeed + Lspeed)/10.0/2.0    # Lspeed : dm/s   -- > m/s  so need to /10.0  
        v_y = 0.0  
        return v_x, v_y, v_th  
          
    def blue_tooth_send(self, data = [], head = 'HY'):  
        if data !=[] and self.rec_data.com_isopen():  
            self.rec_data.send_data(data, head)   #绕中心轴旋转 设定为0  
#        print data  
              
if __name__ == '__main__':  
    try:  
        car_cmd = bluetooth_cmd()  
        car_cmd.talker()  
    except rospy.ROSInterruptException: pass  

复制代码

  注意这段程序里用了自己定义的msg:Num 和 carOdom。这两个msg文件存放于beginner_tutorials/msg文件夹下。如果不知道怎么创建msg,可以看官网的教程或者我的另一篇博文。

这里贴出我定义的消息的内容:

Num.msg:

float32 leftspeed  
float32 rightspeed  

carOdom.msg:

float32 x  
float32 y  
float32 vth  

上面程序发布的/car_speed topic就包含了车子的linear.x和angular.z,运行这个节点以后,我们可以使用rostopic指令来监控这个主题发布的频率:

rostopic hz /car_speed  

看主题发布的频率是否和期待的一致。

 

      现在已经将左右轮速度转化为x轴速度和旋转速度了,下面贴出我改进的官网教程代码,教大家如何发布Odom信息和odom与base_link之间的tf转换关系。官网教程里的vx,vy,vth为常数,我们这里先订阅自己上段程序发布的car_speed主题,也就是订阅机器人实时的前进速度x和旋转速度。把官网程序由常数改为机器人实际速度就行了。下面程序为C++写的,在beginner_tutorials/src文件夹下创建空白文档,命名为your_filename.cpp,把下列代码复制进去:

复制代码

#include <ros/ros.h>  
#include <tf/transform_broadcaster.h>  
#include <nav_msgs/Odometry.h>  
#include <beginner_tutorials/carOdom.h>  
//goal:subscribe the car_speed, then send them  
class SubscribeAndPublish  
{  
public:  
  SubscribeAndPublish()  
  {  
     x_ = 0.0;  
     y_ = 0.0;  
     th_ = 0.0;  
  
     vx_ = 0.0;  
     vy_ = 0.0;  
     vth_ = 0.0;  
     current_time_ = ros::Time::now();  
     last_time_ = ros::Time::now();  
    //Topic you want to publish  
    pub_ = n_.advertise<nav_msgs::Odometry>("odom", 1);  
  
    //Topic you want to subscribe  
    sub_ = n_.subscribe("car_speed", 1, &SubscribeAndPublish::callback, this);  
  }  
  
  void callback(const beginner_tutorials::carOdom::ConstPtr& input)  
  {  
    //nav_msgs::Odometry output;  
    //.... do something with the input and generate the output...  
    current_time_ = ros::Time::now();  
      
    vx_ = input->x;  
    vy_ = input->y;  
    vth_ = input->vth;  
      
    //compute odometry in a typical way given the velocities of the robot  
    //double dt = (current_time - last_time).toSec();  
    double dt = 0.02;  
    double delta_x = (vx_ * cos(th_) - vy_ * sin(th_)) * dt;  
    double delta_y = (vx_ * sin(th_) + vy_ * cos(th_)) * dt;  
    double delta_th = vth_ * dt;  
  
    x_ += delta_x;  
    y_ += delta_y;  
    th_ += delta_th;  
  
    //since all odometry is 6DOF we'll need a quaternion created from yaw  
    geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th_);  
  
    //first, we'll publish the transform over tf  
    geometry_msgs::TransformStamped odom_trans;  
    odom_trans.header.stamp = current_time_;  
    odom_trans.header.frame_id = "odom";  
    odom_trans.child_frame_id = "base_link";  
  
    odom_trans.transform.translation.x = x_;  
    odom_trans.transform.translation.y = y_;  
    odom_trans.transform.translation.z = 0.0;  
    odom_trans.transform.rotation = odom_quat;  
  
    //send the transform  
    odom_broadcaster_.sendTransform(odom_trans);  
  
    //next, we'll publish the odometry message over ROS  
    nav_msgs::Odometry odom;  
    odom.header.stamp = current_time_;  
    odom.header.frame_id = "odom";  
  
    //set the position  
    odom.pose.pose.position.x = x_;  
    odom.pose.pose.position.y = y_;  
    odom.pose.pose.position.z = 0.0;  
    odom.pose.pose.orientation = odom_quat;  
  
    //set the velocity  
    odom.child_frame_id = "base_link";  
    odom.twist.twist.linear.x = vx_;  
    odom.twist.twist.linear.y = vy_;  
    odom.twist.twist.angular.z = vth_;  
  
    //publish the message  
    pub_.publish(odom);  
  
    last_time_ = current_time_;  
  
  }  
  
private:  
//   
  ros::NodeHandle n_;   
  ros::Publisher pub_;  
  ros::Subscriber sub_;  
  ros::Time current_time_, last_time_;  
  tf::TransformBroadcaster odom_broadcaster_;  
  double x_ ;  
  double y_ ;  
  double th_ ;  
  
  double vx_;  
  double vy_ ;  
  double vth_ ;  
  
};//End of class SubscribeAndPublish  
  
int main(int argc, char **argv)  
{  
  //Initiate ROS  
  ros::init(argc, argv, "odometry_publisher");  
  
  //Create an object of class SubscribeAndPublish that will take care of everything  
  SubscribeAndPublish SAPObject;  
  
  ros::spin();  
  
  return 0;  
}  

复制代码

  这段程序首先订阅car_speed这个主题,一旦收到机器人的x轴速度和转向速度,就调用callback去发布消息,让move_base可以订阅到。

      注意:这段程序要能运行,必须在你的beginner_tutorials这个包里添加对tf,nav_msgs的依赖。

<depend package="tf"/>  
<depend package="nav_msgs"/>  

要添加对这两个包的依赖,需要修改在package.xml和CMakeLists.txt进行修改:
在package.xml中添加:

<build_depend>tf</build_depend>  
<build_depend>nav_msgs</build_depend>  

<run_depend>tf</run_depend>  
<run_depend>nav_msgs</run_depend>  

然后在CMakeLists.txt中 find_package(...)里添加 tf 和 nav_msgs就行了,最终得到:

复制代码

find_package(catkin REQUIRED COMPONENTS  
  roscpp  
  rospy  
  std_msgs  
  message_generation  
  tf  
  nav_msgs  
)  

复制代码

最后还要为了使得你的C++程序能够运行,在CMakeLists.txt中最后或者相应位置,还要添加上如下指令:

add_executable(publish_odom src/publish_odom.cpp)  
target_link_libraries(publish_odom ${catkin_LIBRARIES})  
add_dependencies(publish_odom beginner_tutorials_generate_messages_cpp)   

完成这些以后,编译一下你的catkin_ws工作空间,在新终端中输入如下指令:

cd ~/catkin_ws  
catkin_make  

现在,有了这两个节点程序,dsp到move_base和move_base到dsp这条路通了,只要建立地图,发布坐标转换就可以用了。在下一篇文章中,我们将介绍几个与导航有关的 tf 坐标转换,再在一个空白地图上使用move_base进行导航。

       最后,关于这种左右轮速度转化为Odom的程序,ros论坛里有,如这个链接。ros自己写好的教程里也有如arbotix_driver 这个节点程序里有一句,你可以在你的文件系统里搜索arbotix_driver

from arbotix_python.diff_controller import DiffController  

你在文件系统里搜索diff_controller这个文件,打开它就可看到相应的转换程序,楼主和他们的其实相差无几。

最后

以上就是幸福导师为你收集整理的move_base 对机器人的控制的全部内容,希望文章能够帮你解决move_base 对机器人的控制所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部