完整教程:ros_control 中 hardware_interface 教程

news/2025/10/25 21:27:53/文章来源:https://www.cnblogs.com/slgkaifa/p/19165997

完整教程:ros_control 中 hardware_interface 教程

各个网站上找了一圈,没发现ROS Hardware_Interface的比较好的教学资料,ROS Wiki写的又看不大懂。索性花了一个下午时间,边和Gemini对话边查找资料,把这部分内容认真梳理了一遍,写成了一篇教程。可能有不完善的地方,也欢迎指教。


hardware_interface 是 ros_control 大框架下的一个重要组成部分。hardware_interface 的架构基于以下几个核心概念:

  • 资源 (Resource): 机器人上任何可以被独立控制或读取的单元。最常见的资源是“关节”(Joint),但也可以是其他任何东西,如致动器(Actuator)、传感器(IMU Sensor)、或一个简单的GPIO引脚。

  • 句柄 (Handle): 对单个资源的直接访问凭证。控制器通过句柄来读取特定资源的状态(如关节角度)或向其发送指令(如关节目标速度)。句柄确保了资源的访问是受控且唯一的。

  • 接口 (Interface): 一组特定类型资源的管理集合。一个 Interface 中拥有并管理一系列同类型的Handel。它为控制器提供了访问和控制这些资源的方法。

下面进行详细讲解。请注意,hardware_interface一般指这个整体框架,而 interface 或 HardwareInterface 则主要指其中的接口部分。

概述

hardware_interface 的架构主要由以下几个C++类和概念构成:

a. hardware_interface::RobotHW

这是用户与 hardware_interface 交互最主要的类。开发者需要继承这个基类,并为自己的特定机器人实现一个具体的硬件接口类。这个派生类是连接 ros_control 框架和物理硬件的桥梁。

RobotHW 类有两个至关重要的虚函数,必须由用户实现:

b. RobotHW::registerInterface()

在具体代码实现中,我们通过 RobotHW 基类中提供的 registerInterface() 方法,注册和管理机器人支持的所有硬件接口。read、write则是通过这些接口,调用硬件的SDK,对硬件的状态进行读取或者写入。例如:

registerInterface(&hybridJointInterface_);
c. 标准硬件接口 (Standard Hardware Interfaces)

hardware_interface 给定了硬件接口标准形式,基类 hardware_interface::HardwareInterface。

ros_control 框架继承该接口,定义了一系列标准接口:
hardware_interface::JointStateInterface
hardware_interface::ImuSensorInterface
等等.此外,也可以自己定义.

资源 (Resource)

资源 通常对应一个物理实体,比如一个关节电机、一个IMU传感器、一个力传感器或者一个线性的致动器。

资源最重要的是管理,每个资源都必须有一个唯一的字符串名称(例如 “shoulder_pan_joint”, “left_wheel_joint”)。这个名称是整个 ros_control 生态系统(包括URDF、控制器配置文件、RobotHW代码)中识别该资源的关键。例如,ros中,hardware_interface::HardwareInterface 中的 claim_ 用于检测资源的唯一所有性,就是通过维护一个已注册资源的字符串列表,来检查资源是否已经被其他的Handle所有了.再次强调,检查是由Interface进行的.

但是,对于关节 Joint1,我们既需要一个Handle获取其状态,又需要一个Handle来管理发送指令给这个关节,是否会造成冲突呢?答案是不会的.对于一个Interface,如果其定义为:

class JointSomeHandle;
class JointSomeInterface: public HardwareResourceManager<JointSomeHandle, hardware_interface::DontClaimResources>

此时,claim() 和 clearClaims() 方法都是空操作(No-op),它们被调用时什么也不做。也就是不检查其所有权.对于读类型的Interface而言,如JointStateInterface,就是采取的这种定义方式.

而如果采用的是:

class JointSomeHandle;
class JointSomeInterface: public HardwareResourceManager<JointSomeHandle, hardware_interface::ClaimResources>

