Moveit gripper command

No artigo sobre a exploração do eezy bot arm mk2  com o ros moveit com base em mensagens FollowJointTrajectoryAction, ficou em aberto o controlo da pinça ou garra (gripper, claw?).

Pois esse artigo refere-se a controlo do posicionamento do end effector, e não ao controlo da acção do end effector propriamente dito.

Sobre o assunto não encontrei propriamente muita informação mas no entanto, destaco os seguintes:

  • https://answers.ros.org/question/307638/how-to-grasp/
  • https://answers.ros.org/question/227576/how-to-configure-the-gripper_action_controller-correctly/

Os dois artigos acima forneceram as informações importantes para configurar a parte do ros moveit, ou seja as alterações ao ficheiro config/controllers.yaml descritas mais abaixo.

A outra fonte de inspiração, que se aplicou às alterações do node eba_arm_control.py de modo a implementar o action server para o GripperCommand, foi um ficheiro do nxdefiant, que reproduzo na integra no meu repositório, e está disponivel no seguinte endereço:

https://github.com/inaciose/roscode/blob/master/ros/moveit-trajectory-griper-action-server-node.py

Deste script extrai apenas as partes necessárias ao controlo da pinça. Note-se que o script também implementa o feedback e o cancel, quer no GripperCommand quer no FollowJointTrajectory.

Alterações ao pacote ebamk2_moveit_config

Ao ficheiro config/controllers.yaml anteriormente criado no pacote de configuração do moveit para o braço eezybotarm mk2, cujo conteúdo original era o seguinte:

controller_manager_ns: /
controller_list:
  - name: arm_controller
    action_ns: follow_joint_trajectory
    type: FollowJointTrajectory
    joints: [joint_1, joint_2, joint_3, joint_6]

Foi removida a joint_6 da lista dos joints para o FollowJointTrajectory, e adicionadas as seguintes linhas que definem o controlador para a pinça (gripper) do robot.

  - name: gripper_controller
    action_ns: gripper_action
    type: GripperCommand
    joints: [joint_6]
    action_monitor_rate: 20
    goal_tolerance: 0.002
    max_effort: 100
    stall_velocity_threshold: 0.001
    stall_timeout: 1.0

Após as alterações, o conteúdo do ficheiro config/controllers.yaml ficou conforme apresentado abaixo.

controller_manager_ns: /
controller_list:
  - name: arm_controller
    action_ns: follow_joint_trajectory
    type: FollowJointTrajectory
    joints: [joint_1, joint_2, joint_3]
  - name: gripper_controller
    action_ns: gripper_action
    type: GripperCommand
    joints: [joint_6]
    action_monitor_rate: 20
    goal_tolerance: 0.002
    max_effort: 100
    stall_velocity_threshold: 0.001
    stall_timeout: 1.0

Com esta alteração o moveit passa a publicar mensagens nos tópicos: gripper_controller/gripper_action/goal.

Se o nosso node nao implementar o action server para estas mensagens o moveit suspende o uso do controller.

Nessa situação aparecem no terminal as seguintes mensagens de aviso e erro

[ WARN] [1590357841.286752284]: Waiting for gripper_controller/gripper_action to come up
[ERROR] [1590357847.287084048]: Action client not connected: gripper_controller/gripper_action

Esta mensagem deixa de aparecer quando o nosso node, no meu caso o  eba_arm_control.py, responde adequadamente.

Alterações ao eba_arm_control.py

As alterações ao node não foram muito grandes, e encontram-se resumidas abaixo.

Incluir a importação das bibliotecas de mensagens usadas.

# gripper
from control_msgs.msg import GripperCommandAction, GripperCommandActionResult, GripperCommandFeedback

def __init__(self): 

No metodo de inicialização da classe foi adicionado o código que declara e inicializa o actionlib server.

        # Set up action GripperCommandAction
        self.action_server_gripper = actionlib.SimpleActionServer("/gripper_controller/gripper_action", 
                                        GripperCommandAction, 
                                        self.do_action_gripper_callback, False)
        self.action_server_gripper.start()

def do_action_gripper_callback(self, goal):

Este método é novo e é o responsavel pelo processamento das mensagens recebidas. Ou seja abre e fecha a pinça e devolve o resultado.

    def do_action_gripper_callback(self, goal):
        print ('Received gripper goal %.2f'%goal.command.position)		

	# adjust position and commit to hardware
        self.c(goal.command.position)
        self.publish_servos_state(self.robot_joints)

	# Action done, either canceled or position reached
        self._gripper_result.status = 3 # 3 = GoalStatus.SUCCEEDED
        self._gripper_result.result.position = goal.command.position
        self._gripper_result.result.stalled = False
        self._gripper_result.result.reached_goal = True
        self.action_server_gripper.set_succeeded(self._gripper_result.result)
        print('gripper move complete')

Para histórico, foi feita uma cópia do node eba_arm_control.py sem as alterações para contemplar o gripper, para o seguinte ficheiro:  eba_arm_follow_trajectory.py.

Considerações finais sobre grasp, gripper e afins

Apesar de ter chegado a uma implementação, ela não é completamente satisfatória.

Em primeiro lugar porque, conforme artigo indicado abaixo, pelo que percebi não existe um interface para o GripperCommand no rviz do moveit.

https://answers.ros.org/question/313637/openclose-end-effector-with-moveit-rviz/

Por outro lado, parece que existe mais que um tipo de solução para este tipo de problema.

