在ROS环境下,如何驱动真实的机器人?

4791
4
2019年12月12日 11时41分

​最近在知乎上看到一个问题:在ROS环境下,怎么使用moveit!来驱动真实的六轴机械臂?

很多小伙伴在使用ROS的时候,都会产生类似的疑问,程序写过那么多,仿真也跑过不少,但是如何控制真实机械臂/机器人呢?

今天古月君就来尝试破个题。

首先,解决这个问题的关键词是“接口”。所谓接口,即数据传输的通道,如何将ROS功能包计算得到的数据发给真实机器人并使之运动是问题的关键。

 1

 

机械臂有点复杂,我们先以简单一些的ROS小车为例,看看ROS是如何让真实小车动起来的。

大家在某宝上搜索“ROS移动机器人”,会出现一系列的小车,看来看去,无非都是类似下图的零部件组成的:

 

2

  做个分类,大家应该会更清晰一些:

 

3

 

这就是从控制角度看到的机器人四大组成部分,ROS并不是机器人的全部,主要运行于控制系统当中。

以小车的导航为例,从复杂的算法到小车的运动具体经过了哪些步骤呢?

1.使用者在rviz中使用鼠标选择一个导航目标点

2.全局规划器开始路径规划,得到一条从A到B的最优路径

3.本地规划器开始计算机器人每个周期的最佳速度,尽量靠近最优路径并躲避动态障碍物

 

OK,划重点啦,此时以上还都是ROS功能包完成的工作,我们进一步简化以上步骤,所有功能看成黑盒,输入是目标位置,输出是周期速度,这个周期速度就是“接口”。

 

4

 

接下来我们要做的事情就是让小车的硬件匹配这个周期速度的接口,怎么匹配呢?

小车的运动最后由电机执行,电机要转起来就需要一个电压信号,要产生电压信号就需要将控制信号(PWM)放大,要产生控制信号就需要有一个微控制器(MCU),微控制器的输入指令哪里来,一条电缆(网线或串口线)连接PC和MCU,接口就连上了。

当然,接口连上只是“肉体连接”,要做到“精神连接”还需要完成控制器里的驱动控制,也就是我们常说的PID闭环控制。

 

至此,我们成功的让小车动起来了,总结一下,我们怎么让小车动起来的:

1.ROS功能包跑起来

2.控制数据传输给小车的控制器

3.控制器里完成底层控制

4.控制信号变成电信号,电机转起来

 

5

 

似乎有点偏题,我们回到机械臂的场景,原理依然是上边的四个步骤,根据不同的硬件条件,并不是每个步骤都需要我们自己来实现。

在ROS环境下,不管是移动小车的move_base,还是机械臂的MoveIt!,都是解决第一个步骤的功能算法问题。ROS最大的好处就是:我们可以先不关注功能算法的内部实现,通过接口的拼接快速实现系统的原型所以这里我们需要关注的一个问题是MoveIt!的输入输出接口是什么?

 

在下边这张图中,我们可以看到MoveIt!核心节点的接口:

输入:编程API(C++、Python)、GUI(Rviz中的Motion Planning)

输出:关节轨迹(Trajectory)

 

6

 

先不纠结MoveIt!里边干了啥,反正当我们通过程序或者界面指定一个目标位置后,它会规划得到一条运动到目标位置的轨迹,这条轨迹由一系列关节空间的位置组成。

 

7

 

和ROS小车一样,接下来,我们要把这条轨迹发给机械臂的控制器,如果你使用的是类似UR、ABB这种工业机械臂的话,控制器都是配套的,只需要在示教器上做一些TCP端口的配置,就可以接收轨迹数据了,后续的底层控制算法和电机驱动就不需要我们关心了,完善的控制器都会帮我们实现。

 

8

 

换一个场景,如果是我们自己做机械臂,控制器需要自己开发,又该如何做呢?

还是上边ROS小车的思路,机械臂控制器里也需要实现这些基础功能:

1.接收控制数据(运动轨迹)

2.完成底层运动控制

3.控制信号变成电信号,电机转起来

 

9

 

不管你用的控制器是MCU、树莓派还是PC,总会有和外界通信的方法,比如常见的串口、网络等,所以第一个接收控制数据的方法就是通过任一媒介,将轨迹数据发送到控制器上,具体实现可以参考ros_serial、ROS-I Simple Message功能包或串口、 socket通信的编程方法。

