A Saga do Braço Robótico: O Ínicio de um sonho!
Hoje vamos iniciar uma saga aqui, que estou estou enrolando há um bom tempo para fazer: a construção completa de um braço robótico profissional (podemos chamar assim?). O objetivo é que, no fim, tenhamos um braço robótico de um tamanho considerável e com funções relativamente complexas.
A minha ideia aqui sempre foi tentar trazer projetos completos, mas, como podemos ver, esse blog está parado há muito tempo. Por isso desta vez vou fazer um pouco diferente: vou postando em partes, enquanto vou fazendo (e tendo paciência para escrever um texto minimamente conciso).
Estava na aula de Cálculo 3 e o professor explicou coordenadas esféricas. O meu primeiro pensamento foi: “Isso é perfeito para controlar um braço robótico por coordenadas polares!”.
Logo já comecei a fazer alguns rabiscos no caderno e aqui estamos (estudar que é bom, nada).
Mas afinal, o que são coordenadas esféricas?
É uma outra forma de determinarmos a localização de pontos no espaço, invés de usar X, Y e Z, usamos r, θ (teta) e φ (fi).
- r = Distância da origem até o ponto;
- θ = Ângulo em relação ao eixo vertical;
- φ = Ângulo em relação ao eixo horizontal.
Não vou me aprofundar nessa parte, pois essa matéria é MUITO chata. Mas se você quiser estudar a fundo, recomendo o canal Matematéca no YouTube, ou, se você gostar de sofrer, recomendo o livro do Stewart (mentira, não recomendo isso nem para o meu pior inimigo).
Usando alguns conceitos de trigonometria, como a Lei dos Cossenos, fiz o seguinte esboço e cheguei nestas fórmulas:

