Moveit Noetic的运动规划组python接口

Moveit Noetic的运动规划组python接口

记录学习如何使用moveit的python API进行机械臂的控制

🚀 环境配置 🚀

  • ubuntu 20.04
  • ros noetic
  • moveit noetic
  • 法奥机械臂 frcobot_fr5

文章目录

  • Moveit Noetic的运动规划组python接口
    • 1. 设置moveit功能包
    • 2. 编写MoveItController
    • Reference

1. 设置moveit功能包

可以参考这篇文章:【Moveit2】使用moveit_setup_assistant配置自己的机械臂功能包,moveit2和moveit1功能包的配置非常相似,这里就不再赘述。

配置好moveit功能包之后,我们查看一下当前的文件目录

.
├── build
├── devel
└── src
    └── frcobot_ros
        ├── fr5_gripper_moveit_config
        ├── fr_planning
            └── scripts
        ...

其中fr5_gripper_moveit_config是我使用moveit_setup_assasitant配置的moveit功能包,而fr_planning是我用于存放控制脚本的功能包。

我们将脚本文件存放于./scripts目录下,命名为moveitServer.py,相应的配置文件要做如下修改

CMakeLists.txt

find_package(catkin REQUIRED COMPONENTS
  actionlib
  control_msgs 
  diagnostic_msgs
  geometry_msgs
  moveit_msgs
  moveit_ros_perception
  moveit_ros_planning_interface
  roscpp
  rospy
  sensor_msgs
  shape_msgs
  std_msgs
  std_srvs
  tf
  trajectory_msgs
  message_generation
)
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES fr_planning
   CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)