收到数据之后呢?MoveIt!规划得到的关节轨迹由一系列轨迹点组成,每两个点之间的时间间隔不定,基本是0.1~1秒之间,这个时间间隔对于底层控制来讲,是非常大的,很容易造成轨迹运动不圆滑、速度不均匀的现象,需要进一步细分到和控制周期匹配的间隔,也就是你可能常听说的“轨迹插补”,具体实现可以参考ros_control。

比如初始轨迹的运动总时间是5s,按照10ms插补,那么我们将得到一条由500个点组成的轨迹,每个点包含此刻各关节的位置信息。

 

10

 

接下来就是把这些位置信息变成电信号,让电机转动带动机械臂运动,这就是我们常说的电机驱动。如果你用的是步进电机,你可能需要一个可以接收脉冲位置的步进驱动器,如果你用的是伺服电机,可能需要一个可以接收位置指令的伺服驱动器,如果你使用的是舵机,直接发送位置指令即可,如果你要自己做驱动器,请Google“如何实现电机驱动器”。

按照周期依次完成所有点后,轨迹运动完成,真实机械臂就按照MoveIt!的规划完成运动了。

 

古月君洋洋洒洒写了这么多,你可能已经从入门到放弃了。。。

好吧,忽略上边的所有内容,直接看图:

 

11

 

ROS MoveIt!控制真实机械臂的一般框架:

1.通过程序或界面设置机械臂运动目标

2.MoveIt!完成运动规划并输出关节轨迹

3.通过socket接口和控制器连接,将关节轨迹发送给控制器

4.控制器进行插补运算,并周期发送给电机驱动器

5.驱动器完成闭环控制,让电机多、快、好、爽的跟随输入指令

6.控制器反馈实时状态到MoveIt!,Rviz动态显示当前状态

 

以上内容古月君偏向于系统原理的介绍,具体实现的手段和硬件相关,各位还需要在原理的基础上完成开发。愿大家都拥有一段美好的机器人开发之旅~

 

发表评论

后才能评论

评论列表(4条)

  • u3oey_0531 2020年1月28日 下午6:14

    胡老师您好,我在使用您的书的时候,启动gazebo的时候打不开gazebo 有这样的提示:(51) SSL: no alternative certificate subject name matches target host name ‘api.ignitionfuel.org 然后闪退 是什么情况 我用的是melodic版本

    • 古月 回复 u3oey_0531 2020年2月6日 下午11:02

      首先确认是否是在虚拟机中运行的,需要配置图形渲染是用cpu,其次确认是否下载了离线模型库,gazebo最好重新安装下

  • 张达 2019年12月17日 下午10:46

    胡老师您好,我是您机械臂实战课程的学员,我在跟着您的课程moveit部分做一下例程:
    roslaunch cute_moveit_config demo.launch
    rosrun marm_planning moveit_fk_demo.py
    时,遇到如下问题:
    Failed to import pyassimp, see https://github.com/ros-planning/moveit/issues/86 for more info
    [ INFO] [1576593461.761421725]: Loading robot model ‘cute_300es’…
    [ INFO] [1576593461.761502347]: No root/virtual joint specified in SRDF. Assuming fixed joint
    [ INFO] [1576593461.878585250]: Loading robot model ‘cute_300es’…
    [ INFO] [1576593461.878607852]: No root/virtual joint specified in SRDF. Assuming fixed joint
    [ INFO] [1576593463.025034459]: Ready to take commands for planning group cute_arm.
    [ INFO] [1576593463.833792801]: Ready to take commands for planning group cute_gripper.
    Traceback (most recent call last):
    File “/home/zhx/ROS/catkin_ws/src/cute_robot/marm_planning/scripts/moveit_fk_demo.py”, line 50, in
    MoveItFkDemo()
    File “/home/zhx/ROS/catkin_ws/src/cute_robot/marm_planning/scripts/moveit_fk_demo.py”, line 32, in __init__
    gripper.set_joint_value_target([0.01])
    File “/opt/ros/kinetic/lib/python2.7/dist-packages/moveit_commander/move_group.py”, line 227, in set_joint_value_target
    raise MoveItCommanderException(“Error setting joint target. Is the target within bounds?”)
    moveit_commander.exception.MoveItCommanderException: Error setting joint target. Is the target within bounds?
    请问这是什么原因?

    • 古月 回复 张达 2019年12月23日 下午3:28

      你用的是课程例程么,错误提示gripper.set_joint_value_target([0.01])里的0.01不在运动范围内