机械臂仿真 ros下从xacro模型文件搭建Moveit!+Gazebo仿真系统

目录总览

小车yolo机械臂(一)ros下gazebo搭建小车(可键盘控制)安装摄像头仿真 加载yolo检测识别标记物体

小车yolo机械臂(二)机械臂仿真 ros下从xacro模型文件搭建Moveit!+Gazebo仿真系统

小车yolo机械臂(三)ROS消息订阅监听 rospy.Subscriber 订阅监听yolo python实现订阅/darknet_ros/bounding_boxes topic

小车yolo机械臂(四)python ros 和darknet_ros 使用launch文件启动脚本

小车yolo机械臂(五)让小车在命令下运动起来 rostopic pub /cmd_vel geometry_msgs/Twist

小车yolo机械臂(六)ros gazebo 小车摄像头根据darknet_ros中yolo目标检测的信息进行自主运动

小车yolo机械臂(七)小车与机械臂融合,并控制机械臂运动 gazebo control

小车yolo机械臂(八)ros小车和机械臂gazebo仿真,机械臂根据darknet_ros中yolo检测结果来自动运动 python实现

一,项目下载

项目所需代码已经上穿github,直接下载即可用:

https://github.com/Whiffe/arm-of-robot-using-Moveit-in-ros-gazebo-rviz

项目总体:
在这里插入图片描述

按照正常的操作步骤,是需要使用Moveit生成机械臂的配置文件,该配置文件已经在下载的文件中,即:marm_moveit_config文件,所以使用Moveit生成文件的过程我们直接跳过。

如果想要自己操作的小伙伴,参考以下的博客:
MoveIt!上手指南
从xacro模型文件搭建Moveit!+Gazebo仿真系统

二,marm_moveit_config配置文件使用

测试moveit的配置文件里的demo
在终端输入命令:

roslaunch marm_moveit_config demo.launch

在这里插入图片描述

可以看到rviz的界面结果:

在这里插入图片描述

通过拖动机械臂末端的球可以改变机械臂的位置,拖动蓝绿红三个圈可以改变机械臂的姿态,当确定一个姿态后,可在左侧Planning一栏中点击Plan按钮规划从当前位姿到指定位姿的运动,可以看见模拟此次运动规划的透明灰色机械臂,但此时实际的机械臂并没有动,可在左侧点击Add,添加Robot Model显示机械臂当前所处的实际状态,再点击Execute就可让实际的机械臂按照刚刚模拟的轨迹运动。另外,也可更改机械臂的运动速度和加速度值,对应Planning - Options中的Velocity Scaling和Acceleration Scalling,也可以通过Query一栏中选定已设定的姿态(配置时的Robot Pose)来进行规划。
在这里插入图片描述

三,Gazebo搭建ROS仿真环境

3.1 相关概念简介

