ROS control hardware_interface

ROS control hardware_interface

Estrutura do pacote para interface de hardware de um robot

Abaixo segue a estrutura mínima para um pacote para interface de hardware para um robot. Apenas são obrigatórios os ficheiros a indicados a negrito.

  • robot_hardware_interface_pkg
    • launch/
      • some_controllers.launch
    • config/
      • controllers.yaml
      • hardware.yaml
      • joint_limits.yaml
    • include/
      • robot_hardware_interface_pkg/
        • robot_hardware_interface.h
    • src/
      • robot_hardware_interface_node.cpp
    • CMakeLists.txt
    • package.xml

 

Includes básicos no ficheiro de header do hardware_interface.

robot_hardware_interface.h

// C++
#include <boost/scoped_ptr.hpp>

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

// ROS Controls
#include <hardware_interface/robot_hw.h>
#include <hardware_interface/joint_state_interface.h>
#include <hardware_interface/joint_command_interface.h>

#include <controller_manager/controller_manager.h>

#include <joint_limits_interface/joint_limits.h>
#include <joint_limits_interface/joint_limits_interface.h>
#include <joint_limits_interface/joint_limits_rosparam.h>
#include <joint_limits_interface/joint_limits_urdf.h>

 

Com base no artigo do site da slaterobotics um pacote do ROS com o hardware interface de um robot para ROS control tem no minimo a seguinte estrutura:

Fontes

  1. https://www.slaterobotics.com/blog/5abd8a1ed4442a651de5cb5b/how-to-implement-ros_control-on-a-custom-robot

ROS control controller_manager_msgs

ROS control controller_manager_msgs

O controller_manager na sua operação necessita de tipos de mensagem adequados para a interação com os outros elementos dos sistemas robóticos.

Tipos de mensagens do controller_manager do ROS

  • ControllerState
  • ControllerStatistics
  • ControllersStatistics
  • HardwareInterfaceResources

Mensagens de tipos de serviços do controller_manager do ROS

  • ListControllerTypes
  • ListControllers
  • LoadController
  • ReloadControllerLibraries
  • SwitchController
  • UnloadController

Para mais informação consultar

http://docs.ros.org/melodic/api/controller_manager_msgs/html/index-msg.html

ROS control controller_manager

Na forma mais simplificada podermos dizer que o gestor de controlador (controller_manager) fornece a infraestrutura para interagir com os controladores.

O gestor de controlador também fornece um ciclo compatível com requerimentos de hard-realtime para controlar um mecanismo robótico.

O mecanismo robótico tem de estar representado por uma instância hardware_interface :: RobotHW (ver hardware_interface), e o controlador (ros_controller) a carregar tem de herdar a classe controller_interface::Controller. (ver controller_interface)

O controller_manager fornece diferentes ferramentas para os controladores.  Com uma flexibilidade permite a execução de controladores a partir de um ficheiro de lançamento (launch files), da linha de comandos ou de um node ROS. De uma forma geral fornece os mecanismos para carregar, libertar, iniciar e parar controladores.

Ao carregar um controlador, o controller_manager usará o nome do controlador como raiz para todos os parâmetros específicos do controlador. Sendo o mais importante, o tipo que identifica qual o plugin (ros_controller) a carregar.

Ferramentas de linha de comandos do gestor de controlador

O pacote controller_manager tem duas ferramentas para operar com os controllers. O controller_manager , o spawner e o unspawner .

controller_manager

Podemos interagir com o controlador especifico com o seguinte input na linha de comandos:

rosrun controller_manager controller_manager <command> <name1> <name2> ...

Na linha acima, <name1> e <name2> representam os ros_controlers com que queremos interagir.

Ainda na linha acima, o <command> representa as seguintes acções a executar sobre os ros_controllers especificados na linha.

  • load: carrega controllers (carrega e inicializa controladores)
  • unload: liberta controllers (destrói controladores previamente carregados)
  • start: arranca controllers (arranca controladores carregados)
  • stop: pára controllers (pára controladores a executar)
  • spawn: carrega e arranca  controllers
  • kill: pára e liberta controllers

Quando não se especifica controladores é possível obter informações sobre os controladores e recarregar as suas bibliotecas.

rosrun controller_manager controller_manager <command>

list: lista todos os controladores pela ordem em que foram executados e fornece o estado de cada controlador

list-types: lista todos os tipos de controladores que o gestor de controlador conhece. Se o controlador não estiver nesta lista, então não poderá gerá-lo.

reload-libraries: recarrega todos os controladores disponíveis como plugins. Esta operação é conveniente quando se está a desenvolver um controlador e se deseja testar o novo código, sem reiniciar sempre todo o robot. Esta operação não reinicia os controladores que estavam a ser executados antes.

reload-libraries –restore: recarrega todos os controladores disponíveis como plugins e restaura todos os controladores ao seu estado original.