Conforme o link seguinte, pode ser usadas soluções baseadas no, pick and place pipeline, moveit_grasps e no moveit_tasks_constructor.

https://answers.ros.org/question/350706/open-gripper-using-grippercommand-in-pick-and-place-pipeline/

Provavelmente voltarei mais tarde a este assunto

eezybotArm MK2 ROS moveit! basic integration

Depois de conseguir por a funcionar soluções menos apropriadas para movimentar o eezybotarm mk2 no ros moveit!, como, por exemplo, conduzir o robot em espelho com a apresentação do rviz, por subscrição do tópico fake_controller_joint_states, quando se corre o demo.launch, consegui implementar uma forma mais adequada de exploração do eezybotarm mk2 com o moveit!. com base nas mensagens follow joint trajectory.

Passo 1 – Criar ou adaptar de alguma fonte o firmware para o microcontrolador que é o responsavel directo pelos actuadores. Neste caso do eezybotarm mk2 os servo motores.

Passo 2 – Criar ou adaptar de alguma fonte o node ros com o actionlib server que recebe as mensagens joint_trajectory_action, processa as e publica ao longo do tempo a sequência dos ângulos a aplicar a cada actuador em cada passo.

Passo 3 – Criar a descrição do braço robotico num ficheiro com o formato urdf.

Passo 4 – Criar o pacote de configuração do braço robótico para o moveit! com o moveit_setup_assistant.

Passo 5 – Alterar o pacote de configuração do braço robótico para o moveit!  pois é necessário criar e alterar ficheiros de configuração (yaml) e de lançamento (launch). Ver alterações ao moveit config de um braço para ligação eficaz ao nosso hardware.

Passo 6 – executar o comando de lançamento de nodes:

roslaunch ebamk2_moveit_config ebamk2_planning_execution.launch

Deverá aparecer o rviz com a representação do braço e o interface de controlo que permite a selecção da nova posição do braço robotico.

Para aceder ao controlo sobre o braço é necessário ter o Display:  MotionPlaning. Para adicionar, caso necessário, clicar no botão Add na área de Displays e seleciona-lo.

Nesta solução não se usa um hardware interface em conformidade com as especificações e interface do ros control. O  termo controllers que é usado nas vaŕias informações disponiveis sobre o assunto deixa-me um bocado confundido, até por que encontrei informação nesse sentido (ver link abaixo). Mas tanto quanto percebi,  o controller não necessita de ter uma hardware interface que siga o padrão do ros control.

https://answers.ros.org/question/331384/building-a-custom-hardware-interface-for-moveit/

O que indicamos como controller determina o namespace de um conjunto de tópicos, com os nomes tipicos dos actionlib servers e com tipos de mensagens apropriados, como por exemplo, no caso das indicações da trajectoria do braço, o control_msgs/FollowJointTrajectoryActionGoal.

O nosso node, e que é indicado como controller, tem de ter um action  server que cuide do processamento dessas mensagens, enviando os dados necessários para o controlo de posição dos diversos servo motores a partir das informaçoes de posição (e …velocidade e esforço), existentes nas mensagens recebidas.

Nesta minha primeira implementação do node com um action server para mensagens da familia FollowJointTrajectory adoptei o script meArm.py em python que descobri no pacote typetyp.

Sobre este node em c++ ver o seguinte link.

https://answers.ros.org/question/192739/implement-moveit-on-real-robot/

Outra nota importante é que não existe qualquer feedback do hardware, pelo que a posição das articulações que compõem as joint_states publicadas são todas meras copias das posições desejadas. Para podermos ter publicadas as posições reais, teremos, caso do ebamk2, de usar servos com feedback e escrever o codigo adequado para usar esse feedback no nosso node.

O proximo passo é o controlo da pinça, já que este tipo de mensagens apenas trata do posicionamento do end effector, e não diz nada sobre como este se comporta.

 

coffee-bot

O coffee bot é o nome de um pacote do ROS (coffee_bot), e também de um repositório do github que contem quer o pacote para o ROS quer o firmware para o Arduino, necessário para explorar o braço robótico eezyBotArm MK2 com o Robotic Operating System.

O repositório original está disponivel a partir do meu fork no seguinte endereço: https://github.com/inaciosef/coffee-bot.

Este conjunto de software para o braço robótico eezyBotArm MK2 permite:

  • Comandar o braço robotico com o teclado
  • Gravar os movimentos executados
  • Reproduzir os movimentos gravados de forma automática
  • Visualizar o movimento do braço no rviz (o firmware publica mensagens sensor_msgs/JointState)

Conheci este pacote por ter visto o video abaixo no youtube.

A interação entre o node ROS e o firmware do Arduino (que é feito com base no rosserial) é efectuada com base nos tópicos x, y, z e g, que correspondem aos vários servos do braço e aceitam mensagens do tipo std_msgs/UInt16. Existe também um tópico com mensagens do tipo sensor_msgs/JointState que é publicado pelo firmware e informa a posição das várias articulações do braço robótico.

Este pacote foi importante na elaboração da parte do pacote rosarm_control que diz respeito ao eezyBotArm.

 

 

ebamk2_description

O pacote ROS ebamk2_description contem a descrição do braço róbótico EezyBotArm MK2.

O pacote ROS ebamk2_description contem a descrição do braço róbótico EezyBotArm MK2.

Existem três versões base com a descrição do braço robotico nos seguintes  ficheiros urdf.

ebamk2.urdf

