工业机器人是专门设计和制造用于执行各种工业任务的机器人系统,这些机器人通常被用于自动化制造过程,以提高生产效率、降低成本,并执行危险或重复性高的任务。随着技术的不断进步,工业机器人的能力和应用范围还将继续扩大。在本节的内容中,将介绍基于ROS实现一个工业机器人运动控制和轨迹规划系统。
实例4-1:基于ROS的工业机器人的运动控制和轨迹规划系统(源码路径:codes\4\gui\ ROS_Motion_Control)
4.9.1 系统介绍
本项目基于ROS实现了一个工业机器人运动控制和轨迹规划系统,通过使用ROS、Gazebo和RViz等开发工具,借助Python程序对ABB、Universal Robots和Fanuc等多个工业机器人进行运动规划。本项目分别实现了机械设计(使用SolidWorks和Autodesk Inventor)、ROS中的机器人轨迹路径规划(使用Python)、RViz中的机器人轨迹可视化功能。通过提供简单的演示,展示了对多个工业机器人的运动控制、关节和笛卡尔运动、ROS参数、话题、服务等基本概念的应用。
4.9.2 配置文件
文件config/robot.yaml用于初始化项目中的一些关键参数。首先,它包含了用于在RVIZ仿真工具中初始化对象位置的参数,包括对象的初始坐标和是否可见。其次,它定义了不同机器人臂的初始家庭参数,其中包括UR5、ABB IRB 1200和FANUC CR7IA机器人臂的关节初始角度。这些参数在项目启动时用于设置机器人和环境的初始状态。
# 初始化对象的参数(RVIZ中)
object_pos: [0.0, 0.0, 0.0] # 对象的初始坐标
object_visible: False # 对象是否可见
# 初始化机器人臂的参数
# UR5: [1.57, -1.57, 1.57, -1.57, -1.57, 0.0]
# ABB IRB 1200: [0.0, 0.0, 0.0, 0.0, 1.57, 0.0]
# FANUC CR7IA [0.0, 0.0, 0.0, 0.0, -1.57, 0.0]
robot_home_param: [0.0, 0.0, 0.0, 0.0, -1.57, 0.0] # 机器人臂的关节初始角度
4.9.3 数据采集
在“data_collection”目录中包含了两个程序文件,分别是 read_joint_pose.py 和 read_tcp_pose.py。这两个文件共同构成了数据采集(data_collection)模块,负责实时获取机器人的关节姿态和工具坐标系姿态,并通过ROS话题发布,以便其他模块或用户实时监测机器人状态。
(1)文件src/data_collection/read_joint_pose.py是一个ROS节点,通过库MoveIt与机器人的关节进行交互,实时读取当前关节姿态,并使用ROS发布者发布到话题 'current_joint_pose'。脚本通过异常处理确保稳定运行,发布频率为1 Hz。这适用于需要实时监测机器人关节状态的场景。
# 系统(默认库)
import sys
# ROS的Python客户端库
import rospy
# MoveIt库提供的功能包装器
import moveit_commander
# 数据类型(消息、服务)
from rospy.numpy_msg import numpy_msg
from rospy_tutorials.msg import Floats
# Numpy(数组计算库)
import numpy as np
def main():
# 节点初始化
rospy.init_node('read_joint_init', anonymous=True)
# 创建MoveGroupCommander对象
group = moveit_commander.MoveGroupCommander('manipulator')
# 创建ROS发布者
publisher = rospy.Publisher('current_joint_pose', numpy_msg(Floats), queue_size=5)
try:
while not rospy.is_shutdown():
# 获取当前关节值
c_jP = group.get_current_joint_values()
# 转换为NumPy数组
fConv_c_jP = np.array([c_jP[0], c_jP[1], c_jP[2], c_jP[3], c_jP[4], c_jP[5]], dtype=np.float32)
# 发布到ROS话题
publisher.publish(fConv_c_jP)
# rospy频率休眠 -> 1 Hz
rospy.Rate(1).sleep()
except:
print('意外错误:', sys.exc_info()[0])
finally:
print('再见.')
if __name__ == '__main__':
sys.exit(main())
对上述代码的具体说明如下所示:
- 首先进行了ROS节点的初始化,并创建了MoveIt库的MoveGroupCommander对象,用于与机器人的关节进行交互。接着,它创建了一个ROS发布者,负责发布当前机器人关节姿态到名为'current_joint_pose'的ROS话题。
- 在主循环中,通过group.get_current_joint_values()获取当前机器人的关节值,并将其转换为NumPy数组。然后,使用ROS发布者将这个数组发布到指定话题。最后,通过rospy.Rate(1).sleep()控制发布频率为1 Hz。
- 最后通过异常处理功能捕获任何异常并打印错误信息,在代码的最后,无论是否发生异常,都会打印“Bye.”。
总体而言,该脚本用于实时读取机器人关节姿态并通过ROS话题发布,适用于需要实时监测机器人关节状态的应用场景。
(2)文件src/data_collection/read_tcp_pose.py是一个ROS节点,用于读取机器人当前的工具坐标系(TCP - Tool Center Point)姿态,并将其发布到ROS话题 'current_tcp_pose'。
# 系统(默认库)
import sys
# ROS的Python客户端库
import rospy
# MoveIt库提供的功能包装器
import moveit_commander
# 数据类型(消息、服务)
import geometry_msgs.msg
def main():
# 节点初始化
rospy.init_node('read_tcp_init', anonymous=True)
# 创建MoveGroupCommander对象
group = moveit_commander.MoveGroupCommander('manipulator')
# 创建ROS发布者
publisher = rospy.Publisher('current_tcp_pose', geometry_msgs.msg.PoseStamped, queue_size=5)
try:
while not rospy.is_shutdown():
# 获取当前工具坐标系(TCP)的姿态
c_tcpP = group.get_current_pose(group.get_end_effector_link())
# 发布到ROS话题
publisher.publish(c_tcpP)
# rospy频率休眠 -> 1 Hz
rospy.Rate(1).sleep()
except:
print('意外错误:', sys.exc_info()[0])
finally:
print('再见.')
if __name__ == '__main__':
sys.exit(main())
4.9.4 ROS 服务
在“service”目录中包含两个 Python程序,分别是 reset_robot.py 和 set_object.py。这两个文件提供了 ROS 服务,用于重置机器人的关节位置,并在 MoveIt 规划场景中动态设置或移除一个球体对象。
(1)文件src/service/reset_robot.py定义了一个 ROS 服务,用于重置机器人的位置(关节空间)。通过调用该服务可以将机器人的关节空间重置到预定义的初始位置,用于调试和初始化机器人状态。
# 系统(默认库)
import sys
# ROS的Python客户端库
import rospy
# MoveIt库提供的功能包装器
import moveit_commander
# 数据类型(消息、服务)
from std_srvs.srv import Trigger
# Numpy(数组计算库)
import numpy as np
class reset_robot_handler():
"""
描述:
该类定义了一个用于重置机器人位置(关节空间)的ROS服务。
"""
def __init__(self):
# 节点初始化
rospy.init_node('reset_init')
self.robotics_arm_name = 'manipulator'
self.robot = moveit_commander.RobotCommander()
self.group = None
# 等待MoveGroupCommander对象初始化
while self.group == None:
try:
self.group = moveit_commander.MoveGroupCommander(self.robotics_arm_name)
except Exception:
rospy.sleep(1)
# 触发器 -> 重置机器人位置(关节)
self.set_trigger = rospy.Service('reset_robot', Trigger, self.reset_robot_pose)
def reset_robot_pose(self, request):
# 从robot.yaml文件中获取机器人的初始关节角度参数
joint_target = rospy.get_param('/robot_home_param')
# 设置规划参数
self.group.set_max_velocity_scaling_factor(0.25)
self.group.set_max_acceleration_scaling_factor(0.25)
# 设置机器人参数(关节控制)
self.group.set_joint_value_target(joint_target)
# 获取机器人关节空间的轨迹规划
plan = self.group.plan(joint_target)
# 执行轨迹
self.group.execute(plan, wait=True)
rospy.sleep(0.5)
# 重置
self.group.stop()
self.group.clear_path_constraints()
self.group.clear_pose_targets()
return [True, '机器人位置已成功重置。']
def main():
rospy.wait_for_service('/move_group/get_loggers')
reset_robot_handler()
rospy.spin()
if __name__ == '__main__':
sys.exit(main())
上述代码的实现流程如下所示:
- 首先初始化 ROS 节点,并在初始化时尝试创建 MoveGroupCommander 对象,与机器人的指定运动组进行交互。然后,定义了一个名为 reset_robot 的 ROS 服务,用于重置机器人的关节姿态。
- 在 reset_robot_pose 方法中,通过读取参数文件中的机器人初始关节角度,设置运动规划的速度和加速度参数,然后规划并执行关节空间中的目标姿态。最后,清除路径约束和姿态目标。
- 通过 main 函数等待 MoveIt 的相关服务初始化,然后创建 reset_robot_handler 对象,开始监听 ROS 服务请求。
(2)文件src/service/set_object.py是一个 ROS 节点,用于在 MoveIt 环境中设置或移除一个球体对象,通过检测 ROS 参数 /object_visible 来控制对象的显示和移除功能。
import sys
# ROS的Python客户端库
import rospy
# MoveIt库提供的功能包装器
import moveit_commander
# 数据类型(消息、服务)
import geometry_msgs
def main():
# 节点初始化
rospy.init_node('set_object_init', anonymous=True)
# 创建MoveGroupCommander和PlanningSceneInterface对象
group = moveit_commander.MoveGroupCommander('manipulator')
scene = moveit_commander.PlanningSceneInterface()
robot = moveit_commander.RobotCommander()
try:
while not rospy.is_shutdown():
# 获取ROS参数 '/object_visible'
visibility = rospy.get_param('/object_visible')
if visibility == True:
# 获取主脚本中的参数(见 test.py)
position = rospy.get_param('/object_pos')
# 设置对象的参数(RVIZ)
obj = geometry_msgs.msg.PoseStamped()
obj.header.frame_id = robot.get_planning_frame()
obj.pose.position.x = position[0]
obj.pose.position.y = position[1]
obj.pose.position.z = position[2] - 0.3
# 在环境中显示对象
scene.add_sphere('obj_1', obj, 0.05)
else:
# 移除环境中的所有对象
scene.remove_world_object()
# rospy频率休眠 -> 10 Hz
rospy.Rate(10).sleep()
except:
print('Unexpected error:', sys.exc_info()[0])
finally:
print('Bye.')
if __name__ == '__main__':
sys.exit(main())
上述代码用于在 MoveIt 环境中动态设置或移除一个球体对象,通过 ROS 参数控制对象的可见性,适用于需要在机器人规划场景中添加或移除物体的应用场景。上述代码的实现流程如下所示。
- 首先初始化 ROS 节点,并创建 MoveGroupCommander 和 PlanningSceneInterface 对象,分别用于与机器人的运动组进行交互和管理场景规划。
- 在主循环中,通过读取 ROS 参数 /object_visible 判断是否显示对象。如果 visibility 为 True,则获取参数 /object_pos 来确定对象的位置,并创建一个球体对象。这个球体对象通过 PlanningSceneInterface 加入到 MoveIt 的规划场景中。如果 visibility 为 False,则移除场景中的所有物体。
- 最后,通过 rospy.Rate(10).sleep() 控制主循环的执行频率为 10 Hz。