spawner

Para carregar e iniciar automaticamente, de uma só vez, um conjunto de controladores, e posteriormente, parar e destruir automaticamente os mesmos controladores de uma só vez, usa-se a ferramenta spawner:

rosrun controller_manager spawner [--stopped] <name1> <name2> ...

Quando se executa o spawner, os controladores indicados na linha de comandos serão carregados e iniciados (a menos que se especifique –stopped). O Spawner continuará a funcionar enquanto os controladores estiverem activos. Quando se mata o spawner com (ctrl-c), todos os controladores iniciados por ele param e são destruídos.

unspawner

Para parar automaticamente um conjunto de controladores e reiniciá-los mais tarde, pode-se usar a ferramenta unspawner, com a seguinte linha de comando:

rosrun controller_manager unspawner <name1> <name2> ...

Os controladores indicados serão parados, mas não destruídos. Assim que que o unspawner for morto com (ctrl-c) os controladores serão reiniciados.

controller_group

No ROS melodic foi incluído um novo comando que permite alternar um grupo de de controladores com propósitos especiais. Para saber mais consultar a página do ros wiki cujo o endereço está disponível no fim deste artigo.

Ferramentas de lançamento (launch)

Pode-se executar controller_manager para iniciar os controladores em ficheiros de lançamento (launch files). No entanto, este procedimento não é recomendado pois o controlador permanecerá activo mesmo depois de o ficheiros de lançamento for morto com (ctrl+c).  Em vez disso, nos ficheiros de lançamento deve-se usar a ferramenta spawner para carregar, iniciar, parar e descarregar automaticamente um ou mais controladores.

Exemplo de ficheiro launch para lançar controllers.

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

Para carregar os controllers mas não proceder ao seu arranque, incluir o comando –stopped nos argumentos. Fica conforme exemplo abaixo.

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

Caso se use um ficheiro controllers.yaml, o nome dos controllers a ser nos ficheiros launch está ligado ao nome e a forma como o nome está estruturado no ficheiro controllers.yaml.

Para saber mais sobre a interacçao sobre o ficheiro  controllers.yaml e o lançamento de controllers em ficheiros launch, ver o seguinte artigo: ROS controllers config.

ROS API

Para interagir com os ros_controllers a partir de outro node ROS, o controller_manager fornece cinco chamadas de serviço (com indicação do respectivo tipo de mensagens):

  • controller_manager/load_controller (controller_manager_msgs/LoadController)
  • controller_manager/unload_controller (controller_manager_msgs/UnloadController)
  • controller_manager/switch_controller (controller_manager_msgs/SwitchController)
  • controller_manager/list_controllers (controller_manager_msgs/ListControllers)
  • controller_manager/list_controller_types (controller_manager_msgs/ListControllerTypes)
  • controller_manager/reload_controller_libraries (controller_manager_msgs/ReloadControllerLibraries)

Para saber mais sobre as mensagens usadas pelos serviços do controller_manager ver: ROS control controller_manager_msgs

Para saber mais consultar a página do ros wiki cujo o endereço está disponível no fim deste artigo.

http://wiki.ros.org/controller_manager?distro=melodic

ROS control controller_interface

O pacote controller_interface contém a classe base para a interface dos ros controllers.

Todos os controladores  em tempo real para o ROS devem herdar a classe base do controlador deste pacote, controller_interface::Controller.

O gestor de controladores, controller_manager, apenas carrega o controlador caso ele herde e implemente os métodos desta classe.

Estrutura de um ROS controller

Os métodos fundamentais da classe controller_interface::Controller são os seguintes:

  • init();
  • start();
  • update();
  • stop();

A estrutura básica do classe Controller é a seguinte:

namespace controller_interface 
{ 
  class Controller 
  { 
  public: 
    virtual bool init(hardware_interface *robotHW, 
                     ros::NodeHandle &nh); 
    virtual void starting(); 
    virtual void update(); 
    virtual void stopping(); 
  }; 
} 

O fluxo de trabalho da classe Controller é o seguinte:

Esta classe é especialmente importante quando desenvolvemos controladores para o ROS control (ros_controllers). Assim como para percebermos como funcionam os controlladores já existentes.

Inicialização do controlador

O primeiro método do controlador a ser executado aquando do seu carregamento pelo controller_manager é o init().

Este método requer dois parametros:

  • hardware_interface *robotHW, (Implementação da classe hardware_interface que permite aceder ao hardware do robot)
  • ros::NodeHandle &nh (a classe de base do node ROS)

O método init(), não tem restrições do tempo de execução. Não corre em tempo real, e apenas é executado uma vez aquando do carregamento do controlador pelo controller_manager.

Se este método devolver um erro, o controller_manager não completa o carregamento do controlador.

Caso existe algum erro durante a execução neste método (init), podermos usar mensagens personalizadas para notificar da existência de erros específicos.

