ros_control 介绍

简介: ros_control 脱胎于pr2 的 硬件封装层部分 pr2_mechanism,经过pal-robotics 和 hidof 两个公司的工程师进行了改写,变得适用于所有机器人的硬件封装库,负责统一管理硬件驱动与传感器底层细节,处理异常,分配资源,向上提供统一接口。作为一个end2end的ROS 机器人系统集成解决方案

来源

ros_control 脱胎于pr2 的 硬件封装层部分 pr2_mechanism,经过pal-robotics 和 hidof 两个公司的工程师进行了改写,变得适用于所有机器人的硬件封装库,负责统一管理硬件驱动与传感器底层细节,处理异常,分配资源,向上提供统一接口。作为一个end2end的ROS 机器人系统集成解决方案。

优势

ros_control 是一个类库!! 并不是直接的工具库,需要自己写程序继承特定基类来做到接口的统一。

Ros_control 使用的最直接好处是可以复用 ros-controllers 里面的一些控制算法,以及与支持ros_control的仿真器 gazebo 的良好支持。

缺点

ros_control 框架最大的问题,很多模块严重冗余,很多部分设计突出一个没必要,架构过于复杂,很多模块象征意义大于实际意义,更多是提供一个系统集成的思路或者雏形,具体完善到工业级还得好长的路要走,学习曲线陡峭没文档。

基本架构

在这里插入图片描述
基本架构是这样的:

机器人的硬件通讯库(串口,can, ethercat, 等等)

ros_control 的robot_hw部分

controller_manager 部分 与具体的 controller

controller 部分就会提供给ROS系统中其他上层组件标准控制与感知接口,比如 topic : cmd_vel,joint/command action:trajectory_server 等等。

简单实例

Controller_manager 与很多controller都已经很完善了,需要写的就是robothw部分

一个最简单的ros_control例子:

https://github.com/ros-controls/ros_controllers/blob/indigo-devel/diff_drive_controller/test/diffbot.h

https://github.com/ros-controls/ros_controllers/blob/indigo-devel/diff_drive_controller/test/diffbot.cpp

在diffbot.h 中定义了一个双轮差速小车的模型。
Diffbot 类中定义了小车的joint 信息(位置,速度,扭矩? 力? ,pos, vel,effort),来描述关节的状态,在这里插入图片描述
又定义了cmd来存储对关节的控制量。
在这里插入图片描述
设置了不同的hardware_interface对相应数据进行注册,
在这里插入图片描述
然后将不同的控制接口注册到robothw上.
在这里插入图片描述
实现了 两个虚方法 read 和write ,因为是个demo,所以处理数据非常简单。
源码如下

template <unsigned int NUM_JOINTS = 2>
class Diffbot : public hardware_interface::RobotHW
{
public:
  Diffbot()//构造函数
  : running_(true)
  , start_srv_(nh_.advertiseService("start", &Diffbot::start_callback, this))
  , stop_srv_(nh_.advertiseService("stop", &Diffbot::stop_callback, this))
  {
    // Intialize raw data  //初始化原始数据  在私有部分有声明该四个变量
    std::fill_n(pos_, NUM_JOINTS, 0.0);
    std::fill_n(vel_, NUM_JOINTS, 0.0);
    std::fill_n(eff_, NUM_JOINTS, 0.0);
    std::fill_n(cmd_, NUM_JOINTS, 0.0);

    // Connect and register the joint state and velocity interface
    for (unsigned int i = 0; i < NUM_JOINTS; ++i)
    {
      std::ostringstream os;
      os << "wheel_" << i << "_joint";

// 设置不同的hardware_interface对应数据 并 进行注册,
      hardware_interface::JointStateHandle state_handle(os.str(), &pos_[i], &vel_[i], &eff_[i]);//设置jointstate 接口数据
      jnt_state_interface_.registerHandle(state_handle);

      hardware_interface::JointHandle vel_handle(jnt_state_interface_.getHandle(os.str()), &cmd_[i]);//设置joint vel handle 接口数据
      jnt_vel_interface_.registerHandle(vel_handle);
    }
     //进行注册
    registerInterface(&jnt_state_interface_);
    registerInterface(&jnt_vel_interface_);
  }

