关于ROS_Contorller的详解

2018-11-09  本文已影响0人  insist_coder

ROS_Control框架介绍

官方给出的ros_control的框架图
  1. Controller:一个机器人包含多个controller,类似ros_controllers中现提供的、effort_controllersjoint_state_controllerposition_controllersvelocity_controllersjoint_trajectory_controllers,不同的controller可以完成对不同模块的控制。例如完成对关节力的控制、速度控制等等。请求下层的硬件资源,并提供PID控制器,读取底层硬件资源的状态,发送控制指令。
  1. Controller Manager:顾名思义,用来管理和控制各个controller的管理器,其主要提供统一的接口来管理不同的manager。

  2. Hardware Rescource:为上下两层提供硬件资源的接口,内部有一个hardware resource manager来完成硬件资源管理。

  3. RobotHW:硬件抽象层和硬件直接打交道,通过write和read方法来完成硬件的操作,这一层也包含关节限位、力矩转换、状态转换等功能。

  4. Real Robot:实际的机器人上也需要有自己的嵌入式控制器,接收到命令后需要反映到执行器上,比如接收到位置1的命令后,那就需要让执行器快速、稳定的到达位置。

contorller_manager

此处我们看一下controller_manager.cpp的源码,可以看出通过一个控制机器加载器工具来进行初始化之后,最后再通过订阅六个service,完成了controller_manager的初始化,六个service分别是list_controllers、list_controller_types、load_controller、unload_controller、switch_controller、reload_controller_libraries,从其名字的字面意思也不难理解这六个服务的作用是什么。

加载控制器时,controller_manager将使用控制器名称作为所有控制器特定参数的根,最重要的是,标识要加载哪个插件的类型。控制器管理器提供与控制器交互的基础框架。根据你是从启动文件,命令行还是ROS节点运行控制器,控制器管理器提供不同的工具来运行控制器。

ControllerManager::ControllerManager(hardware_interface::RobotHW *robot_hw, const ros::NodeHandle& nh) :
  robot_hw_(robot_hw),
  root_nh_(nh),
  cm_node_(nh, "controller_manager"),
  start_request_(0),
  stop_request_(0),
  please_switch_(false),
  current_controllers_list_(0),
  used_by_realtime_(-1)
{
  // create controller loader
  controller_loaders_.push_back( 
    ControllerLoaderInterfaceSharedPtr(new ControllerLoader<controller_interface::ControllerBase>("controller_interface",
                                                                                                  "controller_interface::ControllerBase") ) );

  // Advertise services (this should be the last thing we do in init)
  srv_list_controllers_ = cm_node_.advertiseService("list_controllers", &ControllerManager::listControllersSrv, this);
  srv_list_controller_types_ = cm_node_.advertiseService("list_controller_types", &ControllerManager::listControllerTypesSrv, this);
  srv_load_controller_ = cm_node_.advertiseService("load_controller", &ControllerManager::loadControllerSrv, this);
  srv_unload_controller_ = cm_node_.advertiseService("unload_controller", &ControllerManager::unloadControllerSrv, this);
  srv_switch_controller_ = cm_node_.advertiseService("switch_controller", &ControllerManager::switchControllerSrv, this);
  srv_reload_libraries_ = cm_node_.advertiseService("reload_controller_libraries", &ControllerManager::reloadControllerLibrariesSrv, this);
}

可以使用controller_manager脚本从命令行与controller_manager进行交互,command包括:
load: 加载一个控制器(创建和初始化,但是不启动)
unload: 卸载一个控制器(销毁)
start: 启动一个控制器
stop: 停止一个控制器
spawn: 加载并启动一个控制器
kill: 停止并卸载一个控制器

rosrun controller_manager controller_manager <command> <controller_name>

要获取控制器的状态,command包括:
list: 按照执行顺序列出所有控制器,并给出每个控制器的状态
list-types: 列出控制器管理器知道的所有控制器类型。如果控制器不在此列表中,将无法获取。
reload-libraries: 重新加载所有可用作插件的控制器库。当您开发控制器并且想要测试新的控制器代码时,这很方便,而无需每次都重新启动机器人。而且不会重新启动之前运行的控制器
reload-libraries --restore: 重新加载所有可用作插件的控制器库,并将所有控制器恢复到其原始状态

rosrun controller_manager controller_manager <command>

