尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Python+ROS+MoveIt!驱动UR5机械臂与AG95夹爪实现精准抓取

Python+ROS+MoveIt!驱动UR5机械臂与AG95夹爪实现精准抓取 简介本资源是一套基于Python、ROS与MoveIt框架实现UR5机械臂协同AG95夹爪完成给定位姿抓取任务的完整工程实践方案面向计算机、自动化、人工智能及机器人相关专业的学生、教师与初/中级开发者适用于课程设计、毕业设计、实验教学与ROS机械臂入门进阶学习。压缩包共34个文件含4个核心launch启动脚本如go_grasp.launch、check_and_grasp.launch、2个关键Python控制脚本go_grasp.py与dh_hand_client.py、3个TF坐标系配置文件、19张过程截图涵盖RVIZ仿真界面、坐标系示意图、抓取状态对比等以及README.md、环境配置.env、配置yaml等支撑文件整体大小为9.33MB。已有348人学习下载项目源自高分98分本科毕设所有代码均经实机/仿真双重调试验证附带详细开发文档与项目解析清晰呈现从MoveIt运动规划、夹爪通信控制到位姿解析执行的全流程逻辑目录结构模块分明便于理解与二次开发。1. 项目概述从零到一构建一个实用的机械臂抓取系统最近在整理过去的项目资料翻到了一个挺有意思的实战案例用Python脚本结合ROS机器人操作系统和MoveIt运动规划框架驱动一台UR5协作机械臂和AG95电动夹爪去完成一个指定姿态的抓取任务。这个项目听起来有点复杂但拆解开来其实就是把机器人学里几个核心的模块——运动学、路径规划、执行控制——给串起来了。对于想从仿真迈入实体机器人操作或者想理解工业级机器人应用开发流程的朋友来说这个案例是个非常好的切入点。它不只是一个简单的“Hello World”而是涵盖了从环境配置、模型配置、运动规划到末端执行器控制的完整链路。无论你是机器人专业的学生还是有一定编程基础想转行机器人开发的工程师跟着这个流程走一遍都能对“如何让机械臂动起来并完成一个具体任务”有非常扎实的理解。我们用的UR5和AG95在教育和工业原型开发中非常常见所以这套代码和思路的复用性很高。2. 核心思路与方案选型为什么是PythonROSMoveIt在开始敲代码之前我们先聊聊为什么选这个技术栈。这决定了我们项目的“地基”是否稳固。2.1 为什么选择ROS作为中间件ROS不是一个真正的操作系统而是一个运行在Linux之上的分布式通信框架。它的核心价值在于提供了标准的通信机制话题、服务、动作、丰富的工具集Rviz可视化、Gazebo仿真和庞大的开源生态。对于UR5和AG95优傲机器人Universal Robots和艾利特机器人AUBOAG95制造商都提供了官方的ROS驱动包。这意味着我们不需要从零开始写底层通信代码直接使用这些驱动包就能通过ROS话题或服务来发送关节目标位置、速度指令或者读取机械臂的状态。ROS就像一个“软件总线”把机械臂、夹爪、传感器如果有和我们的决策程序连接在一起让模块间的数据交换变得标准化和简单。2.2 为什么MoveIt是运动规划的不二之选MoveIt是ROS生态中功能最强大、最流行的机器人运动规划框架。它封装了运动学求解KDL、TRAC-IK等、碰撞检测FCL、Bullet、路径规划OMPL算法库等复杂功能。我们的核心任务“给定位姿的抓取”可以分解为运动学求解给定末端执行器夹爪的目标位置和姿态合称“位姿”MoveIt能帮我们计算出机械臂各个关节需要转动的角度逆运动学。路径规划从当前姿态运动到目标姿态中间不能撞到自己或环境。MoveIt会利用OMPL中的规划算法如RRT、RRTConnect在关节空间或笛卡尔空间搜索出一条无碰撞、平滑的路径。轨迹执行将规划好的路径一系列时间点上的关节位置、速度、加速度通过ROS话题发送给机械臂的控制器驱动驱动机器人平滑运动。如果没有MoveIt上述每一步都需要我们自己实现工作量巨大且容易出错。MoveIt提供了一个高层级的Python接口moveit_commander让我们可以用几十行代码就完成复杂的规划任务。2.3 Python胶水语言与快速原型利器C是ROS和MoveIt的底层语言性能最优。但对于上层任务逻辑、算法验证和快速开发Python以其简洁的语法、丰富的科学计算库如NumPy和强大的脚本能力成为更优选择。MoveIt提供了完善的Python API使得我们能够以非常直观的方式设置规划场景、指定目标、执行规划。我们的“源码”主体就是一个或多个Python脚本它扮演着“大脑”的角色获取目标位姿、调用MoveIt进行规划、发送轨迹、控制夹爪开合。2.4 UR5与AG95经典组合的优势UR5是6自由度协作机械臂灵活性足以完成大多数抓取、放置、装配任务。AG95是一款二指电动夹爪支持位置和力控制通讯接口丰富通常支持Modbus TCP/IP或ROS话题。选择它们是因为生态成熟ROS驱动和MoveIt配置包非常完善。仿真支持好在Gazebo中能获得高保真的动力学仿真模型便于前期算法测试降低实体操作风险。文档丰富社区和官方提供了大量案例和排错指南。方案总结我们的架构是“Python脚本决策层 - MoveItROS接口规划层 - UR/AG95 ROS驱动控制层 - 实体硬件”。这个分层架构清晰职责分离便于调试和功能扩展。3. 环境搭建与依赖配置一步一坑的避雷指南理论说完了我们进入实战。第一步就是把环境搭起来。这里以Ubuntu 20.04 ROS Noetic为例这是UR官方驱动较稳定的组合。Ubuntu 22.04 ROS2 Humble也是趋势但部分包的兼容性可能需要额外处理。3.1 ROS Noetic 与基础工作空间创建首先按照ROS官网或“鱼香ROS”提供的一键安装脚本安装ROS Noetic完整版。安装后创建我们的项目工作空间mkdir -p ~/ur5_ag95_ws/src cd ~/ur5_ag95_ws/src catkin_init_workspace cd .. catkin_make source devel/setup.bash记得把最后一行source命令加入你的~/.bashrc文件这样每次打开终端都会自动配置好这个工作空间的环境。3.2 安装UR机械臂与MoveIt相关功能包UR的ROS驱动和MoveIt配置包已经集成在universal_robot元功能包中。我们通过git克隆到src目录下cd ~/ur5_ag95_ws/src git clone -b melodic-devel https://github.com/ros-industrial/universal_robot.git注意这里用的是melodic-devel分支它对Noetic的兼容性最好。克隆后需要安装一些依赖cd ~/ur5_ag95_ws rosdep update rosdep install --from-paths src --ignore-src -yrosdep是ROS的依赖管理工具它会自动检查并安装universal_robot包所需的所有系统依赖。3.3 配置AG95夹爪的ROS驱动AG95的ROS驱动可能需要从制造商处获取或者使用社区维护的版本。假设我们有一个名为ag95_driver的包。将其放入src目录。关键是要确保这个驱动包能提供一个ROS话题例如/ag95/gripper_command来控制夹爪开合并可能提供另一个话题如/ag95/gripper_status来反馈夹爪状态。通常控制消息可能是一个简单的std_msgs/Float64表示开合宽度或自定义的GripperCommand消息。3.4 安装并配置MoveIt对于UR5universal_robot包里已经包含了MoveIt配置文件。但为了更灵活地集成夹爪我们通常使用MoveIt Setup Assistant来生成我们自己的配置包。启动MoveIt Setup Assistantroslaunch moveit_setup_assistant setup_assistant.launch加载URDF模型你需要一个包含UR5机械臂和AG95夹爪的统一机器人描述文件URDF。这个文件描述了机器人所有连杆、关节、外观以及碰撞几何。你可以手动编写或者将UR5的URDF和AG95的URDF通常由供应商提供合并。在Setup Assistant中加载这个URDF文件。配置自碰撞矩阵让MoveIt知道哪些连杆之间不需要做碰撞检测比如相邻连杆以加快规划速度。定义虚拟关节如果机器人是固定在世界基座上的可以跳过或定义一个连接世界world和机器人基座base_link的固定虚拟关节。定义规划组这是关键一步。我们需要定义两个规划组manipulator包含UR5从基座base_link到末端法兰tool0的所有关节。这个组用于手臂的运动规划。gripper包含AG95夹爪的一个或两个关节模拟手指开合。这个组用于控制夹爪。还需要定义一个endeffector将夹爪的基座连杆例如gripper_base_link指定为manipulator规划组的末端效应器End-Effector。这样MoveIt就知道“手”在哪里了。定义位姿可以预设一些常用位姿比如“home”初始位置、“ready”准备位置。生成配置包指定输出包名例如ur5_ag95_moveit_config然后生成。这个包包含了MoveIt运行所需的所有配置文件。注意合并URDF和配置MoveIt是前期最繁琐但也最重要的步骤。一个错误的关节父子关系或坐标系定义会导致后续规划完全失败。务必使用Rviz的RobotModel显示插件仔细检查生成的模型确保机械臂和夹爪的联动关系正确。3.5 安装必要的Python库除了ROS包我们的Python脚本可能需要pip install numpy rospkg tf transformationstransformations库在处理四元数、欧拉角等姿态表示时非常方便。4. 核心代码解析让机械臂“思考”与“执行”环境准备好后我们来看核心的Python脚本。这个脚本主要做三件事初始化MoveIt、规划运动到目标位姿、控制夹爪。4.1 初始化MoveItCommander#!/usr/bin/env python3 import rospy import sys import moveit_commander import moveit_msgs.msg import geometry_msgs.msg from math import pi # 初始化MoveIt和ROS节点 moveit_commander.roscpp_initialize(sys.argv) rospy.init_node(ur5_ag95_pick_place_node, anonymousTrue) # 实例化RobotCommander对象提供机器人整体的信息 robot moveit_commander.RobotCommander() # 实例化PlanningSceneInterface对象用于与周围环境交互添加/移除障碍物 scene moveit_commander.PlanningSceneInterface() # 实例化MoveGroupCommander对象针对我们定义的manipulator规划组 group_name manipulator move_group moveit_commander.MoveGroupCommander(group_name) # 设置规划参数可选但很重要 move_group.set_planning_time(5.0) # 规划时间限制单位秒 move_group.set_num_planning_attempts(10) # 规划尝试次数 move_group.set_goal_position_tolerance(0.01) # 位置容差单位米 move_group.set_goal_orientation_tolerance(0.05) # 姿态容差单位弧度 move_group.set_max_velocity_scaling_factor(0.5) # 最大速度比例因子0.5表示一半速度更安全 move_group.set_max_acceleration_scaling_factor(0.5) # 最大加速度比例因子 # 打印一些基本信息用于调试 print( 参考坐标系: %s % move_group.get_planning_frame()) print( 末端执行器连杆: %s % move_group.get_end_effector_link()) print( 可用的规划组:, robot.get_group_names()) print( 当前关节状态:, move_group.get_current_joint_values()) print( 当前末端位姿:, move_group.get_current_pose().pose)4.2 规划并执行到目标位姿假设我们已知目标位姿例如通过视觉系统识别得到它是一个相对于世界坐标系通常是base_link的位置和姿态。def move_to_target_pose(target_pose_list): 将机械臂末端移动到指定的目标位姿。 target_pose_list: [position_x, position_y, position_z, orientation_x, orientation_y, orientation_z, orientation_w] # 创建目标位姿对象 pose_goal geometry_msgs.msg.Pose() pose_goal.position.x target_pose_list[0] pose_goal.position.y target_pose_list[1] pose_goal.position.z target_pose_list[2] pose_goal.orientation.x target_pose_list[3] pose_goal.orientation.y target_pose_list[4] pose_goal.orientation.z target_pose_list[5] pose_goal.orientation.w target_pose_list[6] # 设置目标位姿 move_group.set_pose_target(pose_goal) # 进行运动规划。plan方法返回一个元组(plan, success, planning_time, error_code) plan move_group.plan() success plan[1] if success: print( 规划成功开始执行...) # 执行规划出的轨迹 move_group.execute(plan[0], waitTrue) # 等待动作完成 move_group.stop() # 确保没有残留的运动指令 move_group.clear_pose_targets() # 清除当前目标 print( 运动执行完成。) return True else: print( 规划失败) move_group.clear_pose_targets() return False # 示例移动到一个预设的位姿单位米四元数 # 这是一个示例位姿实际应用中需要根据你的工作空间和物体位置调整 target_pose [0.3, 0.2, 0.4, 0.0, 0.707, 0.0, 0.707] # 位置在(0.3,0.2,0.4)姿态为绕Y轴旋转90度 move_to_target_pose(target_pose)4.3 控制AG95夹爪夹爪控制通常不通过MoveIt而是直接通过其ROS驱动提供的接口。假设驱动提供了一个名为/ag95/gripper_command的话题消息类型是std_msgs/Float64数据代表夹爪的开合宽度米。import rospy from std_msgs.msg import Float64 class GripperController: def __init__(self): # 创建发布器发布夹爪控制指令 self.gripper_pub rospy.Publisher(/ag95/gripper_command, Float64, queue_size10) # 等待话题建立连接避免第一条消息丢失 rospy.sleep(0.5) def open_gripper(self, width0.08): 打开夹爪到指定宽度默认8cm msg Float64() msg.data width self.gripper_pub.publish(msg) rospy.loginfo(f发送夹爪打开指令宽度: {width} m) rospy.sleep(1.0) # 等待夹爪动作完成时间根据实际情况调整 def close_gripper(self, width0.01): 闭合夹爪到指定宽度默认1cm模拟抓取 msg Float64() msg.data width self.gripper_pub.publish(msg) rospy.loginfo(f发送夹爪闭合指令宽度: {width} m) rospy.sleep(1.0) # 在主程序中使用 gripper GripperController() rospy.sleep(2) # 等待其他节点初始化 # 抓取序列示例 print(移动到接近位置...) # 先规划到一个物体上方的“预抓取”位置这个位置在物体正上方一定高度姿态与抓取姿态一致 pre_grasp_pose [0.3, 0.2, 0.25, 0.0, 0.707, 0.0, 0.707] if move_to_target_pose(pre_grasp_pose): gripper.open_gripper() # 打开夹爪 rospy.sleep(0.5) print(下降到抓取位置...) # 规划到实际的抓取位置Z轴更低 grasp_pose [0.3, 0.2, 0.15, 0.0, 0.707, 0.0, 0.707] # Z坐标从0.25降到0.15 if move_to_target_pose(grasp_pose): rospy.sleep(0.5) # 稳定一下 gripper.close_gripper() # 闭合夹爪抓取物体 rospy.sleep(1.0) print(提升到撤离位置...) # 抓取后先垂直提升到预抓取位置避免横向移动时碰撞 if move_to_target_pose(pre_grasp_pose): print(抓取成功) # 接下来可以规划到放置位置...4.4 整合完整的抓取任务脚本框架将以上部分整合并加入错误处理和状态判断就形成了一个基本的抓取任务脚本。核心逻辑是一个状态机移动到预抓取位 - 打开夹爪 - 移动到抓取位 - 闭合夹爪 - 抬起到安全高度 - 移动到放置位 - 打开夹爪。def main(): # ... 初始化部分见4.1 gripper GripperController() rospy.sleep(3) # 给所有节点充足的启动时间 try: # 1. 回到一个安全的初始位置例如在MoveIt!配置中定义的“home”姿态 move_group.set_named_target(home) move_group.go(waitTrue) move_group.stop() # 2. 获取目标位姿这里假设是硬编码的实际可能来自视觉、用户输入等 target_grasp_pose [...] # 你的目标抓取位姿 # 3. 计算预抓取位姿在目标点正上方0.1米处 pre_grasp_pose target_grasp_pose.copy() pre_grasp_pose[2] 0.1 # Z坐标增加0.1米 # 4. 执行抓取序列 # 移动到预抓取点 if not move_to_target_pose(pre_grasp_pose): rospy.logerr(移动到预抓取点失败) return gripper.open_gripper() # 直线下降到抓取点笛卡尔空间路径 waypoints [] # 当前位姿就是预抓取点 wpose move_group.get_current_pose().pose waypoints.append(copy.deepcopy(wpose)) wpose.position.z - 0.1 # 垂直下降0.1米 waypoints.append(copy.deepcopy(wpose)) # 计算笛卡尔路径 (plan, fraction) move_group.compute_cartesian_path( waypoints, # 路径点列表 0.01, # 路径分辨率米 0.0) # 跳跃阈值0表示禁用 if fraction 1.0: # 100%路径规划成功 rospy.loginfo(笛卡尔路径规划成功执行下降...) move_group.execute(plan, waitTrue) else: rospy.logwarn(笛卡尔路径规划不完全成功 (%.2f%%). 尝试关节空间规划。 % (fraction * 100)) # 降级方案直接用关节空间规划到抓取点 if not move_to_target_pose(target_grasp_pose): rospy.logerr(无法到达抓取点任务终止。) return rospy.sleep(0.5) gripper.close_gripper() # 抓取 rospy.sleep(1.0) # 5. 抬起到预抓取点或安全高度 move_group.set_named_target(pre_grasp) # 假设你定义了这个位姿 move_group.go(waitTrue) # 6. 移动到放置位置并释放流程类似 # ... print( 抓取放置任务完成) except rospy.ROSInterruptException: return except KeyboardInterrupt: return finally: moveit_commander.roscpp_shutdown() if __name__ __main__: main()5. 仿真与实体调试从虚拟到现实的关键步骤在把代码部署到真机上之前强烈建议在Gazebo仿真环境中进行测试。这能避免因程序错误导致的物理碰撞风险。5.1 在Gazebo中启动仿真环境通常UR和AG95的驱动包会提供Gazebo启动文件。例如对于UR5roslaunch ur_gazebo ur5.launch这个命令会启动Gazebo并加载一个UR5的仿真模型。对于AG95你可能需要修改URDF或启动文件将夹爪模型添加到UR5的末端。这可能需要手动编辑一个融合后的URDF文件并在启动时加载它。5.2 在Rviz和MoveIt中监控与规划新开一个终端启动MoveIt和Rvizroslaunch ur5_ag95_moveit_config demo.launch这个launch文件会启动MoveIt的MoveGroup节点和Rviz配置界面。在Rviz中你可以看到机器人模型。使用“Interact”工具拖拽末端效应器来设置目标。点击“Plan”来测试规划。点击“Execute”让仿真机器人运动如果同时运行了Gazebo并且demo.launch配置了与仿真控制器的连接Gazebo中的模型也会同步运动。5.3 连接实体机器人当仿真测试无误后就可以连接实体机器人了。安全第一务必确保急停按钮在可触及范围内机器人运动范围内无人。网络配置确保你的工控机/PC与UR5控制器在同一个局域网内。UR5控制器通常有一个网口。启动UR驱动使用真实的驱动launch文件而不是gazebo的。例如roslaunch ur_robot_driver ur5_bringup.launch robot_ip:192.168.1.100 # 替换为你的UR控制器IP这个launch文件会启动ur_modern_driver或ur_robot_driver通过TCP/IP与UR控制器通信。启动MoveIt同样启动ur5_ag95_moveit_config的moveit_planning_execution.launch或类似名称这个launch文件会配置MoveIt使用真实的机器人驱动接口而不是仿真的。启动夹爪驱动启动AG95夹爪的ROS驱动节点使其连接到真实的夹爪控制器可能是通过串口或以太网。运行你的Python脚本在一切就绪后运行你的抓取脚本。首次运行时建议将速度比例因子set_max_velocity_scaling_factor设置为0.1或更低以极慢的速度观察机器人的运动是否符合预期。6. 常见问题与深度排错实录在实际操作中你几乎一定会遇到下面这些问题。这里记录了我的排查思路和解决方法。6.1 MoveIt规划失败报“Unable to sample any valid states for goal tree”问题分析这是最常见的规划失败错误之一意味着规划算法无法在目标位姿附近找到有效的、无碰撞的关节构型。排查步骤检查目标位姿是否可达首先在Rviz中用“Interact”工具手动拖拽末端到目标位姿附近看看机器人模型是否扭曲到一个不合理的位置。如果手动都很难摆过去说明位姿可能接近或超出工作空间边界。检查碰撞在Rviz的MotionPlanning插件中开启“Collision Display”查看规划时哪些连杆被标记为碰撞通常显示为红色。可能是目标位姿导致机器人自身碰撞也可能是与场景中的障碍物在PlanningScene中添加的碰撞。调整规划算法和参数MoveIt默认使用RRTConnect算法。可以尝试更换算法例如RRT或RRTstar。在代码中可以通过move_group.set_planner_id(RRT)来设置。同时增加set_planning_time和set_num_planning_attempts给规划器更多时间和机会。放宽目标容差过小的位置和姿态容差会让规划变得极其困难。适当增大set_goal_position_tolerance和set_goal_orientation_tolerance。检查起始状态有时机器人当前姿态处于一个奇异点或尴尬位置导致规划困难。可以先让机器人移动到一个安全的“home”位置再从那里开始规划到目标。6.2 执行轨迹时实体机器人不动或抖动问题分析规划成功但执行失败。问题可能出在控制器接口或轨迹本身。排查步骤检查控制器话题通过rostopic list查看MoveIt发布的轨迹话题通常是/scaled_pos_joint_traj_controller/command是否有数据。再检查UR驱动订阅的话题是否正确。确保仿真和实体启动文件中的控制器配置一致。检查轨迹点时间戳实体控制器对轨迹点的时间戳非常敏感。确保MoveIt发布的轨迹消息JointTrajectory中的points.time_from_start是单调递增的。有时仿真没问题但实体控制器要求更严格。检查速度/加速度限制实体机器人的最大速度/加速度可能小于MoveIt规划时使用的默认值。确保在MoveIt配置中joint_limits.yaml正确设置了关节的速度、加速度和加加速度jerk限制。在代码中通过set_max_velocity_scaling_factor设置为一个较小的值如0.3再试。查看控制器日志UR控制器网页界面或ROS驱动节点的日志会给出更具体的错误信息如“轨迹点时间无效”、“超出关节限位”等。6.3 夹爪控制无响应问题分析夹爪驱动节点可能未启动、话题名称不匹配或消息类型错误。排查步骤rostopic list | grep gripper确认夹爪控制话题是否存在。rostopic echo /ag95/gripper_command在运行你的控制命令时查看该话题是否有消息发布出来。rostopic type /ag95/gripper_command确认消息类型是否与你的Python代码中发布的消息类型一致。检查夹爪驱动节点的启动日志看是否有连接错误如串口打不开、IP连接失败。6.4 坐标系混乱导致位姿错误问题分析这是最隐蔽的错误之一。你的目标位姿是基于哪个坐标系base_linkworld还是相机坐标系MoveIt规划组的规划坐标系get_planning_frame()是什么解决方案统一坐标系确保你的目标位姿是发布在MoveIt规划坐标系下的。通常规划坐标系是base_link或world。使用TF变换如果目标位姿来自视觉传感器如相机你需要通过TF树将位姿从相机坐标系转换到机器人基座坐标系。使用tf2_ros.TransformListener来查询变换。在Rviz中可视化将你的目标位姿以PoseStamped消息的形式发布出来在Rviz中添加一个Pose显示将其话题指向你发布的位姿。直观地看这个位姿箭头是否出现在你期望的位置。6.5 笛卡尔路径规划失败fraction 1.0问题分析compute_cartesian_path返回的fraction小于1.0表示只有部分路径可以规划通常是因为中间路径点存在碰撞或不可达。应对策略增加路径分辨率eef_step参数但会增加计算量。在下降路径中间添加更多的中间点而不是直接从A到B。如果只是抓取一个更鲁棒的方法是先规划到目标点正上方的预抓取点关节空间规划然后只做最后一段垂直向下的笛卡尔运动路径很短成功率更高。如果连垂直向下的笛卡尔路径都失败可以考虑用关节空间规划直接到抓取点虽然末端路径可能不是严格的直线但对于抓取任务有时是可接受的。这个项目从环境搭建到最终调试每一步都充满了细节。最耗时间的往往不是写代码而是解决模型配置、坐标系转换和硬件通信中的各种“小问题”。我的建议是充分利用Rviz和ROS命令行工具rostopic,rosnode,rqt_graph,tf_echo进行可视化调试耐心地隔离问题。当看到UR5机械臂平稳地运动到指定位置AG95夹爪精准地闭合抓住物体时你会觉得这一切的折腾都是值得的。这不仅仅是一段代码更是对机器人软件栈一次深刻的理解。本文还有配套的精品资源点击获取
返回列表