catkin_install_python(PROGRAMS
  scripts/moveitServer.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

packages.xml

<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>

<!-- add -->
<build_depend>message_generation</build_depend>
<build_depend>actionlib</build_depend>
<build_depend>control_msgs</build_depend>
<build_depend>diagnostic_msgs</build_depend>
<build_depend>geometry_msgs</build_depend>
<build_depend>manipulation_msgs</build_depend>
<build_depend>moveit_msgs</build_depend>
<build_depend>sensor_msgs</build_depend>
<build_depend>shape_msgs</build_depend>
<build_depend>std_srvs</build_depend>
<build_depend>tf</build_depend>
<build_depend>trajectory_msgs</build_depend>

<build_export_depend>roscpp</build_export_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>

<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>

<!-- add -->
<exec_depend>message_runtime</exec_depend>
<exec_depend>actionlib</exec_depend>
<exec_depend>control_msgs</exec_depend>
<exec_depend>diagnostic_msgs</exec_depend>
<exec_depend>geometry_msgs</exec_depend>
<exec_depend>manipulation_msgs</exec_depend>
<exec_depend>moveit_msgs</exec_depend>
<exec_depend>sensor_msgs</exec_depend>
<exec_depend>shape_msgs</exec_depend>
<exec_depend>std_srvs</exec_depend>
<exec_depend>tf</exec_depend>
<exec_depend>trajectory_msgs</exec_depend>

2. 编写MoveItController

这部分主要参考官网给出的API示例

具体就不解读了,相信能看懂

moveitServer.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 导入基本ros和moveit库
import rospy, sys
import moveit_commander
from moveit_commander import MoveGroupCommander, PlanningSceneInterface, RobotCommander
from moveit_msgs.msg import  PlanningScene, ObjectColor,CollisionObject, AttachedCollisionObject,Constraints,OrientationConstraint
from geometry_msgs.msg import PoseStamped, Pose
from tf.transformations import quaternion_from_euler
from copy import deepcopy
import numpy as np
import math
from copy import deepcopy


class MoveIt_Controller:

    def __init__(self, is_use_gripper: bool = False):
        # init ros moveit config
        moveit_commander.roscpp_initialize(sys.argv)

        # init ros node
        rospy.init_node('moveit_control_server', anonymous=False)

        # set the name of MoveItGroup
        self.arm = moveit_commander.MoveGroupCommander("arm")
        # set the tolerance of joint
        self.arm.set_goal_joint_tolerance(0.001)
        self.arm.set_goal_position_tolerance(0.001)
        self.arm.set_goal_orientation_tolerance(0.01)
        # get the link of end effector
        self.end_effector_link = self.arm.get_end_effector_link()

        # set the reference frame of MoveItGroup
        self.reference_frame = "base_link"
        self.arm.set_pose_reference_frame(self.reference_frame)

        # set the maximum of planning time and other parameters
        self.arm.set_planning_time(10)
        self.arm.allow_replanning(True)
        self.arm.set_planner_id("RRTstar")

        # set the maximum acceleration and velocity (set to 0-1)
        self.arm.set_max_acceleration_scaling_factor(1)
        self.arm.set_max_velocity_scaling_factor(1)

        # set the arm to "up" pose
        self.go_up()

        # pub scene
        # self.set_scene()    # set table
    
    #=============================== tool function ===============================
    def close(self):
        moveit_commander.roscpp_shutdown()
        moveit_commander.os._exit(0)
    
    def setColor(self, name, r, g, b, a=0.9):
        # init color object of moveit
        color = ObjectColor()
        # set color
        color.id = name
        color.color.r = r
        color.color.g = g
        color.color.b = b
        color.color.a = a
        # update the color dict
        self.colors[name] = color
    
    def sendColors(self):
        # send the color to the planning scene
        # init
        p = PlanningScene()
        # need color to be different
        p.is_diff = True
        # get the color from color dict
        for color in self.colors.values():
            p.object_colors.append(color)
        # publish the color to scene
        self.scene_pub.publish(p)
    
    def set_scene(self):
        # init scene interface
        self.scene = PlanningSceneInterface()
        # init scene publisher
        self.scene_pub = rospy.Publisher('planning_scene', PlanningScene, queue_size=5)
        self.colors: dict = {}
        rospy.sleep(1)

        # set a table under the arm
        table_id = "table"
        self.scene.remove_world_object(table_id)
        rospy.sleep(1)
        table_size = [2, 2, 0.01]
        # set the pose of the obj
        table_pose = PoseStamped()
        # set the frame of the obj
        table_pose.header.frame_id = self.reference_frame
        table_pose.pose.position.x = 0.0
        table_pose.pose.position.y = 0.0
        table_pose.pose.position.z = -table_size[2]/2 - 0.02
        # w=1表明物体的姿态没有任何旋转,它与世界坐标系对齐。
        table_pose.pose.orientation.w = 1.0
        self.scene.add_box(table_id, table_pose, table_size)
        self.setColor(table_id, 0, 1, 0, 1.0)
        self.sendColors()


    #=============================== move function ===============================
    def go_up(self, a=1, v=1):
        self.arm.set_max_acceleration_scaling_factor(a)
        self.arm.set_max_velocity_scaling_factor(v)
        # "up" is the custom position set by myself
        self.arm.set_named_target('up')
        self.arm.go()
        rospy.sleep(1)

    def go_home(self, a=1, v=1):
        self.arm.set_max_acceleration_scaling_factor(a)
        self.arm.set_max_velocity_scaling_factor(v)
        # "home" is the custom position set by myself
        self.arm.set_named_target('home')
        self.arm.go()
        rospy.sleep(1)
    
    # 关节规划运动,输入6个关节角度(unit: radian)
    def move_j(self, joint_configuration=None, a=1, v=1):
        if joint_configuration == None:
            joint_configuration = [0, -np.pi/2, 0, -np.pi/2, 0, 0]
        self.arm.set_max_acceleration_scaling_factor(a)
        self.arm.set_max_velocity_scaling_factor(v)
        rospy.loginfo("move_j:" + str(joint_configuration))
        self.arm.set_joint_value_target(joint_configuration)
        self.arm.go()
        rospy.sleep(1)
    
    # reference frame下的空间规划,输入xyzRPY
    def move_p(self, pose_configuration=None, a=1, v=1):
        if pose_configuration == None:
            pose_configuration = [0.3, 0, 0.3, 0, -np.pi/2, 0]
        self.arm.set_max_acceleration_scaling_factor(a)
        self.arm.set_max_velocity_scaling_factor(v)

        target_pose = PoseStamped()
        # set reference frame 
        target_pose.header.frame_id = self.reference_frame
        target_pose.header.stamp = rospy.Time.now()
        target_pose.pose.position.x = pose_configuration[0]
        target_pose.pose.position.y = pose_configuration[1]
        target_pose.pose.position.z = pose_configuration[2]
        q = quaternion_from_euler(pose_configuration[3], 
                                    pose_configuration[4],
                                    pose_configuration[5])
        target_pose.pose.orientation.x = q[0]
        target_pose.pose.orientation.y = q[1]
        target_pose.pose.orientation.z = q[2]
        target_pose.pose.orientation.w = q[3]

        # set current pose as the start pose
        rospy.loginfo("move_p:" + str(pose_configuration))
        self.arm.set_start_state_to_current_state()
        self.arm.set_pose_target(target_pose, self.end_effector_link)
        self.arm.go(wait=True)
        # traj = self.arm.plan()
        # self.arm.execute(traj)

        # clean the target for next time plan
        self.arm.clear_pose_targets()
        rospy.sleep(1)
    
    # 空间直线运动,输入连续的(x,y,z,R,P,Y, x2,y2,z2,R2,P2,Y2, ...)
    # 默认只执行一个点位,需要指定传入点位的数量
    def move_l(self, tool_configuration, waypoints_number=1, a=0.5, v=0.5):
        if tool_configuration == None:
            tool_configuration = [0.3, 0, 0.3, 0, -np.pi/2, 0]
        self.arm.set_max_acceleration_scaling_factor(a)
        self.arm.set_max_velocity_scaling_factor(v)

        waypoints = []
        for i in range(waypoints_number):
            target_pose = PoseStamped()
            target_pose.header.frame_id = self.reference_frame
            target_pose.header.stamp = rospy.Time.now()
            target_pose.pose.position.x = tool_configuration[6*i + 0]
            target_pose.pose.position.y = tool_configuration[6*i + 1]
            target_pose.pose.position.z = tool_configuration[6*i + 2]
            q = quaternion_from_euler(tool_configuration[6*i + 3],
                                        tool_configuration[6*i + 4],
                                        tool_configuration[6*i + 5])
            target_pose.pose.orientation.x = q[0]
            target_pose.pose.orientation.y = q[1]
            target_pose.pose.orientation.z = q[2]
            target_pose.pose.orientation.w = q[3]
            waypoints.append(deepcopy(target_pose.pose))
        rospy.loginfo("move_l:" + str(tool_configuration))
        fraction = 0.0      # 路径规划覆盖率
        max_tries = 100     # 最大尝试规划次数
        attempts = 0        # 已经尝试规划次数

        self.arm.set_start_state_to_current_state()
        while fraction < 1.0 and attempts < max_tries:
            (plan, fraction) = self.arm.compute_cartesian_path(
                waypoints,  # waypoint poses, 路径点列表
                0.001,      # eef_step, 终端步进值
                0.00,       # jump_threshold, 跳跃阈值
                True)       # avoid_collisions, 避障规划
            attempts += 1
        if fraction == 1.0:
            rospy.loginfo("Path computed successfully. Moving the arm.")
            self.arm.execute(plan, wait=True)
            rospy.loginfo("Path execution complete.")
        else:
            rospy.loginfo("Path planning failed with only " + str(fraction) + 
                            "success after " + str(max_tries) + " attempts.")
        rospy.sleep(1)

    #=============================== test ===============================
    def test_move_functions(self):
        try:
            print("Test for robot...")
            # self.go_home()
            # self.move_j([0.3, -1.5, 1.2, 0.0, -1, 0.454125],a=0.5,v=0.5)
            # rospy.sleep(2)
            self.move_p([0.4, 0.4, 0.4, -np.pi/2, 0, 0])
            rospy.sleep(2)
            self.move_p([-0.2, -0.3, 0.5, np.pi/4, 0, 0])
            rospy.sleep(2)
            # self.move_l([0.4, 0.1, 0.4, -np.pi, 0, 0] )
            #rospy.sleep(2)
            self.move_l([0.4, 0.1, 0.4, -np.pi, 0, 0,
                         0.3, 0.4, 0.4, np.pi, 0, 0,],waypoints_number=2)
            rospy.sleep(2)
            print("Test success!")
            # self.close_gripper()
            # self.open_gripper()
            # self.grasp([0.4,0.2,0 ],[-np.pi, 0, 0])
            # self.move_p([-0.3, 0, 0.3, 0, -np.pi / 2, 0])
            # self.go_home()
            # waypoints=[]
            # start_pose = self.arm.get_current_pose(self.end_effector_link).pose
            # pose1=deepcopy(start_pose)
            # pose1.position.z +=0.1
            # waypoints.append(deepcopy(pose1))
            # self.move_l(waypoints)
            # self.go_home()
            #self.some_useful_function_you_may_use()
        except:
            print("Test fail! ")

if __name__ == "__main__":
    moveit_server = MoveIt_Controller(is_use_gripper=False)
    # test move functions
    moveit_server.test_move_functions()

然后启动rviz,再运行这个节点就能够让机械臂末端运动到指定的位姿了。

roslaunch fr5_gripper_moveit_config demo.launch 
rosrun fr_planning moveitServer.py 

如图所示

Image

Reference

[1]Move Group Python Interface
[2]【ROS机械臂入门教程】第6讲-Moveit基础(python)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/626510.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springboot月度员工绩效考核管理系统

摘要 本月度员工绩效考核管理系统采用java语言做为代码编写工具&#xff0c;采用mysql数据库进行系统中信息的存储与处理。框架采用springboot。 本系统的功能分为管理员和员工两个角色&#xff0c;管理员的功能有&#xff1a; &#xff08;1&#xff09;个人中心管理功能&am…

解决OpenHarmony设备开发Device Tools工具的QUICK ACCESS一直为空

今天重新安装了OpenHarmony设备开发的环境&#xff0c;在安装过程中&#xff0c;到了工程之后&#xff0c;QUICK ACCESS一直为空。如下图红色大方框的内容一开始没有。 解决方案&#xff1a; 在此记录我的原因&#xff0c;我的原因主要是deveco device tools的远程连接的是z…

Spring Bean的生命周期 五步 七步 十步 循序渐进

&#x1f468;‍&#x1f3eb; 参考视频地址 &#x1f496; 五步版 实例化 bean&#xff08;构造方法&#xff09;属性注入&#xff08;set() 方法&#xff09;初始化方法&#xff08;自定义&#xff09;使用bean销毁方法&#xff08;自定义&#xff09; &#x1f496; 七步版…

janus源码分析(1)--代码结构整理

基础说明 janus官网 https://janus.conf.meetecho.com/index.html janus源码地址 https://github.com/meetecho/janus-gateway 编译及部署参考 https://pro-hnb.blog.csdn.net/article/details/137730389?spm1001.2014.3001.5502 https://pro-hnb.blog.csdn.net/article/deta…

Online RL + IL : TGRL: An Algorithm for Teacher Guided Reinforcement Learning

ICML 2023 Poster paper Intro 文章设定一个专家策略&#xff0c;给出两种优化目标。一个是基于专家策略正则的累计回报&#xff0c;一个是原始累计回报。通过比较二者动态的衡量专家策略对智能体在线学习的影响程度&#xff0c;进而实现在线引导过程。 Method 原始的RL目标…

MyBatis常见报错:org.apache.ibatis.binding.BindingException

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 异常现象描述 当开发者在使用MyBatis进行数据库操作时&#xff0c;可能会遇到org.apache.ibatis.binding.BindingException: Parameter appId not found这样的错误提示。这个错误通常会让程序无法正常运行&#xff…

DeepSort / Sort 区别

推荐两篇博文,详细介绍了deepsort的流程及代码大致讲解: https://blog.csdn.net/qq_48764574/article/details/138816891 https://zhuanlan.zhihu.com/p/196622890 DeepSort与Sort区别: 1、Sort 算法利用卡尔曼滤波算法预测检测框在下一帧的状态,将该状态与下一帧的检测结…

TongWeb8 脚本录制功能

应用场景 在TongWeb8的命令行使用过程中&#xff0c;为简化从手册查找命令行参数的过程&#xff0c;增加了脚本录功能。录制您在控制台上所进行的操作过程&#xff0c;并可在一个新的环境回放这些操作&#xff0c;以提高业务系统的部署效率。录制的脚本文件类型包括 commandsto…

webapi路由寻址机制

路由匹配的原则 1、启动 Application_Start 文件夹中有个WebApiConfig 会把路由规则写入一个容器 2、客户端请求时&#xff1a; 请求会去容器匹配&#xff0c;先找到控制器&#xff08;找到满足的&#xff0c;就转下一步了&#xff09;&#xff0c;然后找Action&#xff0c;we…

高级DBA手把手教你达梦8国产数据库级联更新语句用MergeInto合并代替方法(达梦官方手册无此内容)

高级DBA手把手教你达梦8国产数据库级联更新语句用MergeInto合并代替方法&#xff08;达梦官方手册无此内容&#xff09; 一、传统级联更新语句例子 举例&#xff1a; 表 1&#xff1a;T1 字段名类型A时间类型B字符类型C字符类型D字符类型E字符类型 表 2&#xff1a;T2 字…

IDEA找不到database图标的解决方法

首先右边侧边栏和左边的侧边栏都看一下&#xff0c;确认没有数据库图标以后再参考下面方法。 第一步&#xff0c;打开设置&#xff0c;在插件里搜索database 第二步 安装好&#xff0c;点击确定 返回主页面&#xff0c;左边的侧边栏会出现database图标&#xff0c;点击号就可以…

C++自定义日期类的精彩之旅(详解)

在学习了C的6个默认成员函数后&#xff0c;我们现在动手实现一个完整的日期类&#xff0c;来加强对这6个默认成员函数的认识。 这是日期类中所包含的成员函数和成员变量&#xff1a; 构造函数 // 函数&#xff1a;获取某年某月的天数 inline int GetMonthDay(int yea…

2024精美UI小程序打印系统源码 PHP后端 附搭建教程+功能脑图

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 后端安装说明&#xff1a; 测试环境&#xff1a;NginxPHP7.4MySQL5.6 PHP安装扩展&#xff1a;sg11 网站运行目录设置为&#xff1a;/public 网站伪静态规则设置为&#xff1a;think…

C++基础语法之数组

一、一维数组 在C中&#xff0c;一维数组是一系列具有相同数据类型的元素的集合。它们在内存中是连续存储的&#xff0c;可以通过索引访问每个元素。 一维数组的声明形式如下&#xff1a; 数据类型 数组名[常量表达式] 例如&#xff1a; // 声明一个能存储10个整数的数组 in…

33三个启动菜单的区别辨析与本质探索

三个启动菜单的区别辨析与本质探索 你是否傻傻分不清以下三种启动菜单的本质到底是什么&#xff1f; 有一个看起来非常古老生硬&#xff0c;蓝色大背景&#xff0c;字母丑陋&#xff1b; 还有一个看起来老气横秋&#xff0c;黑底白字&#xff0c;像极了远古时期的电脑报废的样…

CSS2(一):CSS选择器

文章目录 1、CSS基础1.1 CSS简介1.2 CSS编写位置1.2.1 行内样式1.2.2 内部样式1.2.3 外部样式1.2.4 样式优先级 1.2.5 CSS代码风格 2、CSS选择器2.1、基本选择器2.1.1 通配选择器2.1.2 元素选择器2.1.3 类选择器2.1.4 ID选择器2.1.5 总结 2.2、CSS复合选择器2.2.1 交集选择器2.…

TailwindCSS在vite项目中的安装与使用

一、Tailwind CSS工作原理 Tailwind CSS 的工作原理是扫描所有 HTML 文件、JavaScript 组件和任何其他类名称模板&#xff0c;生成相应的样式&#xff0c;然后将它们写入静态 CSS 文件。它快速、灵活且可靠 — 具有零运行时间。 二、安装必要依赖 Vite创建的项目默认集成了Post…

【从零开始学习Redis | 第十一篇】快速介绍Redis持久化策略

前言&#xff1a; Redis 作为一种快速、高效的内存数据库&#xff0c;被广泛应用于缓存、消息队列、会话存储等场景。然而&#xff0c;由于其特性是基于内存的&#xff0c;一旦服务器进程退出&#xff0c;内存中的数据就会丢失。为了解决这一问题&#xff0c;Redis 提供了持久…

二叉树——初解

二叉树 树树的概念树的性质 二叉树二叉树的概念二叉树的性质二叉树的实现方式数组构建左孩子右兄弟法构建指针构建 树 树的概念 在计算机科学中&#xff0c;树&#xff08;Tree&#xff09;是一种重要的非线性数据结构&#xff0c;它由若干节点&#xff08;Node&#xff09;组…

揿针在医保上叫什么?

点击文末领取揿针的视频教程跟直播讲解 创新型皮内针&#xff08;揿针&#xff09;——医保甲类产品 皮内针&#xff08;揿针&#xff09;技术属于重点推广的中医适宜技术&#xff0c;是将特制的小型针具固定于腧穴部位的皮内或皮下做较长时间留针的一种方法&#xff0c;称“…