注:本文参考和翻译于robotis的官方文档:Robotis Manipulator Library. 翻译版权和额外提供内容隶属于北京小芽科技有限公司。分享请注明出处。
概述
robotis_manipulator是一个用于控制机械手的库,该库提供了一个用于设置机械手参数的类,并提供了一些数学函数用于配置机械手控制器,以及一个使用minimum-jerk算法的轨迹生成器。用户可以自行设计一个继承RobotisManipulator的类,并通过使用提供的函数和虚拟类来设置该类。该类提供的功能包括:创建轨迹,接收关节位置信息,发送关节目标位置信息。open_manipulator_libs 可以作为一个参考例程。
安装
robotis_manipulator软件包支持ROS和OpenCR控制板。用户可以通过在ROS环境下使用robotis_manipulator软件包编写自己的程序来控制用户的机械手。如果你想在一个更简单的开发环境中使用robotis_manipulator,你可以使用OpenCR,这是一个强大的嵌入式系统。用户可以在支持OpenCR的arduino IDE环境中轻松使用robotis_manipulator。
ROS 软件包
注 : 该软件包已经在安装有ROS Kinetic Kame
的 Ubuntu 16.04
做过测试。
在PC上安装Ubuntu
下载Ubuntu 16.04并在PC上安装。
可以按照以下方式安装Ubuntu。
在PC上安装 ROS
下面的脚本将为你简化ROS的安装流程。在一个终端窗口中运行以下命令。终端程序可以通过屏幕左上角的Ubuntu搜索图标找到。打开终端的快捷键是Ctrl
+Alt
+t
。安装完ROS后,请重新启动电脑。
1 | $ sudo apt-get update |
注意。为了检查哪些软件包已经安装,请查看这个链接。 install_ros_kinetic.sh
如果您喜欢手动安装,请点击下面的链接。
ROS 相关软件包
安装robotis_manipulator 软件包。 请在终端中运行以下命令:
1 | $ cd ~/catkin_ws/src/ |
If the catkin_make command has been completed without any errors, all the preparations for using the robotis_manipulator package are done.
OpenCR控制器
连接
如下图,把OPENCR的USB口通过microUSB线连接到电脑PC上。
注:请参考OpenCR的详细说明。
Arduino IDE 设置
注:本页仅解释linux环境下OpenCR的设置过程。如果您想在windows或mac环境中使用OpenCR,请参考[Arduino IDE了解OpenCR的使用](https://emanual.robotis.com/docs/en/parts/controller/opencr10/#arduino-ide)。
安装Arduino IDE(Linux)
从Arduino官方主页下载最新版本的Arduino IDE,然后安装。目前,OpenCR将在1.6.4或更高版本中提供服务。
https://www.arduino.cc/en/Main/Software
然后,将下载的文件解压缩到所需文件夹,并从终端执行安装文件。在本例中,下面的示例将tools文件夹置于用户文件夹的顶部(~/)中。此文件夹将用作Arduino IDE文件夹。
1 | $ cd ~/tools/arduino-1.6.4 |
Set the file path of installed Arduino IDE as an absolute path named PATH in the bashrc file. Here recommends to use gedit editor. (Use another editor, if necessary.) Finally, source it to apply the changes.
将安装的Arduino IDE的文件路径设置为bashrc文件中名为PATH的绝对路径。这里推荐使用gedit编辑器。(如有必要,请使用其他编辑器。)最后,使用source指令接受环境变量的更改。
1 | $ gedit ~/.bashrc |
运行 Arduino IDE(Linux)
在终端中输入以下指令运行Arduino IDE:
1 | $ arduino |
运行Arduino IDE后,单击菜单栏中的File→ Preferences。当“首选项”窗口出现时,将以下链接复制并粘贴到“Additional Boards Manager URLs”文本框。(此步骤可能需要大约20分钟。)
1 | https://raw.githubusercontent.com/ROBOTIS-GIT/OpenCR/master/arduino/opencr_release/package_opencr_index.json |
通过Boards Manager安装OpenCR 相关库
Click Tools → Board → Boards Manager.
在编辑框中输入OpenCR以查找ROBOTIS提供的OpenCR包。发现后,单击安装。
安装完毕之后,将出现 “INSTALLED” 字样。
在Tools → Board中查看是否出现OpenCR Board。 单击该OpenCR Board导入相关资源。
端口设置
此步骤显示程序上载的端口设置。OpenCR应通过USB端口连接到PC和OpenCR。
Select Tools → Port → /dev/ttyACM0.
警告:根据USB连接环境的不同,字符串“/dev/ttyACM0”中的最后一个数字值“0”可能不同。
注:请参考 Arduino IDE for using OpenCR(linux) 以了解相关使用方法。
API 相关
使用教程
robotis_manipulator是一个库,它存储控制操纵器所需的参数,并进行运动学求解、轨迹生成和执行器通信。本教程介绍如何使用robotis_manipulator。在本教程中,我们将使用为控制OpenMANIPULATOR-X RM-X52-TNM而创建的open_manipulator_libs
作为例子。
步骤1: 设计OpenManipulator机械手类
1 |
|
创建一个机械手类,继承robotis_manipulator::RobotisManipulator
类。在这个例子中,我们创建了initOpenManipulator
和processOpenManipulator
作为该类的公有函数。
步骤2:初始化机械手
InitOpenManipulator
功能设置机械手的DH(Denavit Hartenberg)参数、运动学解算器、执行器和轨迹生成器。下面是OpenManipulator
类的InitOpenManipulator
函数。
1 | void OpenManipulator::initOpenManipulator(bool using_actual_robot_state, STRING usb_port, STRING baud_rate, float control_loop_time) |
设置机器人参数
在robotis_manipulator中,机械手由world、joint components和tool components组成,如下图所示。world是指机械手固定的基地(基板)。joint components和tool components分别有一个框架和坐标系。在joint component中,坐标位于关节的旋转轴上,而在tool component中,坐标是在夹具的中心位置。
在InitOpenManipulator
函数中, 机械手的DH 参数设置如下所示:
1 | /***************************************************************************** |
设置机械手的DH参数可以使用 addWorld
, addJoint
, addTool
, 和 addComponentChild
函数。
addWorld 函数
1 | void RobotisManipulator::addWorld(Name world_name, |
在固定的机械手中设置一个world 。这个world指的是固定机械手的一个基础坐标点,这个点可以根据固定的机械手状态而改变。一个机械手只有一个世界坐标点。
- world_name : world坐标的名称
- child_name : 下一个连接到world坐标点的坐标系名词
- world_position : 指定world坐标系的位置。它有一个矢量格式,默认值是(0.0, 0.0, 0.0)的原点。
- world_orientation : 指定初始world坐标的方向。它有一个旋转矩阵的格式,默认值是单位矩阵。
addJoint 函数
1 | void RobotisManipulator::addJoint(Name my_name, |
增加一个机械手的joint component。joint component是指所有带或不带执行器运行的关节组件。位于机械手末端的末端执行器被排除在joint component之外。joint component的位置和方向是指关节所在的旋转轴的坐标位置和方向。
- my_name : 指定相应关节组件的名称。
- parent_name : 指定此关节组件连接到的上一个组件的名称。
- child_name : 指定此关节组件连接到的下一个组件的名称。
- relative_position : 以矢量格式指定关节坐标与父部件坐标的相对位置。
- relative_orientation : 以旋转矩阵格式指定关节坐标相对于父部件坐标的相对方向。
- axis_of_rotation : 指定关节组件的旋转轴,旋转轴在relative_position和relative_orientation所设定的坐标中。
- joint_actuator_id : 指定用于该关节的id。id可以设置为大于或等于0的自然数,并且各个关节的id必须互异。如果id被设置为*-1*,则该关节被指定为被动关节,没有附加致动器。
- max_position_limit : 指定该关节的最大运动范围;
- min_position_limit : 指定该关节的最小运动范围;
- coefficient : 通过关节的结构指定reduction ratio。这个值表示执行器的位置值与关节的位置值的比率。
- mass : 指定关节的质量。
- inertia_tensor : 指定联合组件的惯性张量(inertia tensor)。这个值是为父组件坐标定义的。
- center_of_mass : 指定关节组件的重心。该值是为父部件坐标定义的。
addTool 函数
1 | void RobotisManipulator::addTool(Name my_name, |
添加一个机械手的工具组件。这个工具被称为机械手的末端执行器,被安装在机械手的末端,也就是机械爪,它没有任何子组件。一个机械手可以被配置有多个工具组件。
- my_name : 指定相应工具组件的名称。
- parent_name : 指定该工具组件所连接的前一个组件的名称。
- relative_position : 以矢量格式指定工具坐标相对于父组件坐标的相对位置。
- relative_orientation : 以旋转矩阵格式指定关节坐标相对于父部件坐标的相对方向。
- tool_id : 指定工具中使用的执行器(舵机)的id。id可以被设置为大于或等于0的自然数,并且各个执行器(舵机)的id必须互异。如果id被设置为-1,则该工具被指定为一个没有连接致动器的被动末端执行器。
- max_position_limit : 指定末端执行器运行范围的上限。
- min_position_limit : 指定末端执行器运行范围的下限。
- coefficient : 表示执行器的位置值与工具部件位置值的比例。
- mass : 指定该工具组件的质量。
- inertia_tensor : 指定工具组件的*惯性张量(inertia tensor)*。这个值是为父组件坐标定义的。
- center_of_mass : 指定工具组件的重心。该值是为父部件坐标定义的。
addComponentChild 函数
1 | void RobotisManipulator::addComponentChild(Name my_name, Name child_name); |
在addJoint
函数之后,使用addComponentChild
函数添加该组件的子组件。当关节组件除了在addJoint
函数中已经指定的child_name外,还有其他子组件时使用。工具组件没有子组件,因为它位于操纵器的末端。
- my_name : 指定当前关节的名称。
- child_name : 指定要添加的子组件名称。
添加运动学对象 (Kinematics Object)
在initOpenManipulator
函数中,添加了用于控制机械手的*运动学求解算法(kinematics solving algorithm)*,如下所示。
1 | /***************************************************************************** |
*运动学求解算法(kinematics solving algorism)*取决于用户的机械手。因此,robotis_manipulator
的配置是为了让用户可以配置运动学求解器并测试用户的算法。当然,关于串联结构机械手的通用求解算法,open_manipulator_libs
中提供了以下运动学求解器类。
- 使用 Chain Rule 和 Jacobian 的运动学求解器;
- 使用 Chain Rule 和 Singularity Robust Jacobian 的运动学求解器;
- 使用 Chain Rule 和 Singularity Robust Position Only Jacobian 的运动学求解器;
如果用户想把他的算法应用于自己的机械手,用户可以创建一个新的运动学求解器类。这个新的类是通过继承下面的robotis_manipulator::kinematics
类来创建的。
- ```c++
robotis_manipulator::kinematics1
2
3
4
5
6
7
8
9
10
11
12
13
```c++
class Kinematics
{
public:
Kinematics() {}
virtual ~Kinematics() {}
virtual void setOption(const void *arg) = 0;
virtual Eigen::MatrixXd jacobian(Manipulator *manipulator, Name tool_name) = 0;
virtual void solveForwardKinematics(Manipulator *manipulator) = 0;
virtual bool solveInverseKinematics(Manipulator *manipulator, Name tool_name, Pose target_pose, std::vector<JointValue>* goal_joint_position) = 0;
};
OpenManipulator-X机械手使用的kinematics::SolverCustomizedforOMChain
类包括以下内容。
1 | /***************************************************************************** |
为了使用 “robotis_manipulator “的所有API函数,如上面的 “kinematics::SolverCustomizedforOMChain “类中所示,必须将以下每个函数声明为 “虚函数”。
每个虚函数的配置如下所示:
- setOption : 当需要改变运动学求解器的选项时,通过使用
arg
指针参数来配置设置该选项(类成员参数)。 - jacobian : 配置返回
MatrixXd
雅各布矩阵(jacobian matrix),用于设置name
(tool_name)的特定组件的姿势(pose),使用Manipulator
(manipulator)的组件参数(joint_value,relative,joint_constant,等等)。 - solveForwardKinematics : 使用
Manipulator
(manipulator)组件的参数(joint_value,relative,joint_constant,等等),并通过设置每个组件参数的Pose
(pose_from_world)值返回,配置解决机械手的前向运动学。 - solveInverseKinematics : 配置返回
std::vector<JointValue>
goal_joint_value,通过解决逆运动学,将name
tool_name组件的Pose
pose_from_world定位到Pose
target_pose。
添加制动器(舵机)对象
In the initOpenManipulator
function, the actuator classes to be used to control actuators of the manipulator is added as shown below. 在 initOpenManipulator
函数中,添加了用于控制机械手执行器的actuator类,如下所示。
1 | if(using_actual_robot_state) |
使用addJointActuator
函数添加关节的执行器类,使用addToolActuator
函数添加工具的执行器类。使用setJointActuatorMode
和setToolActuatorMode
函数设置这两个类别的控制模式。JointDynamixel
和 GripperDynamixel
类可以与DYNAMIXEL一起使用,否则用户需要为自己的执行器创建 JointActuator
和 ToolActuator
当在一个操纵器中使用不同种类的执行器时,可以添加复数的JointActuator
和ToolActuator
类。
关节制动器类(Joint Actuator Class)
新创建的关节执行器(joint actuator)类是通过继承以下robotis_manipulator::JointActuator
类来创建的。
robotis_manipulator::JointActuator
1 | class JointActuator |
OpenManipulator 使用的 JointDynamixel
类的结构如下所示:
1 | class JointDynamixel : public robotis_manipulator::JointActuator |
为了使用robotis_manipulator
的所有API函数,必须编写以下每个虚拟
函数,如上面的JointDynamixel
类。
每个虚函数的配置如下所示:
init : 配置该函数,以设置本类中要使用的致动器的
std::vector<uint8_t>
actuator_id,并能够使用const void*
arg设置其他所需的设置参数。actuator_id
的值与Set Robot Parameter中设置的值相同。setMode : 将设置为
std::vector<uint8_t>
actuator_id的致动器的模式设置为const void*
arg的值。根据致动器的类型,可能不是必要。getId : 配置返回由
init
函数设置的std::vector<uint8_t>
actuator_id。如果添加了几个JointAcuator
类,它们被用来确定这个对象中包含的执行器的id。enable : 它被用来启用这个类所控制的执行器。要通过
getEnabledState
函数获得启用状态,请在该函数中将成员参数enabled_state_设为true。disable : 它用于禁用这个类所控制的致动器。如果致动器被禁用,即使执行了
sendJointActuatorValue
,致动器也不会移动。要通过`getEnabledState’函数获得启用状态,请在该函数中将成员参数enabled_state_设置为false。sendJointActuatorValue : 当该函数被执行时,配置函数中对应
std::vector<uint8_t>
actuator_id的执行器移动到std::vector<robotis_manipulator::ActuatorValue>
value_vector。在这里,value_vector不是关节的JointValue
,而是不经过减速器的ActuatorValue
。value_vector包含每个执行器的position, velocity, acceleration, 和 effort 。根据执行器的情况,也可以只填写position值,其余的值留空。receiveJointActuatorValue :
配置接收执行器的
std::vector<robotis_manipulator::ActuatorValue>
present actuator values。ActuatorValue
包括每个执行器的position, velocity, acceleration, 和 effort *。这些值在乘以Set Robot Parameter中设定的系数值后,被存储在操纵器参数中。换句话说,它不是 “JointValue”,而是不经过减速器的 “ActuatorValue”。根据作动器的情况,可以只填写位置值,其余部分留空,但它可以通过返回速度和加速度来计算每个部件的 dynamic.pose 值。
Tool Actuator 类
新创建的tool actuator 类是继承了 robotis_manipulator::ToolActuator
类而创建的.
robotis_manipulator::ToolActuator
1 | class ToolActuator |
OpenManipulator使用的GripperDynamixel
类有以下结构。
1 | class GripperDynamixel : public robotis_manipulator::ToolActuator |
为了使用robotis_manipulator
的所有API函数,必须编写以下每个虚拟
函数,如上面GripperDynamixel
类所示。
每个虚函数的配置如下所示:
- init : 配置该函数,以设置该类中要使用的执行器的
uint8_t
actuator_id,并能够使用const void*
arg设置其他所需的设置参数。actuator_id
的值与Set Robot Parameter中设置的值相同。一个ToolActuator
类只能控制一个工具执行器。如果你在操纵器上设置了多个工具,请创建另一个ToolActuator
类,并通过addToolActuator
函数添加。 - setMode : 将设置为
uint8_t
actuator_id的执行器的模式设置为const void*
arg的值。根据执行器的类型,这可能不是必须的。 - getId : 返回在
init
函数中设定的uint8_t
actuator_id,如果添加了几个`ToolAcuator’类,它们被用来确定该对象中包含的执行器的id。 - enable : 它用于启用这个类所控制的执行器(舵机)。为了通过
getEnabledState
函数获得启用状态,在这个函数中把成员参数enabled_state_设为true。 - disable : 它用于禁用这个类所控制的执行器(舵机)。如果执行器被禁用,即使
sendToolActuatorValue
被执行,执行器也不会移动。要通过getEnabledState
函数获得启用状态,请在这个函数中把成员参数enabled_state_设为false。 - sendToolActuatorValue 配置函数,当函数被执行时,
uint8_t
actuator_id执行器移动到robotis_manipulator::ActuatorValue
value。在这种情况下,value不是工具的ToolValue',而是
ActuatorValue’,不经过减速器。value包含执行器的position, velocity, acceleration, 和 effort 。根据执行器的情况,也可以只填写position值,其余的值留空。 - receiveToolActuatorValue 配置接收工具执行器的
robotis_manipulator::ActuatorValue
present actuator value。ActuatorValue
包括执行器的位置、*速度、加速度和努力。这些数值在乘以Set Robot Parameter中设定的系数值后,被存储在操纵器参数中。换句话说,它不是 “工具值”,而是不经过减速器的 “执行器值”。根据作动器的情况,可以只填写位置值,其余部分留空,但它可以通过返回速度和加速度来计算每个部件的动态.姿势*值。
添加自定义轨迹对象
Even if you do not add this trajectory generator class, you can create a basic trajectory (TCP, joint) using a minimum jerk, but you need to add a custom_trajectory class to make the manipulator move along your own trajectory. In the initOpenManipulator
function, add custom_trajectory
to be used to create the manipulator’s path (trajectory) as shown below.
即使你不添加这个轨迹生成器类,你也可以用minimum jerk创建一个基本的轨迹(TCP,joint),但是你需要添加一个custom_trajectory类来使机械手沿着你自己的轨迹移动。在initOpenManipulator
函数中,添加custom_trajectory
,用来创建操纵器的路径(轨迹),如下所示。
1 | /***************************************************************************** |
custom trajectory类是通过addCustomTrajectory
函数添加的,它有CustomJointTrajectory
类的类型,返回JointWaypoint
作为路径值,CustomTaskTrajectory
类返回TaskWaypoint
作为路径值。这些类都是通过继承以下robotis_manipulator::CustomJointTrajectory
和robotis_manipulator::CustomTaskTrajectory
类创建的。
robotis_manipulator::CustomJointTrajectory
1 | class CustomJointTrajectory |
robotis_manipulator::CustomTaskTrajectory
1 | class CustomTaskTrajectory |
当你创建一个继承自上述类的类时,你必须编写以下虚函数来使用通过robotis_manipulator的API函数添加的轨迹。
每个虚函数的配置如下所示:
- makeJointTrajectory, makeTaskTrajectory : 当这个函数被执行时,创建并保存一个轨迹表达式,作为类成员变量,可以在
double
move_time时间内从start到达arg(自由形式)。当执行getJointWaypoint
或getTaskWaypoint
函数时,它应该根据double
tick时间(从开始时间到现在时间的差异)返回JointWaypoint
或TaskWaypoint
。 - setOption : 配置此函数,用于设置一些选项数据,通过使用arg创建路径(轨迹)。
- getJointWaypoint, getTaskWaypoint : 将此函数配置为将
makeJointTrajectory
或MakeTaskTraction
生成的轨迹返回为JointWaypoint
或TaskWaypoint
,以确定tick时间(从开始时间到当前时间的差值)。
在OpenManipulator-X中使用的 “Circle “轨迹类的结构如下:
1 | /***************************************************************************** |
步骤3:设计控制流程函数
使机械手成为控制过程的一个函数。虽然可以直接从控制器软件包中写入,但创建一个控制器软件包是很有用的,它可以通过预先填充主要使用的进程来控制多个相同的机械手。
在 OpenManipulator-X中, 控制流程的函数配置如下:
1 | void OpenManipulator::processOpenManipulator(double present_time) |
goal_joint_value
和goal_tool_value
的值是通过getJointGoalValueFromTrajectory
和getToolGoalValue
从make trajectory函数计算的轨迹中返回。如果你使用了makeTaskTrajectory
函数,逆运动学将在getJointGoalValueFromTrajectory
函数中得到解决。- 通过
receiveAllJointActuatorValue
和receiveAllToolActuatorValue
返回present joint values和tool value。这些值存储在RobotisManipulator
类的manipulator_
成员变量中。 - 通过
sendAllJointActuatorValue
和sendAllToolActuatorValue
函数,将从getJointGoalValueFromTrajectory
和getToolGoalValue
得到的goal_joint_value
和goal_tool_value
值发送给推杆控制器。这将使执行器移动到目标位置。 - Solve the forward kinematics based on the present joint values received through
receiveAllJointActuatorValue
,receiveAllToolActuatorValue
and stored the pose value of components calculated to the manipulator_. 根据通过receiveAllJointActuatorValue
、receiveAllToolActuatorValue
收到的present joint values和存储在*manipulator_*计算出的组件的姿势值,解决正向运动学问题。
步骤4:如何使用
使用你上面创建的类和函数,为机械手配置控制器包。关于控制器上可用的API,见这里。例如,在OpenCR上运行的OpenManipulator-X的控制器包组成如下:
open_manipulator_chain.ino
1 |
|
processing.h
1 |
|
remote_controller.h
1 |
|