目录
硬件接口
ROS 控制使用硬件接口与可用的 ROS 控制器之一结合使用,向硬件发送 ( write() ) 命令并从中接收 ( read() ) 关节状态。
截至撰写本文时可用的硬件接口列表(通过硬件资源管理器):
- 关节命令接口- 支持命令一系列关节的硬件接口。请注意,这些命令可以具有任何语义,只要它们每个都可以由单个双精度数表示即可,它们不一定是努力命令。要指定此命令的含义,请参阅派生类:
- 作用力关节接口 - 用于指挥基于作用力的关节。
- 速度关节接口 - 用于命令基于速度的关节。
- 位置关节接口 - 用于指挥基于位置的关节。
- 关节状态接口 - 支持读取一组指定关节的状态的硬件接口,每个关节都有一些位置、速度和作用力(力或扭矩)。
- 执行器状态接口 - 支持读取一组指定执行器状态的硬件接口,每个执行器都有一定的位置、速度和作用力(力或扭矩)。
- 执行器命令接口
- 作用力执行器接口
- 速度执行器接口
- 位置执行器接口
- 力-扭矩传感器接口
- IMU传感器接口
请注意,hardware_interface::JointCommandInterface允许读取关节状态并命令基于 [effort|velocity|position] 的关节(请参阅此答案)。
设置新机器人
此页面将引导您完成设置新机器人以与控制器管理器配合使用的步骤。当您使机器人支持一个或多个标准接口时,您将能够利用在标准接口上工作的大型控制器库。
使用现有接口
假设我们有一个有 2 个关节的机器人:A 和 B。两个关节都是位置控制的。在这种情况下,您为机器人定义一个hardware_interface::RobotHW ,它应该提供标准的JointPositionInterface和JointStateInterface,以便它可以重用所有已编写的与JointPositionInterface和JointStateInterface一起使用的控制器。代码如下所示:
#include <hardware_interface/joint_command_interface.h>
#include <hardware_interface/joint_state_interface.h>
#include <hardware_interface/robot_hw.h>
// 我的机器人类,继承自RobotHW接口
class MyRobot : public hardware_interface::RobotHW
{
public:
// 构造函数
MyRobot()
{
// 连接并注册关节状态接口
hardware_interface::JointStateHandle state_handle_a("A", &pos[0], &vel[0], &eff[0]);
jnt_state_interface.registerHandle(state_handle_a); //注册"A"关节
hardware_interface::JointStateHandle state_handle_b("B", &pos[1], &vel[1], &eff[1]);
jnt_state_interface.registerHandle(state_handle_b); //注册"B"关节
registerInterface(&jnt_state_interface); //注册关节状态接口
// 连接并注册关节位置接口
hardware_interface::JointHandle pos_handle_a(jnt_state_interface.getHandle("A"), &cmd[0]);
jnt_pos_interface.registerHandle(pos_handle_a); //注册"A"关节位置
hardware_interface::JointHandle pos_handle_b(jnt_state_interface.getHandle("B"), &cmd[1]);
jnt_pos_interface.registerHandle(pos_handle_b); //注册"B"关节位置
registerInterface(&jnt_pos_interface); //注册关节位置接口
}
private:
// 私有成员:关节状态接口和关节位置接口
hardware_interface::JointStateInterface jnt_state_interface;
hardware_interface::PositionJointInterface jnt_pos_interface;
double cmd[2]; //控制命令
double pos[2]; //位置数据
double vel[2]; //速度数据
double eff[2]; //力(效能)数据
};
就是这样!那么这段代码实际上是如何控制你的机器人的呢?上述功能旨在使控制器管理器(以及控制器管理器内的控制器)能够访问机器人的关节状态以及机器人的命令。当控制器管理器运行时,控制器将从机器人中的 pos、vel 和 eff 变量中读取,并且控制器会将所需的命令写入 cmd 变量。您的工作是确保 pos、vel 和 eff 变量始终具有可用的最新关节状态,并且您还需要确保机器人执行写入 cmd 变量的所有内容。为此,您可以向机器人类添加 read() 和 write() 函数。在你的 main() 中,你会做这样的事情:
main()
{
MyRobot robot;
controller_manager::ControllerManager cm(&robot);
while (true)
{
robot.read();
cm.update(robot.get_time(), robot.get_period());
robot.write();
sleep();
}
}
正如上图所示,您当然不限于仅从一个接口继承。您的机器人可以提供任意数量的接口。例如,您的机器人可以提供“PositionJointInterface”和“VelocityJointInterface”等等。
创建机器人专用界面
如果您不想为机器人编写一套全新的控制器,并且想利用现有控制器的库,那么标准接口非常棒。但是,如果您的机器人具有标准接口不支持的某些功能怎么办?这是否意味着您根本无法使用标准接口?你猜怎么着,事实证明你可以两者兼得!您可以使用标准接口(并重复使用标准控制器)来实现机器人的标准功能。同时,您可以在特定于机器人的界面中公开特定于机器人的功能。再看一下上图,看看它如何显示具有标准接口和机器人专用接口的机器人。
对于这种情况,代码是什么样的?
class MyRobot : public hardware_interface::RobotHW
{
public:
// 构造函数
MyRobot()
{
// 注册关节状态和位置接口
...
... // 此处的 ... 表示上一个例子中提到的代码,具体请参考前面的代码示例
...
// 注册一些机器人特有的接口
registerInterface(&cool_interface); // 注册自定义的“cool_interface”接口
}
private:
MyCustomInterface cool_interface; // 定义一个名为 cool_interface 的私有成员,类型为 MyCustomInterface
};
或者...您可以注册 MyRobot 类本身:
class MyRobot : public hardware_interface::RobotHW, public hardware_interface::HardwareInterface
{
public:
// 构造函数
MyRobot()
{
// 注册关节状态和位置接口
...
... // 此处的 ... 表示前面示例代码中的内容,具体请参考之前的代码注释
...
// 注册 MyRobot 类本身,以便使 'someCoolFunction' 函数可用
// MyRobot 类继承自 HardwareInterface,这样才能做到这一点
registerInterface(this);
}
// 定义一个函数
void someCoolFunction();
};
因此,自定义接口只不过是向机器人类添加任意数量的函数调用,并注册机器人类本身。这些机器人特定的功能仅适用于专门为您的机器人设计的控制器,但与此同时,您的机器人仍将使用机器人的标准接口与标准控制器配合使用。
资源管理
控制器管理器跟踪每个控制器正在使用哪些资源。资源可以是“right_elbow_joint”、“base”、“left_arm”、“wrist_joints”等。几乎任何您想用于您的特定机器人的东西。资源在硬件接口中指定。例如,!PositionJointInterface 使用关节名称作为资源。您当然可以实现自己的硬件接口,并定义自己的资源。当控制器初始化时,它们会从硬件接口请求大量资源;这些请求由控制器管理器记录。因此控制器管理器确切地知道哪个控制器请求了哪些资源。
RobotHW 类有一个简单的资源管理默认实现:它只是防止两个使用相同资源的控制器同时运行。请注意,使用相同资源的两个控制器可以同时加载,但不能同时运行。如果这个简单的资源管理方案适合您的机器人,您无需执行任何操作,控制器管理器将自动应用此方案。如果您的机器人需要不同的方案,您可以通过实现一个函数轻松创建自己的方案:
class MyRobot : public hardware_interface::RobotHW
{
public:
MyRobot()
{
// 注册硬件接口 接口
...
...(参见上面的代码)
...
// 实现机器人特定的资源管理
bool checkForConflict(const std: :list<ControllerInfo>& info) const
{
// 该控制器列表不能同时运行
...
return true;
// 该列表中的控制器可以同时运行
...
return false;
}
}
};
checkForConflict 方法的输入是控制器信息对象的列表。这些对象中的每一个都与一个控制器匹配,并包含有关该控制器的所有信息。此信息包括控制器名称、控制器类型、硬件接口类型以及控制器声明的资源列表。基于所有这些信息,您可以提出自己的方案来决定是否允许给定的控制器列表同时运行。
参考链接:https://github.com/ros-controls/ros_control/wiki/hardware_interface