Esta versão descreve o robot com os solidos geométricos base e inclui a garra. Reproduz a alteração no angulo entre a haste principal e a horizontal quando a primeira se movimenta, assim como a manutenção da horizontalidade da garra aquando do movimento da haste horizontal.

ebamk2_mesh.urdf

Esta versão descreve o robot com meshes e inclui a garra. Reproduz a alteração no angulo entre a haste principal e a horizontal quando a primeira se movimenta, assim como a manutenção da horizontalidade da garra aquando do movimento da haste horizontal.

ebamk2_web.urdf

Versão original que não reproduz tão bem o movimento do braço robótico e está incluida no repositório ntbd .

Cinemática dos braços róboticos eezyBotArm

A cadeia cinemática dos braços robóticos eezyBotArm, adoptada dos robots manipuladores industriais ABB-IRB460, é baseada em três actuadores, uma base rotativa e duas hastes em T. Uma das quais controlada directamente e outra de forma indirecta. A este sistema principal de duas hastes, está associado um outro sistema de hastes (no modelo 3D mais abaixo estão a roxo) cujo propósito é garantir a horizontalidade da aplicação da garra.

Todos os robots que seguem este modelo tem uma cadeia cinemática semelhante e todas as descrições, fórmulas,  e cálculos aqui apresentados, que foram efectuados com base no eezyBotArm MK2, com uma escala de 7 para 1 face ao ABB-IRB460, aplicam-se a outros braços robóticos, como o eezyBotArm MK1 e o eezyBotArm MK3, com as devidas adequações nos parâmetros usados.

Acção dos actuadores nos braços robóticos eezyBotArm

Um actuador colocado na base e que roda o suporte das hastes segundo o eixo do z (vertical com o plano) e controla o posicionamento da garra no eixo do y, conforme video abaixo.

Um actuador que está acoplado ao braço principal, a azul no video, cujo eixo de rotação se encontra na sua extremidade inferior e controla o posicionamento da garra no eixo do x dentro de uma trajectória inscrita na circunferência do seu raio, conforme video abaixo.

Um ultimo actuador está acoplado indirectamente, por meio de duas hastes intermédias,  à extremidade traseira do braço horizontal, a vermelho no video, que roda sobre o eixo na extremidade superior do braço principal e controla o posicionamento da garra no eixo do z dentro de uma trajectória inscrita na circunferência do seu raio, conforme video abaixo.

Esta haste horizontal é actuada por intermédio de duas outras hastes, a verde na imagem abaixo, que conduzem o movimento do servo.

Quando o actuador na haste A, roda para baixo (no caso de um servo quando o ângulo se move para zero), conjunto das hastes verdes desce, puxando para baixo a parte de traz da haste horizontal (ponto t), que devido ao seu eixo de rotação (ponto c), faz subir a sua parte da frente (ponto h).

Os movimentos da haste principal, a azul, em torno do ponto A e da haste horizontal, a amarelo, em torno do ponto c definem a posição do ponto h face aos eixos x e z, ou seja a distancia da projecção de de h para A, e a altura do ponto h.

A amplitude dos movimentos deste tipo de robots está condicionado pela amplitude de rotação dos motores, das engrenagens que eventualmente estejam envolvidas e das colisões que se possam verificar.

No caso do braço robóticos eezyBotArm MK2, os limites são impostos pelos:

  • Servos de 180º de amplitude de rotação;
  • Carretos envolvidos na rotação sobre o eixo z, um principal (movido pelo servo 0) com 25 dentes e o segundo com 50 dentes, o que faz com que o movimento de rotação sobre esse eixo tenha apenas 90º de amplitude;
  • Colisões entre a haste horizontal (servo 2) e a haste principal (servo 1) que implica que os servos que as movimentam têm respectivamente os seguintes limites: 60º entre os 45º e os 105º (servo 2), e 90º entre os 55º e os 145º (servo 1).

Cálculo da cinemática inversa no eezyBotArm

A cinemática inversa refere-se ao cálculo dos ângulos adequados aos diversos eixos accionados por actuadores de modo a que o ponto de acção do braço (end effector)  se posicione num ponto especifico do espaço.

Dado um determinado ponto a (ver figura mais abaixo) com as coordenadas x, y e z relativamente à origem que para facilitar consideramos estar no centro de rotação do robot a uma altura L (no eixo dos z), o calculo da cinemática inversa envolve a conversão das coordenadas cartesianas, desse ponto, em coordenadas cilíndricas e a partir delas extrair o ângulo desejado para cada um dos três actuadores.

https://pt.wikipedia.org/wiki/Coordenadas_cil%C3%ADndricas

Os cálculos são efectuados nas seguintes fases.

Primeira fase. Conversão das coordenadas cartesianas em coordenadas cilíndricas.

Nestas coordenadas, o ângulo theta é expresso em radiano e o z mantém-se cartesiano. Por isso temos:

  • theta = atan(y/x)
  • raio = srt(x*x + y*y)
  • z = z

O theta é o ângulo que se relacionada com o motor 0,  e define a rotação em torno do eixo dos z, que antes de ser transformado em graus para ser aplicado ao motor sofre a seguinte alteração:

Ângulo do motor 0 = 2 * theta + pi / 2

Numa segunda e terceira fases, efectuam-se os cálculos dos outros dois motores, que me conjunto são responsáveis pelo posicionamento nos eixos do x e do y.

Para calcular os ângulos teremos que considerar a aplicação da lei dos cossenos.