  ros::Time getTime() const {return ros::Time::now();}
  ros::Duration getPeriod() const {return ros::Duration(0.01);}

  void read()
  {
    std::ostringstream os;
    for (unsigned int i = 0; i < NUM_JOINTS - 1; ++i)
    {
      os << cmd_[i] << ", ";
    }
    os << cmd_[NUM_JOINTS - 1];

    ROS_INFO_STREAM("Commands for joints: " << os.str());
  }

  void write()
  {
    if (running_)
    {
      for (unsigned int i = 0; i < NUM_JOINTS; ++i)
      {
        // Note that pos_[i] will be NaN for one more cycle after we start(),
        // but that is consistent with the knowledge we have about the state
        // of the robot.
        pos_[i] += vel_[i]*getPeriod().toSec(); // update position
        vel_[i] = cmd_[i]; // might add smoothing here later
      }
    }
    else
    {
      std::fill_n(pos_, NUM_JOINTS, std::numeric_limits<double>::quiet_NaN());
      std::fill_n(vel_, NUM_JOINTS, std::numeric_limits<double>::quiet_NaN());
    }
  }

  bool start_callback(std_srvs::Empty::Request& /*req*/, std_srvs::Empty::Response& /*res*/)
  {
    running_ = true;
    return true;
  }

  bool stop_callback(std_srvs::Empty::Request& /*req*/, std_srvs::Empty::Response& /*res*/)
  {
    running_ = false;
    return true;
  }

private:
  hardware_interface::JointStateInterface    jnt_state_interface_;//声明joint state 接口 类内部实例
  hardware_interface::VelocityJointInterface jnt_vel_interface_;//声明joint vel接口 类内部实例
  double cmd_[NUM_JOINTS];//存储对关节的控制量
  double pos_[NUM_JOINTS];//joint位置信息
  double vel_[NUM_JOINTS];//joint速度信息
  double eff_[NUM_JOINTS];//joint力信息
  bool running_;

  ros::NodeHandle nh_;
  ros::ServiceServer start_srv_;
  ros::ServiceServer stop_srv_;
};

在diffbot.cpp 中给出了ros_control的运行流程

将Diffbot (继承于hardware_interface::RobotHW)类传给ControlerManager,ControlerManager会查看相对应hardware_interface,使用的时候通过service告诉controller_manager load对应类型及其相应的参数(launch文件种),启动controller,即可

源码如下

// ROS
#include <ros/ros.h>

// ros_control
#include <controller_manager/controller_manager.h>

#include "diffbot.h"

int main(int argc, char **argv)
{
  ros::init(argc, argv, "diffbot");
  ros::NodeHandle nh;

  Diffbot<> robot;
  ROS_WARN_STREAM("period: " << robot.getPeriod().toSec());
  controller_manager::ControllerManager cm(&robot, nh);

  ros::Rate rate(1.0 / robot.getPeriod().toSec());//制定数据更新周期
  ros::AsyncSpinner spinner(1);
  spinner.start();
  while(ros::ok())
  {
    robot.read();//读数据
    cm.update(robot.getTime(), robot.getPeriod());//更新数据
    robot.write();//将更新过的数据写数据
    rate.sleep();
  }
  spinner.stop();

  return 0;
}

ros_control核心概念

hardware_interface:作为ros_control组件最重要的一部分,做了以下抽象:

将能动的部分(类似于机器人关节)抽象为joint,joint类型有旋转,平动,固定等等。
执行器模型抽象为actuator,与joint不同的是actuator的属性值需要一定变换才能对应到joint可以理解为电机减速,或者机构传动。

根据不同的控制方式或者不同的传感器暴露出相应的数据接口,一般移动机器人底盘是速度闭环,而机械臂上是位置闭环,根据这些控制方法的不同分出了不同的控制接口,暴露给上层的controller。

作为机器人的硬件资源与上层的直接接口,可以被运行时产生与删除,结合机器人本身的通讯组件这样实际上实现了一种机器人硬件资源的低层次管理。