p\:=\:\sqrt{x^2\:+\:y^{2\:}\:+\:z^2}a\:=\:\frac{\left(acos\left(\frac{p^2\:-\:2\:\cdot\:ka^2}{2\:\cdot \:\:ka^2}\right)\right)\cdot 180}{\pi }b\:=\:\frac{\left(acos\left(\frac{z}{p}\right)+\:acos\left(\frac{\frac{1}{2}\cdot \:\:\:p}{ka}\right)\right)\cdot 180}{\pi }c\:=\:\frac{\left(arctan\left(\frac{y}{z}\right)\right)\cdot 180}{\pi }Neste primeiro momento, vamos fazer um braço mais simples e conceitual para ver minhas habilidades com cálculo (que não são muitas), mas, para isso, temos que colocar duas condições: vamos ter apenas dois semi-braços e eles vão ter exatamente o mesmo tamanho.
Isso porque, quando estamos trabalhando com triângulos isósceles, nossa vida fica BEM mais simples.
No fim, pretendo que tenhamos um braço com três semi-braços, mas isso já deixa essa matemática muito mais complicada.
Um detalhe importante nessas fórmulas é que, como vamos controlar servosmotores, precisamos converter radianos em graus, por isso, multiplicamos por 180 e dividimos por pi.
Após isso, fiz um código bem simples para Arduino, para que possamos testar o conceito numa miniatura.
/*
Braço robótico controlado por coordenadas cartesianas
Autor: Ryan Avila Sobrinho Gomes
Data de inicio: 28/09/2025
*/
//Inclui bibliotecas
#include <math.h>
#include <VarSpeedServo.h>
//Define pinos
#define potx A0
#define poty A1
#define potz A2
#define pin_servo_a 2
#define pin_servo_b 3
#define pin_servo_c 4
//Define constantes
const float ka = 50.0;
#define velocidade 100
//Declara variaveis
float x_destino;
float y_destino;
float z_destino;
float angulo_a;
float angulo_b;
float angulo_c;
const float distancia_max = 2.0 * ka;
//Inicia servos
VarSpeedServo servo_a;
VarSpeedServo servo_b;
VarSpeedServo servo_c;
void setup() {
Serial.begin(9600);
//Declarando funções dos pinos
pinMode(potx, INPUT);
pinMode(poty, INPUT);
pinMode(potz, INPUT);
servo_a.attach(pin_servo_a);
servo_b.attach(pin_servo_b);
servo_c.attach(pin_servo_c);
}
void loop() {
//Le potenciometros
x_destino = fmap(analogRead(potx), 0, 1023, -distancia_max, distancia_max);
y_destino = fmap(analogRead(poty), 0, 1023, -distancia_max, distancia_max);
z_destino = fmap(analogRead(potz), 0, 1023, 0, distancia_max);
//Chama função de restrição de movimento
restricao_movimento(x_destino, y_destino, z_destino);
//Calcula angulos
calculo_angulos(x_destino, y_destino, z_destino);
//Limita os angulos de 0 a 180 (essa parte é especificamente para servos motores)
long ang_servo_a = angulo_a;
long ang_servo_b = 180 - angulo_b;
long ang_servo_c = fmap(angulo_c, -90, 90, 0, 180);
ang_servo_a = constrain(ang_servo_a, 0, 180);
ang_servo_b = constrain(ang_servo_b, 0, 180);
ang_servo_c = constrain(ang_servo_c, 0, 180);
//Parte de comunicação com o Processing, (formato: c,b,a\ln)
Serial.print(ang_servo_c);
Serial.print(",");
Serial.print(ang_servo_b);
Serial.print(",");
Serial.print(ang_servo_a);
Serial.println();
//Posiciona servos
servo_a.write(ang_servo_a, velocidade);
servo_b.write(ang_servo_b, velocidade);
servo_c.write(ang_servo_c, velocidade);
delay(50); //Delay para estabilização
}
//Funções de calculo dos angulos
void calculo_angulos(float x, float y, float z) {
//Calculo de p
float p_quadrado = x * x + y * y + z * z;
float p = sqrt(p_quadrado);
//proteção caso p seja 0
if (p < 0.01)
return;
//calculos dos angulos (resultado já em graus)
angulo_a = ((acos((p_quadrado - 2.0 * ka * ka) / (2.0 * ka * ka))) * 180.0) / M_PI;
angulo_b = ((acos(z / p) + acos((0.5 * p) / ka)) * 180.0) / M_PI;
angulo_c = (atan2(y, x) * 180.0) / M_PI;
}
//Função de restrição de movimento
void restricao_movimento(float &x, float &y, float &z) {
//limite do z (apenas backup, já que foi restringida na leitura)
if (z < 0)
z = 0;
//Calcula distancia pedida
float distancia_quadrado = x * x + y * y + z * z;
//Se a distancia for maior que o maximo
if (distancia_quadrado > distancia_max * distancia_max) {
float distancia = sqrt(distancia_quadrado);
float fator = distancia_max / distancia;
x = x * fator;
y = y * fator;
z = z * fator;
}
}
//função de mapeamento para float
float fmap(float valor, float min_entrada, float max_entrada, float min_saida, float max_saida) {
return (valor - min_entrada) * (max_saida - min_saida) / (max_entrada - min_entrada) + min_saida;
}
Este código possui duas funções principais: uma de conversão de coordenadas cartesianas (X,Y,Z) para coordenadas esféricas e outra para limitação do movimento.
Tentei fazer este código da forma mais genérica possível, para que não haja dificuldades ao adaptá-lo a outros projetos.
Ainda falta ajustar alguns passos, como a função de limitação, especificamente para servosmotores de 180°. Além disso, como estamos trabalhando com funções do tipo float, foi necessário desenvolver uma função de mapeamento específica para esse tipo.
Os próximos passos serão criar um simulador no Processing para esse código (que na verdade está quase pronto) e desenvolver a parte mecânica de um braço-conceito em escala reduzida para ver se está tudo funcionando (o qual está sendo impresso neste momento).
Após isso vamos fazer um segundo braço robótico com três semi-braços e que tenham tamanhos diferentes, e, após isso vamos fazer a versão definitiva.
Como sempre disse, um dos motivos deste blog é criar o meu acervo de projetos pessoais, fiz esse post meio sem nada demais feito, mas quero lembrar desses detalhes.
Não sei quando vai sair a próxima parte desse projeto (a vida de universitário e CLT é difícil), mas prometo não abandoná-lo (ou não também).
Em breve eu volto com o próximo capítulo dessa novela!!








Publicar comentário