ClaimResources内部维护着一个私有的资源列表,在初始化的时候会将注册在这个Interface下的Handle所指向的资源加入其私有资源列表中.

现在,当一个控制器 joint_state_controller 启动并请求 JointStateInterface 时,ControllerManager就会先检查这个 Interface 在 RobotHW 中真的已经被创建.如果是,检查该Interface 是 DontClaimResources,就直接将这个 Interface 的指针传给这个控制器了.如果对于某一个Interface(如JointCommadInterface),检查其内部是 ClaimResources,则会将其内部的私有资源列表与中央资源列表对比,如果没有重复 Claim,则将接口给Controller,并将私有资源列表加入到中央资源列表中.

句柄 (Handle)

总结来说,对于hardware_interface而言,句柄是向上的接口,用于与控制器通信;硬件SDK是向下的接口,用于与真实硬件或者仿真环境中的物理资源进行交互。由于一般而言机器人有交互的硬件部分较多,所需的句柄较多,我们需要 HardwareInterface 对向上接口 Handle 进行统一管理。

下面的图像表述了句柄的创建与使用流程。
请添加图片描述

Handel的创建流程

步骤一:声明数据存储 (The Data Buffers)

// In MyRobotHW.h
class MyRobotHW : public hardware_interface::RobotHW {
private:
// 为N个关节声明数据存储
// 这些就是“共享内存”
std::vector<double> joint_positions_;std::vector<double> joint_velocities_;std::vector<double> joint_efforts_;std::vector<double> joint_commands_;std::vector<std::string> joint_names_; // 资源名称列表int num_joints_; // 资源数量};

步骤二:绑定数据并实例化 Handle (The Binding)

值得注意的是,Handle 并没有一个统一的基类.例如下面的JointStateHandle.

// In MyRobotHW.cpp (Constructor or init() method)
MyRobotHW::MyRobotHW() {
// 假设我们从参数服务器或配置文件中获取了关节名和数量
// num_joints_ = ...; joint_names_ = ...;
// 为数据存储分配空间
joint_positions_.resize(num_joints_);
for (int i = 0; i < num_joints_; ++i) {
// 1. 为 "joint_names_[i]" 这个资源创建一个 JointStateHandle
hardware_interface::JointStateHandle state_handle(
joint_names_[i],
&joint_positions_[i],              // 指向其位置状态数据的指针
&joint_velocities_[i],             // 指向其速度状态数据的指针
&joint_efforts_[i]                 // 指向其力矩状态数据的指针
);
// ... state_handle 被创建 ...
// 2. 为 "joint_names_[i]" 这个资源创建一个指令Handle (以Position为例)
//    它复用 state_handle 的信息,并额外绑定指令数据变量的地址
hardware_interface::JointHandle command_handle(
state_handle,                      // 传入刚才创建的状态句柄
&joint_commands_[i]                // 指向其指令数据的指针
);
// ... command_handle 被创建 ...
}
}

步骤三:向 Interface 注册 Handle (The Registration)

// In MyRobotHW.cpp (继续在循环中)
for (int i = 0; i < num_joints_; ++i) {
// ... state_handle 和 command_handle 被创建 ...
// 3. 将 Handle 注册到对应的 Interface 中
//    Interface 会以资源名为索引存储这些Handle
jnt_state_interface_.registerHandle(state_handle);
pos_jnt_interface_.registerHandle(command_handle); // 假设是位置控制
}
// 循环结束后,将整个Interface注册到RobotHW基类中
registerInterface(&jnt_state_interface_);
registerInterface(&pos_jnt_interface_);
句柄的使用

上面已经基本将句柄的基本使用方式讲清楚了。下面我们做一个摘要:

Handle的创建

hardware_interface::JointHandle command_handle(
state_handle,                      // 传入刚才创建的状态句柄
&joint_commands_[i]                // 指向其指令数据的指针
);

Handle的注册
总是需要将Handle先注册到 HardwareInterface 中,此后控制器在通过 HardwareInterface 按照名称获取Handel。

jnt_state_interface_.registerHandle(state_handle);
registerInterface(&jnt_state_interface_);

Handle的调用

joint_handle_ = HwInterface->getHandle(joint_name);

接口 (Interface)

Interface 和 Handle 是典型的 容器与元素 的关系。

