ROS中用Twist消息控制機器人

ROS中用Twist消息控制機器人

INSTALLING THE ROS-BY-EXAMPLE CODE是書中第五章的內容,如果我們按照上一篇教程執行過了,就可以直接進入第五章,安裝一個叫rbx1的包。這個包裏面包括了本書中用到的所有例子的源碼,包括路徑規劃,視覺,語音識別等功能。這本書基本就圍繞這個包來學習ROS的使用方法。

  • 基本包的功能介紹
  • 從終端發佈Twist消息控制機器人
  • 從節點發布Twist消息控制機器人
  • 下一步

1.基本包的功能介紹

ROS Base Controller是ROS中的基本控制節點,其中包含基本PID算法來控制電機運動。它主要任務是監聽終端中或其他節點發出的以/cmd_vel爲topic的控制指令(Topic是ROS中的一個基本概念,不同的節點之間通過發佈和訂閱相同Topic的消息來通信),然後發佈/odom topicodometry 消息(里程,指直接獲得的機器人走過的距離,通常由編碼器數據計算得到或結合慣導經EKF得到),同時發佈/odom座標系和機體座標系之間的轉換(如果odom數據由EKF得到的話,這個工作由 robot_pose_ekf 節點完成).

move_base pacakge 可以讓機器人移動至我們指定的目標地點,其中包含避障,路徑規劃等功能。

gmapping package :SLAM,用激光雷達或Kinect構建實時地圖

amcl package : 機器人利用SLAM或odometry數據實時定位

下面是整個流程圖:

這裏寫圖片描述

2.從終端發佈Twist消息控制機器人

其實這個Twist消息我們上一次已經用過了,它的Topic是/cmd_vel,base controler訂閱Twist消息來控制電機。
在終端中執行以下指令查看Twist消息的具體內容:

rosmsg show geometry_msgs/Twist

一切正常的話,終端會輸出以下信息。
這裏寫圖片描述

其中有linear和angular兩個子消息,可以唯一確定機器人的運動狀態。

首先roscore,然後啓動機器人和仿真器:

roslaunch rbx1_bringup fake_turtlebot.launch
rosrun rviz rviz -d `rospack find rbx1_nav`/sim.rviz

打開新的終端,執行以下語句:

rostopic pub -r 10 /cmd_vel geometry_msgs/Twist '{linear: {x: 0.1, y: 0, z: 0}, angular: {x: 0, y: 0, z: -0.5}}'

現在詳細解讀一下這條指令,

“-r 10” 表示以10HZ的頻率發佈這條消息,

“/cmd_vel”爲消息的Topic,”geometry_msgs/Twist” 爲消息類型,

‘{linear: {x: 0.1, y: 0, z: 0}, angular: {x: 0, y: 0, z: -0.5}}’表示指定的線速度和角速度。

運行效果如下:

這裏寫圖片描述

然後我們讓讓機器人停下來,先Ctrl+C終止進程,再輸入以下指令:

rostopic pub -1 /cmd_vel geometry_msgs/Twist '{}'

點擊Rviz左下角的Reset,清除方向箭頭。再執行以下指令:

rostopic pub -1 /cmd_vel geometry_msgs/Twist '{linear: {x: 0.2, y: 0, z: 0}, angular: {x: 0, y: 0, z: 0}}'; rostopic pub -r 10 /cmd_vel geometry_msgs/Twist '{linear: {x: 0.2, y: 0, z: 0}, angular: {x: 0, y: 0, z: 0.5}}'

運行效果如下:

這裏寫圖片描述

pub -1表示僅發佈一次消息,機器人現已0.2m/s直線運行,大概3s之後,開始做圓周運動。

3.從節點發布Twist消息控制機器人

以上演示瞭如何從終端發佈指令控制機器人,但是大多數情況下是在程序中控制的。現在我們來看一下怎麼通過節點發布Twist消息控制機器人,這裏的demo都是用Python寫的,簡潔易懂。

還是先啓動機器人和仿真器:

roslaunch rbx1_bringup fake_turtlebot.launch
rosrun rviz rviz -d `rospack find rbx1_nav`/sim.rviz

然後啓動控制節點:

rosrun rbx1_nav timed_out_and_back.py

這個 timed_out_and_back.py 程序在 rbx1/rbx1_nav/nodes 目錄下,功能是先讓機器人沿直線前進特定的距離,再旋轉180度,再前進相同的距離返回出發點。
運行效果如下:

這裏寫圖片描述

現在我們看一下源代碼分析一下具體怎麼實現:

#!/usr/bin/env python  

import rospy
#導入最主要的Python for ROS庫
from geometry_msgs.msg import Twist
from math import pi
#導入geometry_msgs包中的Twist消息類型
class OutAndBack():
    def __init__(self):
        # 節點名稱
        rospy.init_node('out_and_back', anonymous=False)
        # 當終端按下Ctrl+C之後可以終止節點      
        rospy.on_shutdown(self.shutdown) 
        # 定義在/cmd_vel Topic中發佈Twist消息,控制機器人速度
        self.cmd_vel = rospy.Publisher('/cmd_vel', Twist, queue_size=1) 
        rate = 50 
        # 設置更新頻率爲50HZ
        r = rospy.Rate(rate) 
        # 線速度
        linear_speed = 0.2 
        # 目標距離
        goal_distance = 1.0
        # 到達目標的時間
        linear_duration = goal_distance / linear_speed
        # 角速度 1.0rad/s
        angular_speed = 1.0 
        # 轉角爲Pi(180 degrees)
        goal_angle = pi
        # How long should it take to rotate?
        angular_duration = goal_angle / angular_speed

        # Loop through the two legs of the trip  
        for i in range(2):
            # Initialize the movement command
            move_cmd = Twist()

            # Set the forward speed
            move_cmd.linear.x = linear_speed
            # 機器人向前運動,延時一定時間
            ticks = int(linear_duration * rate)
            for t in range(ticks):
                self.cmd_vel.publish(move_cmd)
                r.sleep()

            # 發送一個空的Twist消息是機器人停止
            move_cmd = Twist()
            self.cmd_vel.publish(move_cmd)
            rospy.sleep(1)

            move_cmd.angular.z = angular_speed
            # 機器人開始旋轉,延時一定時間使機器人轉180度
            ticks = int(goal_angle * rate)
            for t in range(ticks):
                self.cmd_vel.publish(move_cmd)
                r.sleep()

            # 停下來
            move_cmd = Twist()
            self.cmd_vel.publish(move_cmd)
            rospy.sleep(1)

        # 循環兩次之後停止
        self.cmd_vel.publish(Twist())

        # 定義 shutdown(self)可以手動停止機器人
    def shutdown(self):
        # Always stop the robot when shutting down the node.
        rospy.loginfo("Stopping the robot...")
        self.cmd_vel.publish(Twist())
        rospy.sleep(1)

if __name__ == '__main__':
    try:
        OutAndBack()
    except:
        rospy.loginfo("Out-and-Back node terminated.")

4.下一步

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章