意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

02---控制移动底座5(为什么要进行爬移控制)

来源:恒创科技 编辑:恒创科技编辑部
2024-02-02 16:26:59

在大多数时间都是依靠ROS节点来发布恰当的Twist消息。举个简单的例子,假设我们想编程使机器人向前移动1m,旋转180度,然后返回开始的位置。我们会尝试用不同的方法来完成这个任务,这些方法很好地表现了ROS不同层次的运动控制

1、通过定时和定速估计距离和角度

我们第一个尝试是用定时的Twist命令去让机器人花一定时间向前移动一定的距离,旋转180度后,然后以相同的速度进行相同时长的向前移动,不出意外的话它会回到开始的位置。最后我们会让机器人旋转180度回到最初的方向。


02---控制移动底座5(为什么要进行爬移控制)

这段脚本可以在子目录rbx1_nav/nodes下的timed_out_and_back.py中找到。

02---控制移动底座5_xml文件

2、在ArbotiX模拟器上进行计时前进并返回运动

为了保证模拟的TurtleBot回到开始的位置,按下“Ctrl-C”让模拟的TurtleBot中正在运行的启动文件停止运行,然后用以下命令让它重新运行:

roslaunch rbx1_bringup fake_turtlebot.launch

如果你愿意的话,可以用对应Pi Robot或者你自己的机器人的文件替换掉fake_turtlebot.launch,这不会使结果有差别。

如果RViz并不是正在运行,那么就让它开始运行:

rosrun rviz rviz -d `rospack find

或者按下Reset按钮删除掉在上一部分留下的Odometry箭头。

最后运行timed_out_and_back.py节点:

rosrun rbx1_nav timed_out_and_back.py

02---控制移动底座5_xml文件_02

3、计时前进并返回运动的脚本

以下是计时前进并返回节点的完整脚本。

02---控制移动底座5_python_03

02---控制移动底座5_python_04

#!/usr/bin/env python

import rospy
from geometry_msgs.msg import Twist
from math import pi

class OutAndBack():
def __init__(self):
# Give the node a name
rospy.init_node('out_and_back', anonymous=False)

# Set rospy to execute a shutdown function when exiting
rospy.on_shutdown(self.shutdown)

# Publisher to control the robot's speed
self.cmd_vel = rospy.Publisher('/cmd_vel', Twist, queue_size=1)

# How fast will we update the robot's movement?
rate = 50

# Set the equivalent ROS rate variable
r = rospy.Rate(rate)

# Set the forward linear speed to 0.2 meters per second
linear_speed = 0.2

# Set the travel distance to 1.0 meters
goal_distance = 1.0

# How long should it take us to get there?
linear_duration = goal_distance / linear_speed

# Set the rotation speed to 1.0 radians per second
angular_speed = 1.0

# Set the rotation angle to Pi radians (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

# Move forward for a time to go the desired distance
ticks = int(linear_duration * rate)

for t in range(ticks):
self.cmd_vel.publish(move_cmd)
r.sleep()

# Stop the robot before the rotation
move_cmd = Twist()
self.cmd_vel.publish(move_cmd)
rospy.sleep(1)

# Now rotate left roughly 180 degrees

# Set the angular speed
move_cmd.angular.z = angular_speed

# Rotate for a time to go 180 degrees
ticks = int(goal_angle * rate)

for t in range(ticks):
self.cmd_vel.publish(move_cmd)
r.sleep()

# Stop the robot before the next leg
move_cmd = Twist()
self.cmd_vel.publish(move_cmd)
rospy.sleep(1)

# Stop the robot
self.cmd_vel.publish(Twist())

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.")

View Code

#!/usr/bin/env python

import rospy

如果阅读了ROS Beginner Tutorials in Python,你会知道所有ROS节点都是以这两句开头。第一行确保了这个脚本会被看作Python程序脚本,而第二行引用ROS的核心Python库。

from geometry_msgs.msg import Twist

from math import pi

这里我们引用了其他一些我们在脚本中需要用到的组件,在当前的例子中,我们需要用到ROS的geometry_msgs包中的Twist消息类型,和Python的math模块中的常数pi。请注意一个常见的引用错误,即忘记在你的包中的package.xml文件中写上必要的ROS<run_depend>。在当前的例子中,我们的package.xml文件必须要有这行才能正确从geometry_msgs.msg中引用Twist:

<run_depend>geometry_msgs</run_depend>

class OutAndBack():

  def __init__(self):

这里ROS节点主要部分的开头把它自己定义成了一个Python类,并加上一行标准的类初始化

#Give the node a name

rospy.init_node('out_and_back',anonymous=False)

#set rospy to execute a shutdown function when exiting

rospy.on_shutdown(self.shutdown)

每个ROS节点都被要求调用rospy.init_node(),我们也可以设置一个回调函数on_shutdown(),这样我们就可以在脚本结束的时候,比如用户按下ctrl-C的时候,进行必要的清理操作。对于一个移动机器人,最重要的清理操作就是让机器人停下来。我们可以在后面的脚本中看如何做到这点

#Publisher to control the robot's speed
self.cmd_vel = rospy.Publisher('/cmd_vel',Twist)
#How fast will we update the robot's movement?
rate=50
#set the equivalent ROS rate variable

这里定义了我们用来发布Twist命令给/cmd_vel话题的ROS发布者。还设定了以每秒50次的频率来更新机器人的运动

#Set the forward linear speed to 0.2 meters per second
linear_speed=0.2
#Set the travel distance to 1.0 meters
goal_distance=1.0
#How long should it take us to get there?

以相对安全的0.2米/秒的速度初始化前进速度,并把目标距离设定为1.0米,接着计算运动需要多长时间。

# Set the rotation speed to 1.0 radians per second
angular_speed=1.0
#Ser the rotation angle to Pi radians(180 degrees)
goal_angle=pi
#How long should it take to rotate?

设定旋转速度为1.0弧度/秒,目标角度为180度或Pi弧度。

#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
#Move forward for a time to go the desired distance
ticks=int(linear_duration *rate)
for t in range(ticks)
self.cmd_vel.publish(move_cmd)
r.sleep()

正是这里的循环使机器人运动起来,每循环一次就运动一段。因为一些机器人要求不断发布Twist消息来使它持续运动,所以为了让机器人以linear_speed米/秒的速度向前移动linear_distance米,我们需要在恰当的时长内每1/rate秒发布一次move_cmd消息。语句r.sleep()是rospy.sleep(1/rate)的简写。因为我们把变量赋值为r=rospy.Rate(rate)。

#Now rotate left roughly 180 degrees
#Set the angular speed
move_cmd.angular.z=angular_speed
#Rotate for a time to go 180 degrees
ticks=int(goal_angle *rate)
for t in range(ticks)
self.cmd_vel.publish(move_cmd)
r.sleep()

在循环的第二部分,我们让机器人在恰当时间段内以angular_speed弧度/秒的速度旋转,最终一共旋转180度。

#Stop the robot

当机器人完成整个计时前进并返回的过程后,我们发布一条空的Twist消息(所有项都设为0)让它停止运动

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)

这个是我们的停机回调函数,如果脚本因为任何原因停止运行,我们就会通过发布一条空的Twist消息去停止机器人

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

最后这段是运行一段Python脚本的标准程序块。我们实例化OutAndBack类来使脚本(和机器人)运行。

上一篇: 第四章输入/输出(I/O)4.2PCL中I/O模块及类介绍(out是输出还是输入) 下一篇: 手机怎么远程登录云服务器?