A classe joint_limits_interface contém as estruturas de dados para representar os limites das articulações, métodos para carregar os limites a aplicar a partir de formatos comuns, como ficheiros URDF e o servidor de parâmetros ROS, e métodos para impor os limites a diferentes tipos de interfaces de hardware.
O joint_limits_interface é usado na implementação do hardware_interface no método write() (ou equivalente) já após a actualização dos controladores. A imposição de limites substituirá os comandos definidos pelos controladores e não é efectuada no mesmo buffer de dados.
Na configuração de uma interface de limites de articulação (joint limits interface), devem-se tomar em consideração os seguintes elementos:
Representação dos limites
JointLimits – Posição, velocidade, aceleração, empurrão (jerk) e esforço.
SoftJointLimits – Limites de posição de software, k_p, k_v
Mais informações sobre os joint limits e os soft joint limits mais abaixo.
Fontes para obtenção dos limites:
Ficheiros URDF – Existem métodos para carregar do URDF as informações dos limites ao movimento das articulações, joint limits, (posição, velocidade e esforço), assim como sobre os soft limites das articulações, soft joint limits.
Servidor de parâmetros do ROS – Existem métodos de para carregar a partir do servidor de parâmetros do ROS os limites ao movimento das articulações, joint limits, (posição, velocidade, aceleração, empurrão e esforço). A especificação dos parâmetros é a mesma usada no MoveIt, e inclui também os limites de empurrão e esforço.
A implementação concreta dos limites varia consoante o tipo de articulação.
Para articulação controladas por esforço, a implementação de limites flexíveis do PR2 foi portada.
Para articulação com posição controlada, uma versão modificada dos limites flexíveis PR2 foi implementada.
Para articulação com velocidade controlada, foi implementado um método de saturação simples com base nos limites de aceleração e velocidade.
No seguinte link está o exemplo oficial da utilização de joint limits na implementação de uma hardware_interface de um robot.
Os limites da articulações, podem ser de dois tipos, os hard, que são simplesmente referidos de Joint Limits e os soft referidos como Soft Joint Limits.
A diferença fundamental entre os dois tipos de limites é que os soft limits consideram um limite de segurança (safety limit) que é tomado em consideração na implementação dos limites no software.
Os dois tipos de limites podem ser especificado no ficheiro urdf, conforme o exemplo abaixo. O elemento <limit> contêm os atributos correspondentes aos hard joint limits. Enquanto que o elemento <safety_controller> contêm os atributos correspondentes aos soft joint limits.
Para saber mais sobre ficheiros URDF no ROS, consultar o artigo sobre Ficheiros URDF.
Para saber mais sobre os safety limits consultar a informação disponível no seguinte endereço: https://wiki.ros.org/pr2_controller_manager/safety_limits
Instruções simples para usar o joint limits no hardware_interface do robot.
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 diferentesferramentas 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:
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:
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:
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 spawnerpara carregar, iniciar, parar e descarregar automaticamente um ou mais controladores.
Exemplo de ficheiro launch para lançar controllers.
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_managerfornece cinco chamadas de serviço (com indicação do respectivo tipo de mensagens):
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:
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 diferentesinterfaces 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
O ficheirode 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.
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.
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
Os braços robóticos eezyBotArm baseados em servo motores, como o eezyBotArm MK1 e o eezyBotArm MK2 podem ser controlados com uma das soluções abaixo indicadas.
Um micro-controlador com uma biblioteca para controlo de servos, normalmente um atmega328p ou atmega2560
Um modulo Mini Maestro da Pololu para 12 servos, com um PC
Um modulo PCA9865 para 16 servos, com um micro-controlador ou um PC
Para além da opção dos movimentos estarem simplesmente programados, também poderemos considerar como inputs para definir os movimentos do braço o seguinte hardware: