Mini-braço robótico com duas juntas de servo. O joystick do Kit B 37 controla cada eixo em tempo real (modo MANUAL). O botão SW do joystick alterna para modo SEQUÊNCIA que reproduz 5 posições pré-gravadas. O LCD exibe o ângulo de cada junta, o modo activo e uma barra gráfica de posição.
| Componente | Pino Arduino | Nota |
|---|---|---|
| LCD 20×4 (I2C) | A4 (SDA) / A5 (SCL) | Endereço 0x27 |
| Servo 1 — junta base | D9 (PWM 50 Hz) | SG90 ou MG90S |
| Servo 2 — junta braço | D10 (PWM 50 Hz) | SG90 ou MG90S |
| Joystick VRx (eixo X) | A0 | Controla Servo 1 |
| Joystick VRy (eixo Y) | A1 | Controla Servo 2 |
| Joystick SW (botão) | D2 (INPUT_PULLUP) | Alterna MANUAL/SEQUÊNCIA |
Liga D9 e D10. Carrega um sketch simples: sv1.write(90); sv2.write(90); — os dois servos vão para o centro. Confirma que o braço está na posição neutra antes de continuar.
Lê X→ sv1, Y→ sv2 com map(0,1023,0,180). Adiciona zona morta de ±80 em redor do centro. O LCD actualiza sem flickering comparando com os últimos ângulos.
Define 5 posições em struct. Ao premir SW, alterna para sequência que cicla pelas posições com delay configurável. Novo premir de SW regressa a MANUAL.
Regista ° (slot 4) e bloco para barra (slot 5). Integra tudo no dashboard das 4 linhas. Testa MANUAL ↔ SEQUÊNCIA com o joystick.
#include <Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
Servo sv1, sv2;
#define JX A0
#define JY A1
#define JSW 2
#define DZ 80 // zona morta do joystick
// ── Chars custom ────────────────────────────────────────────
byte ic_grau[8] = {0b00110,0b01001,0b01001,0b00110,0b00000,0b00000,0b00000,0b00000};
byte ic_bloco[8] = {0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111};
// ── Estado ──────────────────────────────────────────────────
int a1 = 90, a2 = 90;
int ult1 = -1, ult2 = -1;
bool modoSeq = false;
int seqIdx = 0;
unsigned long tSW = 0, tSeq = 0;
// ── Sequência de 5 posições (junta1, junta2, pausa ms) ──────
struct PosSeq { int a1, a2, ms; const char* nome; };
const PosSeq seq[5] = {
{ 0, 90, 1200, "Inicio "},
{ 45, 45, 900, "Baixo Esq"},
{ 90, 135, 1000, "Centro Cim"},
{135, 45, 900, "Alto Dir "},
{180, 90, 1200, "Fim curso "},
};
// ── Dashboard LCD ────────────────────────────────────────────
void dashboard(const char* modo) {
// Só redesenha quando os ângulos mudam
if (a1 != ult1 || a2 != ult2) {
lcd.setCursor(0, 1);
lcd.print("J1:"); lcd.print(a1);
lcd.write(4); // °
lcd.print(" J2:"); lcd.print(a2);
lcd.write(4); lcd.print(" ");
// Linha 2 — barra de J1 (0–180 → 0–20 blocos)
lcd.setCursor(0, 2); lcd.print("[");
int b = a1 * 18 / 180;
for (int i=0; i<18; i++) i < b ? lcd.write(5) : lcd.write(32);
lcd.print("]");
ult1 = a1; ult2 = a2;
}
lcd.setCursor(0, 3);
lcd.print("Modo: "); lcd.print(modo); lcd.print(" ");
}
void setup() {
lcd.createChar(4, ic_grau);
lcd.createChar(5, ic_bloco);
lcd.init(); lcd.backlight();
sv1.attach(9); sv1.write(90);
sv2.attach(10); sv2.write(90);
pinMode(JSW, INPUT_PULLUP);
lcd.setCursor(0,0); lcd.print("Braco Servo PR.FT9_5");
}
void loop() {
// Botão SW — alterna modo
if (digitalRead(JSW)==LOW && millis()-tSW>400) {
modoSeq=!modoSeq; seqIdx=0; tSW=millis();
lcd.setCursor(0,3);
lcd.print(modoSeq ? "Modo: SEQUENCIA " : "Modo: MANUAL ");
}
if (!modoSeq) {
// ── MODO MANUAL — joystick ──────────────────────────────
int dx = analogRead(JX) - 512;
int dy = analogRead(JY) - 512;
if (dx > DZ) a1 = constrain(a1 + 2, 0, 180);
if (dx < -DZ) a1 = constrain(a1 - 2, 0, 180);
if (dy > DZ) a2 = constrain(a2 + 2, 0, 180);
if (dy < -DZ) a2 = constrain(a2 - 2, 0, 180);
sv1.write(a1); sv2.write(a2);
dashboard("MANUAL ");
delay(20);
} else {
// ── MODO SEQUÊNCIA — cicla pelas 5 posições ─────────────
const PosSeq& p = seq[seqIdx];
a1 = p.a1; a2 = p.a2;
sv1.write(a1); sv2.write(a2);
dashboard(p.nome);
delay(p.ms);
seqIdx = (seqIdx + 1) % 5;
}
}