what is ros_control?

  • ROS为开发者提供的机器人控制中间件。
  • 包含一系列控制器接口、传动装置接口、硬件接口、控制器工具箱等等。
  • 可以帮助机器人应用功能包快速落地,提高开发效率
  • ros_control
  • 图中的一些模块的含义:

    Controller Manager:控制中心,管理控制器与监视器,管理方式例如list,load,unload,switch等

    1:joint_state_publisher:监视器,负责从硬件抽象层接受反馈信号。
    2:joint_trajectory_controller:关节轨迹控制器,使用PID控制算法发布控制信号至硬件抽象层。

    Hardware Resource Interface Layer:硬件抽象层,控制层与硬件资源之间的数据中转站,负责转换普通数据为ROS通讯数据(msg, srv等等),以及传输数据。

    Simulation-Gazebo:Gazebo作为硬件仿真器,由仿真硬件接口中心通过读和写的方式控制

    1:DefaultRobotHWSim:介于ros_control与Gazebo之间提供速度、位置和力矩接口的仿真接口中心
    2: Effort Transmissions:力传动装置,接受硬件抽象层封装的数据并转化为力矩等具体控制数据。
    3:Joint Limits:执行一些关节限制条件,例如碰撞检测,防止模型崩溃,检测后通过接口中心调用将控制力矩写入Gazebo,控制仿真机器人运动。
    Forward State Transmission:通过接口中心实时读取仿真运动的控制反馈数据,并传递回硬件抽象层

    Hardware-Reality:实体机器人

    1:RobotHW:介于ros_control与Gazebo之间提供速度、位置和力矩接口默认的实体硬件接口中心

    2:Embedded Controller:实体电机上的嵌入式控制板卡,接受Joint Limits的力矩数据,转化为电压信号,通过硬件接口中心发送至执行机构Actuators。

    3:Actuators:伺服电机或其他驱动器,按照嵌入式板卡发送的电压数据驱动实体机器人运动

    4:Encoders:编码器,位于执行机构上,实时读取机器人的关节运动状态,由Forward State Transmission通过硬件接口中心读取并反馈至硬件抽象层。

    3.2 ROS常用控制器
    joint_velocity_controller:速度控制器
    joint_position_controller:位置控制器
    joint_effort_controller:力控制器
    joint_state_controller:监控机器人运行状态的模块(接收和处理控制过程的产生的信息),与控制过程无关
    在这里插入图片描述

  • 3.3 ROS中的控制器插件
    控制器管理器:Controller Manager,提供一种通用的接口来管理所有控制器,此处的管理指的就是统筹各个控制器的开关以及各种参数和输入输出等等。
    控制器:Controller,读取硬件状态,发布控制命令至Gazebo(仿真)/硬件抽象层(实体),控制实体机器人的话硬件抽象层还会将数据发送给具体的硬件部位,例如小车车轮上的嵌入式板卡,再由该开发板根据控制方式发送电压信号给驱动电机(执行机构),实现对具体关节的控制,并且在机器人运动过程中,电机上装载的编码器将监控电机的转速并将其反馈至硬件抽象层,进行封装后再经由interface接口发送至控制层的joint_state_controller,形成完整的闭环控制。
    硬件资源:为上下两层提供硬件资源的接口
    机器人硬件抽象:与机器人硬件资源直接想通,通过write和read的方式完成硬件操作
    机器人硬件:执行接收到的命令
    四,arm.xacro机械臂模型解析
    在目录:/home/winston/catkin_ws/src/marm_description/urdf下的arm.xacro文件:

    第一步:为每个link添加惯性参数和碰撞属性

    一个link属性不可缺少三部分:惯性参数(inertial)、可视化属性(visual)和碰撞属性(collision),打开配置文件后发现属性的形式已经是完整的了,只需要改一些参数。

        <link name="link1" >
            <visual>
                <origin xyz="-${link1_len/2} 0 0" rpy="0 ${M_PI/2} 0" />
                <geometry>
                    <cylinder radius="${link1_width}" length="${link1_len}"/>
                </geometry>
                <material name="Blue" />
            </visual>
            <collision>
                <origin xyz="-${link1_len/2} 0 0" rpy="0 ${M_PI/2} 0" />
                <geometry>
                    <cylinder radius="${link1_width}" length="${link1_len}"/>
                </geometry>
            </collision>
            <xacro:inertial_matrix mass="1"/>
        </link>
    
  • 第二步:为每个joint添加传动装置
    oint的作用显然是连接连个link,但link的运动方式有多种,例如平移、旋转等等,因此需要为joint添加传动装置以实现连杆的多种运动方式,传动装置一般就是电机和减速器的组合体,不可缺少。

    利用宏为六个joint添加作为传动装置的电机和减速器

        <!-- Transmissions for ROS Control -->
        <xacro:macro name="transmission_block" params="joint_name">
            <transmission name="tran1">
                <type>transmission_interface/SimpleTransmission</type>
                <joint name="${joint_name}">
                    <hardwareInterface>hardware_interface/PositionJointInterface</hardwareInterface>
                </joint>
                <actuator name="motor1">
                    <hardwareInterface>hardware_interface/PositionJointInterface</hardwareInterface>
                    <mechanicalReduction>1</mechanicalReduction>
                </actuator>
            </transmission>
        </xacro:macro>
        
        <xacro:transmission_block joint_name="joint1"/>
        <xacro:transmission_block joint_name="joint2"/>
        <xacro:transmission_block joint_name="joint3"/>
        <xacro:transmission_block joint_name="joint4"/>
        <xacro:transmission_block joint_name="joint5"/>
        <xacro:transmission_block joint_name="joint6"/>
        <xacro:transmission_block joint_name="finger_joint1"/>
    
  • 第三步:添加gazebo控制器插件
  •     <!-- ros_control plugin -->
        <gazebo>
            <plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
                <robotNamespace>/arm</robotNamespace>
     	    <legacyModeNS>true</legacyModeNS> 
            </plugin>
        </gazebo>
    
  • 五,构建Moveit!+Gazebo联合仿真

    5.1 MoveIt!机器人控制框架

  • 在这里插入图片描述
  • 其中各个模块的功能如下:

    Moveit!模块:运动学+路径规划+碰撞检测

    1,输入:通过可视化控制界面Rviz发布的指令,或包含控制指令的C++、Python源代码

    2,输出:关节空间运动轨迹数据,由多个路径点组成,单点的数据由各个轴的位置、速度、加速度组合描述

    Follow Joint Trajectory:将Moveit!模块输出的数据封装成具体的通讯机制(话题、服务等)

    Trajectory Controller:机器人控制器(仿真/实体),包含上文所说的控制中心、控制器与硬件抽象层

    1,输入:经过格式转换的Moveit!模块输出路径点数据

    2,控制特点:

     1)线性样条:位置连续,速度、加速度不连续
     2)三次样条:位置和速度连续,加速度不连续
     3)五次样条:位置、速度、加速度都连续(ROS默认的插补方式)
    
  • 3,Trajectory Interpolation:轨迹插补,输入的轨迹由于路径点之间存在时间差而整体较粗糙,通过在路径点的时间差内进行插补的方式,可以细化整个轨迹(简单地说就是增大路径点密度)

    4, Position Servo:位置伺服,通过分析插补后的轨迹,确定下一时刻的机器人的位姿,并产生控制机器人各个驱动电机的电压信号,属于硬件抽象层。

    5,输出:驱动机器人各个电机的电压信号

    Robot Body:机器人本体(仿真/实体),6个电机(M)根据伺服信号驱动机器人运动,并通过伺服电机上的编码器实时反馈数据。

    Joint State Controller:控制层的监控模块,接受并处理反馈信号

    5.2 arm_world.launch
    在/home/winston/catkin_ws/src/marm_gazebo/launch目录下找到arm_world.launch,内容如下:

    <launch>
    
      <!-- these are the arguments you can pass this launch file, for example paused:=true -->
      <arg name="paused" default="false"/>
      <arg name="use_sim_time" default="true"/>
      <arg name="gui" default="true"/>
      <arg name="headless" default="false"/>
      <arg name="debug" default="false"/>
    
      <!-- We resume the logic in empty_world.launch -->
      <include file="$(find gazebo_ros)/launch/empty_world.launch">
        <arg name="debug" value="$(arg debug)" />
        <arg name="gui" value="$(arg gui)" />
        <arg name="paused" value="$(arg paused)"/>
        <arg name="use_sim_time" value="$(arg use_sim_time)"/>
        <arg name="headless" value="$(arg headless)"/>
      </include>
    
      <!-- Load the URDF into the ROS Parameter Server -->
      <param name="robot_description" command="$(find xacro)/xacro --inorder '$(find marm_description)/urdf/arm.xacro'" /> 
    
    
      <!-- Run a python script to the send a service call to gazebo_ros to spawn a URDF robot -->
      <node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" respawn="false" output="screen"
    	args="-urdf -model arm -param robot_description"/> 
    
    
    </launch>
    
  • 运行查看机械臂模型在gazebo中是否显示正常
  • roslaunch marm_gazebo arm_world.launch
    
  • 在这里插入图片描述
  • 在这里插入图片描述
  • 显示正常,说明模型没有问题,但此时模型还不能运动,因为我们还没有配置gazebo中的控制器,也就暂时无法接受和处理Moveit发送的轨迹路径点数据。对应的控制器就是Moveit!机器人控制框架中Gazebo部分的Trajectory Controller与Joint State Controller。另外,在配置完Gazebo控制器后还需要配置Moveit中的Follow Joint Trajectory控制器,才可完成Moveit!与Gazebo的通讯。

    5.3 配置Gazebo控制器
    5.3.1配置关节轨迹控制器(轨迹插补)Trajectory Controller
    在功能包marm_gazebo/config路径下的配置文件trajectory_control.yaml,配置内容如下,内容含义为明确控制器接受数据的对象是哪几个关节,注意这里的6个关节名要与原xacro模型文件中的关节名一致,gains表示每个关节在做闭环PID控制时的参数,此处设置了一个默认值,在之后的调试中若要提高控制精度,需要改动这些pid参数。

    arm:
      arm_joint_controller:
        type: "position_controllers/JointTrajectoryController"
        joints:
          - joint1
          - joint2
          - joint3
          - joint4
          - joint5
          - joint6
    
        gains:
          joint1:   {p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0}
          joint2:   {p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0}
          joint3:   {p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0}
          joint4:   {p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0}
          joint5:   {p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0}
          joint6:   {p: 1000.0, i: 0.0, d: 0.1, i_clamp: 0.0}
    
    
      gripper_controller:
        type: "position_controllers/JointTrajectoryController"
        joints:
          - finger_joint1
        gains:
          finger_joint1:  {p: 50.0, d: 1.0, i: 0.01, i_clamp: 1.0}
    
    
  • 之后我们需要一个launch文件,用于加载这个控制器,这里命名为arm_trajectory_controller.launch,内容如下,大致意义为加载上面的yaml文件,并通过启动已有的节点spawner来启动控制器节点arm_controller_spawner,节点名与yaml中的控制器名对应
    <launch>
    
        <rosparam file="$(find marm_gazebo)/config/trajectory_control.yaml" command="load"/>
    
        <node name="arm_controller_spawner" pkg="controller_manager" type="spawner" respawn="false"
              output="screen" ns="/arm" args="arm_joint_controller gripper_controller"/>
    
    </launch>
    
  • 5.3.2 配置关节状态控制器Joint State Controller

    同样在marm_gazebo/config路径下创建配置文件arm_gazebo_joint_states.yaml,内容如下,意义为按照50hz的频率反馈信息。

  • arm:
      # Publish all joint states -----------------------------------
      joint_state_controller:
        type: joint_state_controller/JointStateController
        publish_rate: 50  
      
    
  • launch文件arm_gazebo_states.launch用于启动该控制器,内容如下
  • <launch>
        <!-- 将关节控制器的配置参数加载到参数服务器中 -->
        <rosparam file="$(find marm_gazebo)/config/arm_gazebo_joint_states.yaml" command="load"/>
    
        <node name="joint_controller_spawner" pkg="controller_manager" type="spawner" respawn="false"
              output="screen" ns="/arm" args="joint_state_controller" />
    
        <!-- 运行robot_state_publisher节点,发布tf  -->
        <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher"
            respawn="false" output="screen">
            <remap from="/joint_states" to="/arm/joint_states" />
        </node>
    
    </launch>
    
    
    
  • 5.4 配置Moveit!控制器
    刚刚配置的是Gazebo环境中的关节轨迹控制器与关节状态控制器,现在要配置的是Moveit!的控制器Follow Joint Trajectory,作用是转换Moveit!的轨迹路径点数据为ROS通讯数据。

    在Moviet生成的配置包的配置目录marm_moveit_config/config下的配置文件controllers_gazebo.yaml,内容如下:

    controller_manager_ns: controller_manager
    controller_list:
      - name: arm/arm_joint_controller
        action_ns: follow_joint_trajectory
        type: FollowJointTrajectory
        default: true
        joints:
          - joint1
          - joint2
          - joint3
          - joint4
          - joint5
          - joint6
    
      - name: arm/gripper_controller
        action_ns: follow_joint_trajectory
        type: FollowJointTrajectory
        default: true
        joints:
          - finger_joint1
          - finger_joint2
    
  • 在/launch路径中打开moveit控制器启动文件

    arm_moveit_controller_manager.launch.xml,读取Moveit仿真控制器配置文件的内容如下:

  • <launch>
      <!-- Set the param that trajectory_execution_manager needs to find the controller plugin -->
      <arg name="moveit_controller_manager" default="moveit_simple_controller_manager/MoveItSimpleControllerManager" />
      <param name="moveit_controller_manager" value="$(arg moveit_controller_manager)"/>
    
      <!-- load controller_list -->
      <!-- Arbotix
      <rosparam file="$(find marm_moveit_config)/config/controllers.yaml"/> -->
      <!-- Gazebo -->
       <rosparam file="$(find marm_moveit_config)/config/controllers_gazebo.yaml"/> 
    </launch>
    
  • 之后需要另外创建一个launch文件moveit_planning_execution.launch,以同时启动原有的两个moveit相关的launch文件move_group.launch与moveit_rviz.launch,并且启动关节状态发布器节点joint_state_publisher
    <launch>
     # The planning and execution components of MoveIt! configured to 
     # publish the current configuration of the robot (simulated or real)
     # and the current state of the world as seen by the planner
     <include file="$(find marm_moveit_config)/launch/move_group.launch">
      <arg name="publish_monitored_planning_scene" value="true" />
     </include>
     # The visualization component of MoveIt!
     <include file="$(find marm_moveit_config)/launch/moveit_rviz.launch"/>
    
      <!-- We do not have a robot connected, so publish fake joint states -->
      <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher">
        <param name="/use_gui" value="false"/> 
        <rosparam param="/source_list">[/arm/joint_states]</rosparam>
      </node>
    
    </launch>
    
  • 最后,marm_gazebo/launch路径下的一个launch文件arm_bringup_moveit.launch,用于同时启动刚刚完成配置的三个控制器(Gazebo关节轨迹控制器,Gazebo关节状态控制器,Moveit!控制器),并启动刚刚创建的moveit_planning_execution.launch
    <launch>
      
        <!-- Launch Gazebo  -->
        <include file="$(find marm_gazebo)/launch/arm_world.launch" />
    
        <!-- ros_control arm launch file -->
        <include file="$(find marm_gazebo)/launch/arm_gazebo_states.launch" />   
    
        <!-- ros_control trajectory control dof arm launch file -->
        <include file="$(find marm_gazebo)/launch/arm_trajectory_controller.launch" />
    
        <!-- moveit launch file -->
        <include file="$(find marm_moveit_config)/launch/moveit_planning_execution.launch" />
    
    </launch>
    
  • 5.5 试运行仿真并查看数据

    配置完成后,执行roslaunch命令运行总的launch文件查看效果

  • roslaunch marm_gazebo arm_bringup_moveit.launch
    
  • 在这里插入图片描述
  • 这里会出现rviz报错:
    Global Status: Error:
    Fixed Frame [map] does not exist
  • 在这里插入图片描述
  • 解决方案:
    第一步:Displays/Global Options/Fixed Frame的map改为base_link
  • 在这里插入图片描述
  • 在这里插入图片描述
  • 第二步:点击add,添加RobotModel,点击OK
  • 在这里插入图片描述
  • 在这里插入图片描述
  • 最后就可以看到机械臂模型
  • 在这里插入图片描述
  • 第三步:还是点击add,选择MotionPlanning,点击OK
  • 在这里插入图片描述
  • 最后可以看到:
  • 在这里插入图片描述
  • 运行rviz:点击MotionPlanning的Planning,接着选择Query中的Update,再选择Commands中的Plan and Execute。
  • 在这里插入图片描述
  • 可以看到rviz中的机械臂开始移动:
  • 在这里插入图片描述
  • 界面切换到gazebo中,可以看到gazebo中的机械臂也在跟着移动:
  • 在这里插入图片描述
  • 为了查询关节空间轨迹规划的数据信息,我们执行rostopic list,找到以arm开头topic:
  • 在这里插入图片描述
  • 其中的/goal就是我们需要的目标轨迹话题,我们使用rostopic echo指令输出它的内容:
  • rostopic echo /arm/arm_joint_controller/follow_joint_trajectory/goal
    
  • 发现提示没有输出内容 “no messages received and simulated time is active”
  • 在这里插入图片描述
  • 我们需要让机器人动起来才有规划的数据,因此随便在rviz中规划一次运动,再执行一次查看数据:
  • 在这里插入图片描述
  • 其中header与goal_id是本次规划的标志信息,而goal里的points储存的就是本次规划的具体内容,可见一个路径点的数据由位置position、速度velocities、加速度accelerations、力矩effort以及时间戳time_from_start构成。这些数据将传输给Moveit控制器Follow Joint Trajectory,进行封装后再传递给Gazebo或实际的机器人控制器进行插补,最后传输给驱动装置控制机器人运动。

    另外,可以用rqt_plot可以查看各个关节在本次规划中的运动轨迹(属于关节空间),在上一步的rostopic list中可查找到名为joint_states的话题,我们输出这个话题的内容:

    rostopic echo joint_states
    
  • 在这里插入图片描述
  • 可见话题内的数据为不同时刻下的各个关节的位置、速度以及力的数值。