https://pt.wikipedia.org/wiki/Lei_dos_cossenos

Consideremos o terceiro caso:

c*c = a*a + b*b – 2 * a * b * cos C

Resolvemos em ordem a cos C

c*c = a*a + b*b – 2 * a * b * cos C  é equivalente a

0 = a*a + b*b – c*c – 2 * a * b * cos C é equivalente a

2 * a * b * cos C = a*a + b*b – c*c é equivalente a

cos C = (a*a + b*b – c*c) / (2 * a * b) é equivalente a

ângulo C = acos((a*a + b*b – c*c) / (2 * a * b)) a

Com base na definição de pontos expressa na imagem anterior, consideremos na aplicação da formula acima e na seguinte que:

a = L2 = distancia entre os pontos be, b = sqrt(), e c = L3 = distancia entre os pontos ef

Ângulo do motor M1 = atan(z / raio) + leicossenos(L2, sqrt(raio*raio + z*z), L3)

Pela aplicação

Ângulo do motor M2 = pi – (M1 + leicossenos(L2, L3, sqrt(raio*raio + z*z)) – pi/2)

Os ângulos calculados acima estão expresso em radiano. Antes de serem aplicados aos motores tem de ser convertidos em graus.

Abaixo segue o bloco de código em python que calcula a cinemática inversa nos braços eezyBotArm

L1 = 94
L2 = 150 
L3 = 150 
#Hipotenusa:
def hipo(x,y):
    return math.sqrt(x*x + y*y)
#Cosines law:
def lawOfCosines(a,b,c):
    rate = (a*a + b*b - c*c) / (2 * a * b)
    if abs(rate) > 1:
        if max(rate,0) == 0:
            rate = -1
        if max(rate,0) == rate:
            rate = 1
    return math.acos(rate)

def deg(rad):
    return rad * 180 / math.pi

# Posição em coordenadas cartesianas
cartP = {'xEE': x, 'yEE': y, 'zEE': z}
# Posição em coordenadas cilindricas
cylP = {'theta': math.atan(cartP['yEE']/cartP['xEE']), 'r':hipo(cartP['xEE'], cartP['yEE']), 'zhat':cartP['zEE']-L1}
zhat = cylP['zhat']
rho = hipo(cylP['r'], zhat)
# Ângulos calculados em radiano
M1 = 2*cylP['theta'] + math.pi/2
M2 = math.atan(zhat/cylP['r']) + lawOfCosines(L2,rho,L3)
M3 = M2 + lawOfCosines(L2,L3,rho) - math.pi/2
# Ajustes
angles = [M1,math.pi - M2,M3]
# Conversão dos angulos para graus
angles = [deg(angle) for angle in angles]

 

Cálculo da cinemática directa no eezyBotArm

A cinemática directa refere-se ao do ponto especifico no espaço onde se posiciona elemento de acção do braço (end effector), dados os ângulos adequados aos diversos eixos accionados por actuadores.

Neste caso, os cálculos não o inverso do aplicado acima, e passam por determinar as coordenadas cartesianas em função do calculo da coordenada cilíndrica tendo em conta os angulos dos actuadores e os parâmetros físicos do braço.

Abaixo segue o bloco de código em python que calcula a cinemática directa nos braços eezyBotArm

L1 = distancia entre o ponto b e a superfície onde assenta o braço, L2 = distancia entre os pontos be,  L3 = distancia entre os pontos ef.

# conversão dos angulos para radianos:
angles = [joint*math.pi/180 for joint in joints.data]
# cálculo intermédio para a conversão para as coordenadas cartesianas
r = L2*math.cos(math.pi - angles[1]) + L3*math.cos(angles[2]-math.pi/2) 
# Posição do ponto expresso em coordenadas cartesianas:
x = r*math.cos((angles[0]-math.pi/2)/2)
y = r*math.sin((angles[0]-math.pi/2)/2)
z = L2*math.sin(math.pi - angles[1]) + L3*math.sin(angles[2]-math.pi/2) + L

 

Folha de cálculo para a cinemática directa:

https://docs.google.com/spreadsheets/d/1DB-M-31lVDcXrwiRjAp6iKgvtpz-O-wC2fAOD7AwXrc/edit?usp=sharing

 

Fontes

https://github.com/HotBlackRobotics/ntbd

https://hackaday.io/project/157951

https://github.com/IdreesInc/EEZYbotARM-MK2-Cartesian-Coordinates

 

 

EezyBotArm MK2

O EezyBotArm MK2 é a segunda versão da família de braços robóticos educativos EezyBotArm desenhados para serem fabricados em impressoras 3D e com instruções de montagem disponíveis na Internet.

A informação original do autor está disponível nos seguintes endereços:

  • http://www.eezyrobots.it/eba_mk2.html
  • https://www.thingiverse.com/thing:1454048
  • https://www.instructables.com/id/EEZYbotARM-Mk2-3D-Printed-Robot/

No entanto, sendo este provavelmente o mais conhecido e bem sucedido braço da família de robots EezyBotArm, existe mais informação disponível na Internet para a montagem e exploração deste braço robótico do que para qualquer um dos outros.

Para a impressão e montagem do braço recolhi e publiquei informação em português, incluindo uma lista de materiais actualizada, no artigo sobre como Fazer o braço robótico EezyBotArm MK2.

Cinemática do eezyBotArm MK2