还有其他命令行脚本工具来帮住我们完成不同的任务,具体的可以参考官网给出的说明,就不在此处进行罗列了。

我们还可以通过launch文件来启动我们的控制器,上面的一种是加载并启动,第二种是仅加载不启动。

<launch>
   <node pkg="controller_manager"
         type="spawner"
         args="controller_name1 controller_name2" />
 </launch>

<launch>
   <node pkg="controller_manager"
         type="spawner"
         args="--stopped controller_name1 controller_name2" />
 </launch>

还可以通过图形界面的方式对控制器进行操作,以图形方式加载,卸载,启动和停止控制器,以及显示加载的有关控制器的信息。

rosrun rqt_controller_manager rqt_controller_manager

controller_interface

#ifndef CONTROLLER_INTERFACE_CONTROLLER_H
#define CONTROLLER_INTERFACE_CONTROLLER_H

#include <controller_interface/controller_base.h>
#include <hardware_interface/internal/demangle_symbol.h>
#include <hardware_interface/robot_hw.h>
#include <hardware_interface/hardware_interface.h>
#include <ros/ros.h>


namespace controller_interface
{

/* 
 *具有特定硬件接口的控制器
 * 模板类,该控制器使用的硬件接口类型。这强制了控制器与其要控制的硬件之间的语义兼容性。
 */
template <class T>
class Controller: public virtual ControllerBase
{
public:
  Controller()  {state_ = CONSTRUCTED;}
  virtual ~Controller<T>(){}

  /*
   * 调用init函数来从非实时线程初始化控制器,其中指针指向硬件接口本身,而不是指向RobotHW的指针
   * 参数 hw 此控制器使用的特定硬件接口
   * 参数controller_nh命名空间中的NodeHandle,控制器应从中读取其配置,以及应在何处设置其ROS接口
   * 初始化成功返回ture并且做好启动准备工作
   */
  virtual bool init(T* /*hw*/, ros::NodeHandle& /*controller_nh*/) {return true;};

  /*
   * 参数controller_nh控制器命名空间中的NodeHandle。这是特定于控制器的配置所在的位置。
   */
  virtual bool init(T* /*hw*/, ros::NodeHandle& /*root_nh*/, ros::NodeHandle& /*controller_nh*/) {return true;};


protected:
  /* 
   * 从RobotHW指针初始化控制器
   * 如果它可以从robot_hw中成功获取接口,则对控制器的硬件接口进行初始化
   */
  virtual bool initRequest(hardware_interface::RobotHW* robot_hw,
                           ros::NodeHandle&             root_nh,
                           ros::NodeHandle&             controller_nh,
                           ClaimedResources&            claimed_resources)
  {
    // check if construction finished cleanly
    if (state_ != CONSTRUCTED){
      ROS_ERROR("Cannot initialize this controller because it failed to be constructed");
      return false;
    }

    // 获得硬件接口的指针
    T* hw = robot_hw->get<T>();
    if (!hw)
    {
      ROS_ERROR("This controller requires a hardware interface of type '%s'."
                " Make sure this is registered in the hardware_interface::RobotHW class.",
                getHardwareInterfaceType().c_str());
      return false;
    }

    // 返回此控制器声明的资源
    hw->clearClaims();
    if (!init(hw, controller_nh) || !init(hw, root_nh, controller_nh))
    {
      ROS_ERROR("Failed to initialize the controller");
      return false;
    }
    hardware_interface::InterfaceResources iface_res(getHardwareInterfaceType(), hw->getClaims());
    claimed_resources.assign(1, iface_res);
    hw->clearClaims();

    // success
    state_ = INITIALIZED;
    return true;
  }

  /// 获取此控制器的硬件接口类型的名称
  std::string getHardwareInterfaceType() const
  {
    return hardware_interface::internal::demangledTypeName<T>();
  }

private:
  Controller<T>(const Controller<T> &c);
  Controller<T>& operator =(const Controller<T> &c);

};

}
#endif

从上面的源码中不难看出,contorller通过controlle_interface来完成hardware_interface的初始化。

hardware_interface

最重要的交互接口,与机器人硬件完成连接,我们通过类图来理清接口之间关系。


类图.png

这里需要补充说明的是HardwareResourceManager通过getHandle获取到不同的handle对应到到图中右侧的不同的HardwareInterface。这个在类图上并没有体现出来,流程图如下:


流程图.png
上一篇下一篇

猜你喜欢

热点阅读