Arranque do ros_controller

O método starting() é executado em tempo real e apenas uma vez, antes de qualquer chamada ao método de actualização. O método também pode ser chamado aquando de uma reinicialização sem que o controller seja libertado pelo controller_manager.

Actualização do ros_controller

O método update() é o mais importante do ponto de vista da acção do controlador.  Este método é executado em tempo real a uma frequência de 1000 Hz.

Paragem do controlador

O método stopping() é executado, em tempo real, como a última chamada ao update() e é apenas executado uma vez quando o controlador está a parar. Este método não devolve qualquer resultado e não tem nenhum estado de falha.

Exemplo de um novo controlador

Um pequeno exemplo de como escrever um novo ros_controller está disponível no seguinte endereço:

https://github.com/ros-controls/ros_control/wiki/controller_interface

 

ROS control combined_robot_hw

O pacote combined_robot_hw (CombinedRobotHW) permite combinar vários RobotHWs num só RobotHW. Com o seu uso, todos os  controladores vêm as articulações (joints) de todos os RobotHWs como articulações de um só RobotHW.

O mecanismo que está por traz desse comportamento especial é chamado de carregador de classes (pluginlib). O mesmo sistema por trás do gestor de controladores (controller_manager), portanto, num certo sentido o CombinedRobotHW é um tipo de gestor do RobotHW.

Depois de compor o robot, com vários subsistemas de controlo, pode usar um gestor  de controladores para todo o sistema. Mas caso estiver a usar diferentes interfaces de controlo (esforço, velocidade, posição) em diferentes RobotHWs, não poderá liga-las apenas a um controlador de esforço, por exemplo.

No wiki do repositório do ros_control está um exemplo em que se combina  dois robôs de 2 DOF cada num robô articulado de 4 DOF.

Saber mais em: https://github.com/ros-controls/ros_control/wiki/Writing-CombinedRobotHW

 

ROS controllers config

O ficheiro de configuração dos ros controllers  controllers.yaml pode ser expresso de forma plana, como no exemplo 1a ou de forma hierarquica como no exemplo 2a.

Uma das consequencias da diferente forma de exprimir  os elementos participantes no controlo é que no ficheiro launch estes tem de ser referidos tendo em conta a forma como foram expressos no respectivo ficheiro controllers.yaml.

Exemplo 1a: controllers.yaml

robotname:
    # Publish all joint states 
    joints_update:
      type: joint_state_controller/JointStateController
      publish_rate: 50
    # Position Controllers
    joint_1:
      type: position_controllers/JointPositionController
      joint: joint_1
      pid: {p: 1.0, i: 1.0, d: 0.0}
    joint_2:
      type: position_controllers/JointPositionController
      joint: joint_2
      pid: {p: 1.0, i: 1.0, d: 0.0}
    # Effort Controllers
    joint_3:
      type: effort_controllers/JointEffortController
      joint: joint_3

Exemplo 1b: controllers.launch

<rosparam file="$(find robotnamepkg)/config/controllers.yaml" command="load"/>

<node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen"
      args="
          /robotname/joints_update
          /robotname/joint_1
          /robotname/joint_2
          /robotname/joint_3
      "/>

Exemplo 2a: controllers.yaml

robotname:
  controller:
    # Publish all joint states 
    state:
      type: joint_state_controller/JointStateController
      publish_rate: 50
    # Position Controllers
    position:
      joint_1:
        type: position_controllers/JointPositionController
        joint: joint_1
        pid: {p: 10.0, i: 0.0, d: 1.0}
      joint_2:
        type: position_controllers/JointPositionController
        joint: joint_2
        pid: {p: 10.0, i: 0.0, d: 1.0}
    # Effort Controllers
    effort:
      joint_3:
        type: effort_controllers/JointEffortController
        joint: joint_3

Exemplo 2b: controllers.launch

<rosparam file="$(find robotnamepkg)/config/controllers.yaml" command="load"/>

<node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen"
      args="
          /robotname/controller/state
          /robotname/controller/position/joint_1
          /robotname/controller/position/joint_2
          /robotname/controller/effort/joint_3
      "/>

 

 

 

rosserial arduino error Service handler returned None

Problem described

rosserial_python : Service handler returned None

https://github.com/ros-drivers/rosserial/issues/408

Solution described

https://github.com/ros-drivers/rosserial/pull/414

https://github.com/ros-drivers/rosserial/commit/5e4e6db497b89f752c792bda5fddf1cadd1a79f0

Version confirmed

inaciose@ideapad:~/tmp$ rosversion rosserial_arduino
0.8.0

Solution applied

vi /opt/ros/melodic/lib/python2.7/dist-packages/rosserial_python/SerialClient.py

line 173, 174, abd 175 replaced by:

        self.parent.send(self.id, data_buffer.getvalue())
        while self.response is None:
            time.sleep(0.001)