Devido ás suas características este braço é capaz de rodar apenas 90 graus, 45 para a sua direita, e 45 para a sua esquerda, e alcançar entre 7 cm e 24 cm a partir do seu eixo de rotação e 5 a 22 cm de altura.

Veja o seguinte artigo para saber mais sobre a: Cinemática do braço robot eezyBotArm MK2.

A parte de controlo seja ela hardware ou software está descrita, pelo próprio autor (ver links do autor do braço no inicio do artigo) ou em vários projectos em que o robot manipulador EezyBotArm MK2 é usado.

 

Integração do eezyBotArm MK2 com o ROS

https://github.com/SimBil91/coffee-bot

https://hotblackrobotics.github.io/en/blog/2018/01/17/ntbd-guide-part-I/

https://hotblackrobotics.github.io/it/blog/2018/02/14/sibot-cloud/

https://rospibot.azw.pt/wp-content/uploads/2020/04/eezyarm_APIEMS2019_paper_259.pdf

Braços robóticos EezyBotArm

Os braços robóticos EezyBotArm são uma família de robots manipuladores educativos desenhados com base no robot industrial ABB – IRB 460, pelo italiano Carlo Franciscone.

Até ao momento de escrita deste artigo, esta família já conta com três versões de braços robóticos educativos fáceis de fazer, com instruções e ficheiros stl publicados na Internet.

O mais pequeno, económico, e antigo da família é o EezyBotArm MK1, tem com 3 servos MG90 a mover as hastes e um SG90 a abrir e fechar a garra.

A segunda versão, é o EezyBotArm MK2. Tem com 3 servos MG995 (ou MG946, ou MG966)  a mover as hastes e um SG90 a abrir e fechar a garra.

A terceira versão, o EezyBotArm MK3, passou a usar motores de passo (steppers) como actuadores para posicionamento das hastes, e mantém o servo SG90 como actuador para abrir e fechar a garra.

Para além destes braços desenvolvidos por Carlo Franciscone, existe um remix do EezyBotArm MK2, conhecido por Robot Arm MK2 Plus e que foi redesenhado para usar motores de passo Nema 17.

Os braços desta família não são os únicos desenhados com base no IRB 460. Existem várias edições deste modelo cinemático disponíveis como kits comerciais com destaque para os meArm. 

Cinemática dos braços eezyBotArm

Para além dos componentes mecânicos e actuadores dos braços

Hardware de controlo dos braços robóticos EezyBotArm

Sofware de controlo dos braços robóticos EezyBotArm

 

ntbd eezybotarm mk2

Este artigo é sobre a exploração do projecto genérico para controlo de braços robóticos em ROS com o nome NTBD, cujo o exemplo de implementação é feico com o eezybotarm mk2, e que está descrito no seguinte endereço:

https://hotblackrobotics.github.io/en/blog/2018/01/17/ntbd-guide-part-I/

Para além desta descrição existe também um repositório no github com o software usado na implementação do controlo do braço robótico eezybotarm mk2 no ROS e que está disponível nos seguintes endereços (o segundo é o meu fork)

  • https://github.com/HotBlackRobotics/ntbd
  • https://github.com/inaciose/ntbd

A exploração do software neste repositório será feita de dois modos:

  • Numa primeira fase em conformidade com o procedimento descrito no artigo principal, onde se recorre ao um container do docker pré preparado pelo autor do projecto.
  • Numa segunda fase será abordado de forma nativa de modo a compreender melhor o funcionamento de cada um dos pacotes.
  • Numa terceira fase, irei alterar o hardware de controlo dos servos passando a usar uma placa de geração de sinais PWM com interface i2c baseada no chip PCA9685.

As duas primeiras fases partilham o mesmo hardware descrito no projecto ntbd, ainda sem o modulo PCA9865.

Hardware de controlo do braço robótico

Para além de um braço robótico adequado, o projecto ntbd usa como exemplo o eezibotarm mk2, mas pode ser aplicado noutros braços robóticos como por exemplo o eezibotarm mk1. é  necessário o seguinte hardware:

  • Um micro-controlador. O controlo dos servos pode ser efectuado por um micro-controlador, como por exemplo o ATMEGA 328p. Seguindo o projecto ntbd, será usado um Arduino Mega 2560.
  • Um computador com linux capaz de correr o docker e o ROS. Pode ser um PC x86 ou Raspberry Pi. Na segunda fase o computador tem de ter o ROS instalado.

As ligações entre o arduino e os servos são as seguintes:

  • Servo 1 sinal (amarelo) > Arduino pino 2
  • Servo 2 sinal (amarelo) >Arduino pino 3
  • Servo 3 sinal (amarelo) > Arduino pino 4
  • Servo 4 sinal (amarelo) > Arduino pino 5

Podem ser usados outros pinos, desde que seja capazes de produzir um sinal PWM, mas para isso é necessário alterar o firmware.

Os servos devem ter alimentação externa. Não esquecer de partilhar a terra.

A ligação entre o computador e o Arduino é efectuada por uma interface USB.

Firmware de controlo do braço robótico

Microcontrolador  tem que estar a correr um programa desenhado para o efeito.

No firmware original do ntbd, a integração no ROS  é efectuda pelo recurso às bibiotecas rosserial, e para gerar o sinal PWM adequado é usada a biblioteca Servo. 

O programa é bastante simples, mas o procedimento para a compilação é mais elaborado, e está descrito no seguinte artigo:

NTBD Robot Arm Arduino Firmware

Numa fase posterior será usado um modulo PCA9685, pelo que o firmware terá de ser alterado para o novo hardware.