  1. 包含关系: 一个 Interface 包含零个或多个 Handle。
  2. 访问流程:
    • 硬件侧 (RobotHW): Handle 被创建 -> Handle 被注册到 Interface 中。
    • 控制器侧 (Controller): 请求 Interface -> 从 Interface 中根据名称请求 Handle -> 使用 Handle 读/写数据。
  3. 类型约束: 一个 Interface 只能管理一种类型的 Handle。例如,JointStateInterface 只管理 JointStateHandle,不能将一个用于指令的 JointHandle 注册进去。

请添加图片描述

上面资源部分已经讲解了Interface对资源的Claim操作,保证 具有写操作等互斥操作的Handle 被唯一获取.下面将进一步对 Interface 讲解.

Interface的创建与注册

// MyRobotHW.h
class MyRobotHW : public hardware_interface::RobotHW {
private:
hardware_interface::PositionJointInterface pos_jnt_interface_;
hardware_interface::JointStateInterface    jnt_state_interface_;
};
// MyRobotHW.cpp
MyRobotHW::MyRobotHW() {
// ... 创建 state_handle 和 command_handle ...
jnt_state_interface_.registerHandle(state_handle);
pos_jnt_interface_.registerHandle(command_handle);
registerInterface(&jnt_state_interface_);
registerInterface(&pos_jnt_interface_);
}

在Controller中获取Interface

// MyController.cpp
bool MyController::init(hardware_interface::RobotHW* robot_hw, ...) {
// 获取只读接口,总会成功 (只要接口存在)
auto* state_if = robot_hw->get<hardware_interface::JointStateInterface>();// 获取独占接口,会触发资源冲突检查auto* pos_if = robot_hw->get<hardware_interface::PositionJointInterface>();if (!pos_if) {ROS_ERROR("Failed to get PositionJointInterface.");return false;}// ... 通过接口获取Handle ...}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

飞牛NAS的SSL证书过期,又开启了强制HTTPS,进不去界面修改SSL怎么办? - 详解

飞牛NAS的SSL证书过期,又开启了强制HTTPS,进不去界面修改SSL怎么办? - 详解2025-10-25 21:21 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow…

多表查询-练习

-- 多表查询-练习1 -- 1.查询员工的姓名、年龄、职位、部门信息。(隐式内连接) select e.name,e.age,e.job,d.* from emp e ,dept d where e.dept_id = d.id; -- 2.查询年龄小于30岁的员工姓名、年龄、职位、部门信息。…

多智能体大模型在农业中的应用研究与展望

研究意义 首次系统提出“多智能体 大语言模型”在农业中的完整技术框架,为“耕-种-管-收”全流程智能化、无人化提供理论+落地路线。 技术框架• 多智能体系统(MAS)=“角色分工 + 动态协作 + 分布式决策”。 • 大…

嵌入式基础作业--第七周--IIC协议采集温湿度与OLED显示

任务一. 解释什么是“软件I2C”和“硬件I2C” 根据野火教材第23章"IC--读写EEPROM"的内容,详细解释软件I2C和硬件I2C的概念和区别: I2C总线基础 I2C(Inter-Integrated Circuit)是一种两线式串行总线,包…

Nature子刊 | 基于生物学信息的神经网络

机器学习模型在多组学数据中的应用常常需要在预测准确性与生物学可解释性之间进行权衡。一种新兴的深度学习架构通过结构化地编码生物学知识,以提升预测能力和可解释性。然而,更广泛地采用这种架构仍面临着机遇与挑战…

2025年项目总延期?这30款项目进度管理软件一定有一款适合你!

项目总延期是困扰团队效率的常见难题,但选对工具能让交付率提升至85%以上。本文将为您精选30款高效的项目进度管理软件,覆盖从敏捷开发到传统瀑布模型的不同需求。无论是Codes的全流程管控、Jira的敏捷适配性,还是T…

Educational Codeforces Round 66 (Rated for Div. 2) A~F

A - From Hero to Zero 模拟。 能除 \(k\) 直接除 \(k\),否则减掉余数部分。点击查看代码 #include <bits/stdc++.h>using i64 = long long;void solve() {i64 n, k;std::cin >> n >> k;i64 ans = …

小程序原创--基于微信开发者工具实现的猜谜游戏程序 - 教程

小程序原创--基于微信开发者工具实现的猜谜游戏程序 - 教程2025-10-25 21:07 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !importan…

stm32使用SPI外设读取W25Q32芯片

void SPI_GPIO_Init(void) {//SPI2-NSS PB12:PIN25 --CS//SPI2-SCK PB13:PIN26//SPI2-MISO PB14:PIN27 W25Q32:DO//SPI2-MOSI PB15:PIN28 W25Q32:DIGPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef …

Avjinder Singh Kaler | 数量遗传学基础

研究对象与核心思想• 数量遗传学研究数量性状(如身高、产量等连续变异性状)的遗传规律。 • 特点:受多基因控制,且环境效应显著。单基因模型基础• 单基因模型是数量遗传理论的起点,假设一个基因位点有两个等位基…

鲁东大学提出可解释的自适应集成机器学习全基因组选择算法用于小麦产量性状关键SNPs筛选

研究背景 全基因组选择(genomic selection, GS)是现代分子育种中的一项重要技术,作为一种强大的机器学习GS方法,堆叠集成学习(stacking ensemble learning, SEL)有效地融合了不同模型(基学习器)的优势,以精确…

台球厅收银台押金原路退回系统押金预授权—东方仙盟 - 详解

台球厅收银台押金原路退回系统押金预授权—东方仙盟 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consol…

数论专题小记

我的数论以前一只因为对数字的恐惧而搁置,准备这几天补回来 /kk。 狄利克雷卷积&莫比乌斯反演我们定义 狄利克雷卷积 这种运算是把两个数轮函数 \(f,g\) 卷成另一个函数 \(t\),其中 \(t\) 满足: \(\ \ \ \ \ \ …

ReactUse 与ahook对比 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

机械臂和相机的9点标定原理

9点标定到底怎么工作的? 这个问题困惑了我很久,虽然想海康VisionMaster 和Halcon 这种软件都提供了很好用的工件,但是最好懂原理,这样才不仅能做项目,还能做好项目。 最近好好研究了一下,感觉是搞清楚了,就记录…

遗传改良中的核心技术:交配设计

分享一则报告,系统总结了植物育种中常用的交配设计(Mating Designs)方法。定义与目的定义:交配设计是指为产生后代而在植物群体间有计划的杂交方案。目的:理解性状或行为的遗传控制机制;为作物品种开发提供基础群…

语言是火,视觉是光:论两种智能信号的宿命与人机交互的未来 - 教程

语言是火,视觉是光:论两种智能信号的宿命与人机交互的未来 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: &quo…

书籍推荐 | 《数量遗传学》(王建康)

数量遗传学是智能育种必学课程,这里推荐一本由中国农科院作物科学研究所王建康老师主编的教材。本书系统介绍群体遗传与数量遗传的基本理论及其在动植物育种中的应用。全书分群体遗传、数量遗传、育种应用和基因定位四…

Plant Com | 一种新的多源数据(基因组、表型和跨环境)融合的基因组预测框架-GPS

基因组选择(GS)和表型选择(PS)被广泛用于加速植物育种。然而,在处理处理复杂性状时,这两种选择方法的准确性、稳健性和可转移性尚未得到充分探索。近日,南京农业大学丁艳锋团队在Plant Communications发表题为G…

分享二个实用正则

正则表达式是一种用于匹配和操作文本的强大工具。它由一系列字符和特殊字符组成,用于描述要匹配的文本模式。最近看到二个我觉得很实用的正则使用方式,一起来看看吧前言 正则表达式(Regular Expression,简称regex或…