而hardware_interface 具体实现方式是存储对应状态变量的指针,用字符串表示不同的joint与 Actuator 资源。robothw 基类是 硬件通讯库与hardware_interface交互的部分。硬件通讯库具体的读写过程都在read 与 write 两个虚方法中实现,更新的数据放在robothw类的成员变量中,这些存储着joint 与actuator 状态与命令的空间被hardware_interface索引,传给controller_manager ,通过controller_manager的接口将数据接给controller。所以ros_control内部不存在进程间通讯。

相关实践学习
使用ROS创建VPC和VSwitch
本场景主要介绍如何利用阿里云资源编排服务,定义资源编排模板,实现自动化创建阿里云专有网络和交换机。
ROS入门实践
本课程将基于基础设施即代码 IaC 的理念,介绍阿里云自动化编排服务ROS的概念、功能和使用方式,并通过实际应用场景介绍如何借助ROS实现云资源的自动化部署,使得云上资源部署和运维工作更为高效。
相关文章
|
监控 安全 JavaScript
网络安全开发架构之基于规则引擎的开发架构
规则引擎是一种软件工具或库,用于管理和执行业务规则。它提供了一种灵活且可扩展的方式来处理复杂的业务逻辑、决策制定和规则管理。规则引擎使得规则的定义、配置和执行变得更加可管理和可维护
1132 0
|
存储 Ubuntu C语言
Ubuntu 软件安装方法(入门必看)
Ubuntu 软件安装方法(入门必看)
1401 0
Ubuntu 软件安装方法(入门必看)
|
传感器 NoSQL 算法
ROS Moveit 配置全网最详细教程
本文是关于ROS Moveit配置的全网最详细教程,提供了一键安装脚本,以及如何使用Moveit进行机器人运动规划的详细步骤和说明。文中还深入解析了Moveit的配置包文件、Moveit的源码,以及如何使用不同的运动规划算法(如CHOMP、LERP、STOMP)进行路径规划。
3769 1
ROS Moveit 配置全网最详细教程
|
计算机视觉
树莓派开发笔记(五):GPIO引脚介绍和GPIO的输入输出使用(驱动LED灯、检测按键)
树莓派开发笔记(五):GPIO引脚介绍和GPIO的输入输出使用(驱动LED灯、检测按键)
树莓派开发笔记(五):GPIO引脚介绍和GPIO的输入输出使用(驱动LED灯、检测按键)
|
Ubuntu 机器人 虚拟化
Ubuntu22.04配置ROS2 Humble
这篇文章是关于如何在Ubuntu 22.04系统上配置ROS2 Humble的详细教程,包括虚拟机安装、环境配置、网络设置、软件源更换、ROS1和ROS2的安装步骤。
8805 1
|
Ubuntu Linux 定位技术
在Ubuntu 20.04系统安装Matlab R2021a步骤
希望你可以充分享受这场旅行,从无知的迷雾中找到通向智慧的路。好好装备你的 Linux 旅行箱吧,因为还有很多其他的知识世界等待你去探索和征服。在知识的海洋里,只有勇敢的探索者才能找到自己的道路。快乐旅行!
1574 23
|
人工智能 算法 安全
深度讲解-互联网算法备案指南和教程
随着人工智能和大数据技术的发展,互联网算法在内容推荐、用户画像等领域日益重要,但也带来了安全风险和合规挑战。国家互联网信息办公室为此发布了《互联网算法备案管理规定》,要求具有舆论属性或社会动员能力的互联网信息服务提供者进行算法备案,以确保算法透明性和合规性,维护网络健康秩序。唯安创远AI合规专家将解析备案的必要性、流程及其对企业的影响,帮助企业顺利完成备案。
1613 3
|
Java Linux API
Linux设备驱动开发详解2
Linux设备驱动开发详解
465 6
|
消息中间件 算法 Unix
Linux设备驱动开发详解1
Linux设备驱动开发详解
720 5
|
Rust 监控 网络协议
EtherCAT主站IgH解析(一)--主站初始化、状态机与EtherCAT报文
本文介绍了IgH EtherCAT Master整体运行原理
3578 0
EtherCAT主站IgH解析(一)--主站初始化、状态机与EtherCAT报文