Exploração do NTBD com Docker Containers

O autor do projecto NTBD preparou dois docker containers com os pacotes para o ROS para serem usados no projecto ntbd docker.

  • O container o ntbd_base, contém os pacotes globais (ntbd_core e ntbd_msgs);
  • O container ntbd_manipulator, contém o software especifico para o braço robótico. Neste caso o eezybotarm mk2.

Para além do software nos docker containers é ainda necessário proceder à preparação de um micro controlador, um Arduino Mega, com o firmware referido acima.

Para saber mais sobre o assunto consultar:

Explorar o eezyBotArm mk2 com NTBD Docker Container.

Exploração do NTBD sem docker

Exploração do software existente no repositório do ntbd no github de forma proceder á sua execução fora do docker.

Na base do repositório existem duas pastas. A pasta ntdb_base tem dois pacotes para o ROS que funcionam independentemente o braço robótico que está a ser explorado. Além desses dois pacotes tem ainda um ficheiro de configuração para o nginx. A pasta ntbd_manipulator tem o software especifico para um braço robótico, no caso o eezybotarm mk2, e o software para ser executado no webserver.

Para além dos pacotes do ros, e o software web, o respositório tem também o sketch para o arduino que subscreve o tópico motors do tipo Motors_Array, via rosserial.

ntbd_core

Existente dentro da pasta ntbd_base, é um pacote genérico que se encarrega do movimento dos servos com os seguintes com os seguinte scripts:

  • motors_limiter, publica o tópico motors, e subscreve o motors_nolim;
  • path_planner, publica o tópico desired_position, e subscreve o desired_position_nointerp;
  • position_limiter, publica o tópico desired_position_nointerp, e subscreve o desired_position_nolim;

ntdb_msgs

Existente dentro da pasta ntbd_base, é um pacote genérico que contém a definição das mensagens do tipo  Motors_Array

urdf_manipulator

Existente dentro da pasta ntbd_manipulator, é um pacote especifico para braço robótico, e  tem as pastas de config, launch, meshes e urdf.

Este pacote esta dentro de uma pasta que a refere como abstrata.

Também na pasta ntbd_manipulator, e fora de qualquer pacote do ROS, estão os seguintes ficheiros:

  • fk, publica o tópico actual_position, e subscreve o motors
  • ik, publica o tópico motors_nogripper, e subscreve o desired_position
  • motors_values, publica o tópico motors_nolim, e subscreve os tópicos: gripper_value e motors_nogripper
  • physical_2_visual, publica o tópico joint_states, e subscreve o motors

Também de fora de qualquer pacote do ROS está o ficheiro NTBD_launch.launch.

Todos estes ficheiros tem de ser copiados para dentro de um pacote do ROS para poderem ser executados. Se usarmos o ficheiro launch NTBD_launch.launch, sem modificações, todos os ficheiros tem de ser copiados para o pacote ntbd_core.

O ficheiro NTBD_launch.launch tem um erro, pois refere o ficheiro siBOT_noEE.urdf na pasta robots, quando ele está na pasta urdf.

O projecto implica a instalação de alguns pacotes do sistema e do ROS caso não estejam previamente instalado com os seguintes comandos:

sudo apt install nginx
sudo apt install ros-melodic-rosbridge-server
sudo apt install ros-melodic-rosbridge-suite
sudo apt install ros-melodic-tf2-web-republisher

Por último, já depois de ter copiado os scripts e o launch para o sitio certo, ter configurado o nginx, colocado o conteúdo da pasta web na pasta apropriada, e ter efectuado algumas alterações ao ficheiro launch efectuei a primeira tentativa de executar o ntbd fora do docker com o seguinte comando:

roslaunch manipulator_urdf NTBD_launch.launch

Com os pacotes do ntdb em execução é necessário apontar navegador para o endereço seguinte:

http://localhost

Mas as coisas não funcionaram pois, não visualizo o braço no interface web, conforme acontece quando se usa a versão do docker, e quando tento executar o interface web de controlo do braço dá-me sempre este erro:

2020-04-12 22:12:16+0100 [-] failing WebSocket opening handshake (‘missing port in HTTP Host header ‘localhost’ and server runs on non-standard port 9090 (wss = False)’)
2020-04-12 22:12:16+0100 [-] dropping connection to peer tcp4:127.0.0.1:33722 with abort=False: missing port in HTTP Host header ‘localhost’ and server runs on non-standard port 9090 (wss = False)

Nos seguintes links recolhi alguma informação sobre o assunto mas não consegui resolver o problema:

https://github.com/crossbario/autobahn-python/issues/775

https://github.com/RobotWebTools/rosbridge_suite/issues/467

Após analisar o index.html descobri que o interface fica funcional se alterar a linha 186 para o seguinte:

url : ‘ws://’+ window.location.hostname + ‘:9090’

Após este teste bem sucedido irei preparar dois pacotes ROS adequados a exploração dos braços eezybotarm mk1 e mk2 fora do docker.

Tópicos dos nodes usados pelo ntbd

  • /actual_position (pub: FK)
  • /client_count (pub: rosbridge_websocket)
  • /connected_clients (pub: rosbridge_websocket)
  • /desired_position (pub: path_planner; sub: IK)
  • /desired_position_nointerp (pub: position_limiter; sub: path_planner)
  • /desired_position_nolim (pub: rosbridge_websocket; sub: position_limiter);
  • /diagnostics (pub: init_serial_node)
  • /gripper_value (pub: rosbridge_websocket; sub: motors_values)
  • /joint_states (pub: joint_state_publisher_gui, physical_2_visual; sub: robot_state_publisher)
  • /motors (pub: motors_limiter; sub: FK, physical_2_visual, init_serial_node)
  • /motors_nogripper (pub: IK; sub: motors_values)
  • /motors_nolim (pub: motors_values; sub: motors_limiter)
  • /tf (pub: robot_state_publisher; sub:  tf2_web_republisher)
  • /tf2_web_republisher/cancel (pub: rosbridge_websocket; sub: tf2_web_republisher)
  • /tf2_web_republisher/feedback (pub: tf2_web_republisher; sub: /rosbridge_websocket)
  • /tf2_web_republisher/goal(pub: rosbridge_websocket; sub: tf2_web_republisher)
  • /tf2_web_republisher/result (pub: tf2_web_republisher; sub: /rosbridge_websocket)
  • /tf2_web_republisher/status(pub: tf2_web_republisher; sub: /rosbridge_websocket)
  • /tf_static (pub: robot_state_publisher; sub: tf2_web_republisher)

 

NTBD Arduino Firmware

O firmware a correr no Arduino integra-se no ROS  pelo recurso às bibliotecas rosserial,  e, numa primeira fase, para gera o sinal PWM adequado é usada a biblioteca Servo. 

Posteriormente o sinal PWM será gerado por um módulo PCA9685, e o firmware necessita de ser alterado.

O arduino mega 2560 deve estar a correr o programa: myServoControl_ntbd.ino, que se encontra disponível no repositório ntdb do github.

O programa requer que a biblioteca ros_lib (rosserial arduino) esteja instalada no Arduino IDE.  A biblioteca rosserial pode ser instalada no gestor de bibliotecas disponível no IDE, mas é recomendado usar a biblioteca gerada pelo rosserial-arduino.

Também é obrigatório ter instalados no computador os pacotes do ROS:  rosserial e rosserial arduino. Para instalar pode-se usar os seguintes comandos:

sudo apt install ros-melodic-rosserial
sudo apt install ros-melodic-rosserial-arduino

Como o programa para o Arduino requer mensagens personalizadas do ROS  (ROS custom messages). Ver linha:

#include <ntbd_msgs/Motors_Array.h>

Teremos que efectuar um procedimento especial, que envolve a compilação do pacote de ROS do ntbd que tem as mensagens personalizadas, e assim obter o ficheiro de header necessário.

Para obter o ficheiro Motors_Array.h, é necessário, antes de mais, colocar o respectivo pacote do ROS na pasta adequada do catkin e proceder á sua compilação (também se pode proceder clonagem de todo o repositório postrior compilação):

cd ~/catkin_sw/src
git clone https://github.com/HotBlackRobotics/ntbd
cd ~/catkin_sw
catkin_make

De seguida, tem de se usar um dos seguintes comandos (pelos vistos existe a informação de vários devido à evolução das várias versões do ROS):

No ROS Melodic, o comando que funcionou foi  o ultimo dos indicados abaixo.

rosrun rosserial_client make_library.py ~/ ntbd_msgs
rosrun rosserial_arduino make_library.py ~/ ntbd_msgs
rosrun rosserial_arduino make_libraries.py ~/ ntbd_msgs

~/ representa a pasta de destino onde se encontra a ros_lib (biblioteca rosserial para o arduino)

ntbd_msgs, indica o pacote (com as mensagens) a ser compilado

O comando que usei (o último) gerou uma pasta ros_lib na home com toda a biblioteca do rosserial incluindo uma pasta ntbd_msgs que contem o ficheiro pretendido.

Nesta fase podemos optar por uma das duas soluções:

  • Copiar a pasta ~/ros_lib/ntbd_msgs para ~/Arduino/libraries/ros_lib;
  • Copiar a pasta para dentro da pasta do sketch do arduino, e alterar uma linha de include para passar a incluir a biblioteca localmente: #include “ntbd_msgs/Motors_Array.h”

Nesta fase já podemos compilar e enviar o programa para o Arduino Mega.

Sem alteração da biblioteca a comunicação serial funciona a 57600, por isso é necessário proceder, conforme descrito nos comentários do programa, à alteração a um ficheiro da biblioteca ros_lib.

myServoControl_ntbd.ino

Versão 1 (original)

Nesta versão é usado apenas o micro-controlador (arduino)

/* NTBD integration with eezybotarm
* Servo motors control using rosserial
* Author: fiorella.sibona@gmail.com
*/

#include <Servo.h> 
#include <ros.h>
#include <ntbd_msgs/Motors_Array.h>
#define USE_USBCON

ros::NodeHandle nh;

Servo servo1, servo2, servo3, servo4;

// Callback funtion ("as message is read, perform these actions")
void servos_cb( const ntbd_msgs::Motors_Array& angles_msg){

servo1.write(angles_msg.data[0]); 
servo2.write(angles_msg.data[1]);
servo3.write(angles_msg.data[2]);
servo4.write(angles_msg.data[3]);

}

// Subscriber node declaration, specifies the topic to which subscribe and the callback funtion
ros::Subscriber<ntbd_msgs::Motors_Array> sub("motors", servos_cb);

// Arduino setup function
void setup(){

nh.initNode();
nh.subscribe(sub);

servo1.attach(2); //attach it to pin 2
servo2.attach(3);
servo3.attach(4);
servo4.attach(5);

}

// Arduino loop function
void loop(){

nh.spinOnce();
delay(1);

}

 

Referencias

http://wiki.ros.org/rosserial_arduino/Tutorials/Adding%20Custom%20Messages

https://medium.com/@Sammy_Hasan/quick-code-v0-3-rosserial-custom-messages-ebdfc7ea172e

eezybotarm mk2 ntbd ros docker

Exploração do eezybotarm mk2 recorrendo a docker containers com os pacotes para o ROS do projecto ntbd docker.

O microcontrolador (Arduino Mega 2560)  tem que estar a correr um programa (firmware) desenhado para o efeito,  que usa a bibloteca Servo, para geral o sinal PWM adequado, e que se integra no ROS pelo recurso ao pacote rosserial e rosserial-arduino.

Saiba mais sobre o Firmware de Arduino para controlo de Servos em ROS.

Esta exploração foi efectuada com base nas informaçoes disponveis no  artigo do seguinte endereço:

https://hotblackrobotics.github.io/en/blog/2018/01/17/ntbd-guide-part-I/

Se não estiver instalado, começamos por instalar o docker com o seguinte comando:

sudo apt install docker docker.io
sudo apt install docker-compose

Testar o docker com o seguinte comando:

sudo docker run hello-world

Conforme as instruções disponiveis a partir do ponto 4 do artigo referido acima.

Instalar as duas imagens do docker que são necessárias com os seguintes comandos:

sudo docker pull hbrobotics/ntbd_base:intel
sudo docker pull hbrobotics/ntbd_manipulator:intel

Existem imagens para o Raspberry Pi 3, para as usar basta substituir o :intel por :rpi3.

Nota suplementar a explorar, no docker hub  existem imagens do ROS para o docker que merecem atenção.

https://hub.docker.com/u/hbrobotics/

Além disso  estão disponíveis os ficheiros que permitem fazer os docker containers no seguinte repositório:

https://github.com/HotBlackRobotics/docker-ros-base

Para executar o dois contentores (imagens) de docker devemos executar o seguinte comando:

sudo docker-compose -f docker-compose.hbr_ntbd_intel.yml up

Para o Raspberry Pi 3 usar o ficheiro docker-compose.hbr_ntbd_rpi3.yml

A primeira execução produziu as seguintes mensagens no terminal

Creating hbr_ntbd_manipulator_intel ... 
Creating hbr_ntbd_manipulator_intel ... done
Attaching to hbr_ntbd_manipulator_intel
hbr_ntbd_manipulator_intel | * Starting nginx nginx
hbr_ntbd_manipulator_intel | ...done.
hbr_ntbd_manipulator_intel | [ERROR] [1586442600.408287]: Error opening serial: [Errno 2] could not open port /dev/ttyACM0: [Errno 2] No such file or directory: '/dev/ttyACM0'
hbr_ntbd_manipulator_intel | the rosdep view is empty: call 'sudo rosdep init' and 'rosdep update'

A mensagem que mais me chamou a atenção foi a que refere o erro na abertura da porta serie: /dev/ttyACM0 (esta porta serie não existe, mas sim a ttyUSB0).

Um dos problemas potenciais é a porta não ter permissões. Pelo que o primeiro passo é verificar e atribuir as permissões correctas. Mas duvido que seja um problema pois o container está a correr como root.

Experimentei as seguintes possibilidades (três) para solucionar este erro, só o ultimo funcionou adequadamente:

  • Alterar o mapeamento do device entre o host e o container no ficheiro docker-compose.hbr_ntbd_intel.yml não funcionou.
  • Criar o link simbólico (ln -s /dev/ttyUSB0 /dev/ttyACM0)
  • Alterar o ficheiro NTBD_launch.launch dentro do docker container de modo a que a porta a  usar seja a /dev/ttyUSB0, assim como trocar o baud rate para 57600 (ver mais abaixo o procedimento).

Depois de executar a alteração do ficheiro NTBD_launch.launch voltei a executar o comando do docker compose e o programa funcionou bem.

No raspberry pi 3 também funciona bem dentro do docker com excepção de um problema de visualização já que a imagem fica invertida no plano (de cabeça para baixo) conforme se pode ver na imagem principal do artigo.

Exemplo de utilização dos docker containers do ntbd num raspberry pi 3 apenas para efeitos de visualização.

Alteração do ficheiro launch no container

Com os containers do projecto ntbd a serem executados, correr o seguinte comando para obter o id do container.

sudo docker ps

Usar os primeiros digitos do CONTAINER ID correspondentes ao container do ntbd e lançar uma shell no container com o seguinte comando:

sudo docker exec -it ctnid /bin/bash

Este comando devolve uma prompt no interior do container, pelo que o passo seguinte é instalar o nano, para o usar na alteração do ficheiro launch.

apt install nano

De seguida executamos o nano para alterar o ficheiro com o comando:

nano /catkin_ws/src/ntbd_core/launch/NTBD_launch.launch

Trocamos a porta e o baud rate, para ttyUSB0 e 57600, e gravamos o ficheiro e saimos da shell.

 <arg name="baud" default="115200"/>
<arg name="port" default="/dev/ttyACM0"/>

Posteriormente reiniciamos o container com o comando:

docker restart ctnid

Para mim tive que sair e voltar a entrar mais uma vez, para funcionar.

informação de alteração do container disponivel no seguinte endereço:

How to edit files within docker containers