Tanque Robô Arduino Controlado por Joystick Sem Fio PS2
Componentes e Materiais
| Componente | Quantidade | Observações |
|---|---|---|
| Arduino UNO | 1 | |
| Driver de Motor Dual H-Bridge L298 (SparkFun) | 1 | |
| Kit Robô Tanque DIY | 1 | |
| Controle Sem Fio Sony PS2 | 1 |
Aplicativos e Serviços Online
- Arduino IDE
Sobre o Projeto
Neste tutorial, mostro como usar um joystick sem fio PlayStation 2 (PS2) para pilotar um tanque robótico. Uma placa Arduino Uno é o núcleo do projeto. Ela recebe comandos do controle sem fio e define a velocidade dos motores. Outras placas de desenvolvimento (NodeMCU, Firebeetle, etc.) também podem ser usadas, e os princípios aqui apresentados aplicam-se a outros modelos de robôs e gadgets.




Passo 1: Ferramentas e Materiais

Ferramentas utilizadas:
- Ferro de solda e fio – os motores DC já vêm com fios soldados, mas podem quebrar.
- Folha de espuma EVA (ou outro material não condutor) – para isolar as placas do chassi de alumínio.
- Fita dupla face – para fixar a espuma e o módulo H-Bridge.
- Tesoura – para cortar retângulos de espuma.
Peças de hardware:
- Placa de desenvolvimento baseada em Arduino Uno – controlador principal, fácil de programar.
- Módulo H-Bridge L298N de canal duplo – amplifica sinais de 3.3V/5V para 12V nos motores.
- Kit Chassi Tanque Robô DIY – inclui dois motores DC, engrenagens, esteiras, parafusos, porcas e ferramentas de montagem.
- Controle Remoto Sem Fio PS2 – envia comandos via receptor para o microcontrolador.
- Baterias 18650 3.7V (x3) – em série fornecem 11.1V para motores 12V.
- Suporte para 3 baterias 18650 (3S) – fixa na traseira do tanque.
- Carregador de baterias 18650.
- Jumpers – 6 macho-fêmea para sinais H-Bridge/Arduino, 2 macho-macho para 5V/GND.
- Cabo USB Tipo-B – para upload do código.
Passo 2: Montagem do Robô
A primeira parte foi a montagem da estrutura. O kit surpreendeu pela qualidade e peças sobressalentes. Inclui todas as ferramentas necessárias (chaves Allen, chave de fenda), ótimo para iniciantes. Como ponto negativo, a documentação (manual em chinês) não é amigável e há poucos tutoriais online. O chassi de alumínio pode causar curto-circuito se pinos das placas tocarem a estrutura.


Passo 3: Ligação do Circuito

Um pacote de três baterias 18650 na traseira fornece 11.1V. O L298N recebe sinais de 5V do Arduino e fornece tensão maior aos motores, permitindo rotação em ambas as direções.

Conexões Arduino Uno:
- Pino digital 3 → H-Bridge ENA
- Pino digital 5 → H-Bridge IN1
- Pino digital 4 → H-Bridge IN2
- Pino digital 8 → H-Bridge IN3
- Pino digital 7 → H-Bridge IN4
- Pino digital 6 → H-Bridge ENB
- Pino 5V → H-Bridge 5V
- Pino GND → H-Bridge GND
- Pino digital 10 → Receptor PS2 pino 6
- Pino digital 11 → Receptor PS2 pino 2
- Pino digital 12 → Receptor PS2 pino 1
- Pino digital 13 → Receptor PS2 pino 7
- Pino 3.3V → Receptor PS2 pino 5
- Pino GND → Receptor PS2 pino 4
Conexões H-Bridge:
- ENA → Arduino D3, IN1 → D5, IN2 → D4, IN3 → D8, IN4 → D7, ENB → D6
- 5V → Arduino 5V, GND → Arduino GND
- GND → Fio negativo do pacote de baterias
- 12V → Fio positivo do pacote de baterias
- OUT1 → Motor direito fio negativo, OUT2 → Motor direito fio positivo
- OUT3 → Motor esquerdo fio positivo, OUT4 → Motor esquerdo fio negativo
Receptor PS2:
- Pino 1 (data) → Arduino D12
- Pino 2 (command) → Arduino D11
- Pino 4 (ground) → Arduino GND
- Pino 5 (power) → Arduino 3.3V
- Pino 6 (attention) → Arduino D10
- Pino 7 (clock) → Arduino D13


Passo 4: Configuração do Arduino IDE
- Baixe e instale a versão mais recente do Arduino IDE em arduino.cc.
- Adicione a biblioteca Arduino PS2X: baixe em GitHub, descompacte e copie as pastas para a pasta libraries/tools do Arduino IDE.
Passo 5: Biblioteca do Controle PS2 Explicada

O controle PS2 tem 20 botões digitais e 2 sticks analógicos. Usei a biblioteca PS2X de Bill Porter. Cria-se um objeto PS2X ps2x; e configura-se com ps2x.config_gamepad(clock, command, attention, data, pressure?, rumble?). Funções principais: ps2x.Button(button) para leitura digital e ps2x.Analog(stick_axis) para leitura analógica (0-255). Mapeamento dos botões: direcionais (PSB_PAD_UP, DOWN, LEFT, RIGHT), ação (PSB_GREEN/TRIANGLE, PSB_RED/CIRCLE, PSB_BLUE/CROSS, PSB_PINK/SQUARE), gatilhos (PSB_L1, R1, L2, R2), sticks (PSB_L3, R3), menu (PSB_SELECT, START). Eixos analógicos: PSS_LY, PSS_LX, PSS_RY, PSS_RX.
Passo 6: Sketch #1 – Botões Direcionais (D-pad)

Emula controles de jogos antigos: botões ligam/desligam motores em velocidade fixa. Mapeamento: CIMA = frente, BAIXO = ré, ESQUERDA = virar esquerda, DIREITA = virar direita. Ao virar, motores giram em sentidos opostos para girar no próprio eixo.

Código Arduino (Sketch #1): – veja seção Código abaixo.
Explicação do Código: Inclui PS2X_lib.h. Define pinos do H-Bridge. Variáveis globais: ps2x, error, type, vibrate. No setup(): configura pinos como saída, desabilita motores, inicia Serial (57600), configura ps2x com pinos (13,11,10,12), verifica erros e tipo de controle. No loop(): lê botões D-pad e define pinos de saída para mover rodas. Usa PWM nos pinos ENA/ENB (0-1023). Se nenhum botão pressionado, desabilita motores.
Passo 7: Sketch #2 – Stick Analógico Esquerdo e Botões Digitais (L2 e R2)

Usa stick analógico esquerdo para direção (eixo X) e botões L2/R2 como acelerador/freio/ré. Pressiona R2 para frente, L2 para ré. A posição X do stick mapeia diferença de velocidade entre esteiras.

No loop: lê PSS_LX, mapeia 0-255 para -1023 a 1023. Ajusta velocidade de cada motor. Se R2 pressionado, move frente com PWM proporcional. Se L2, move ré. Se nenhum, desabilita motores.
Passo 8: Sketch #3 – Sticks Analógicos Esquerdo e Direito (Direção Diferencial)

Meu favorito: cada stick controla uma esteira. Stick esquerdo → esteira esquerda, direito → esteira direita. Lê eixos Y de ambos (PSS_LY, PSS_RY), mapeia para -1023 a 1023. Define direção de cada motor conforme sinal. Usa zona morta (±50) para desabilitar motores.

Passo 9: Sketch #4 – Apenas Stick Analógico Esquerdo

Único joystick controla tudo: velocidade de cada esteira depende de X e Y. Ótimo em recursos (sobram botões), mas mais complexo de entender. Baseado em tutorial de direção diferencial.

Passo 10: Considerações Finais
Esforcei-me para tornar este projeto claro e educativo. Se gostou, curta e compartilhe! Confira meus outros tutoriais de robótica:
Considere apoiar futuros projetos com doação Bitcoin: 1FiWFYSjRaL7sLdr5wr6h86QkMA6pQxkXJ

Código
Sketch #1 – Botões Direcionais
// PS2 Tank by Igor Fonseca @2019
// Controls a robotic tank using a PS2 joystick, using D-pad buttons
// based on an example using the PS2X library by Bill Porter 2011
#include
#define ENA 3
#define MOTORA_1 4
#define MOTORA_2 5
#define MOTORB_1 8
#define MOTORB_2 7
#define ENB 6
PS2X ps2x;
int error = 0;
byte type = 0;
byte vibrate = 0;
void setup() {
pinMode(ENA, OUTPUT); pinMode(MOTORA_1, OUTPUT); pinMode(MOTORA_2, OUTPUT);
pinMode(ENB, OUTPUT); pinMode(MOTORB_1, OUTPUT); pinMode(MOTORB_2, OUTPUT);
digitalWrite(ENA,0); digitalWrite(ENB,0);
Serial.begin(57600);
error = ps2x.config_gamepad(13,11,10,12, true, true);
if(error == 0) Serial.println("Found Controller, configured successful");
else if(error == 1) Serial.println("No controller found, check wiring or reset the Arduino");
else if(error == 2) Serial.println("Controller found but not accepting commands");
else if(error == 3) Serial.println("Controller refusing to enter Pressures mode, may not support it.");
type = ps2x.readType();
switch(type) {
case 0: Serial.println("Unknown Controller type"); break;
case 1: Serial.println("DualShock Controller Found"); break;
case 2: Serial.println("GuitarHero Controller Found"); break;
}
}
void loop() {
if(error == 1) return;
ps2x.read_gamepad(false, vibrate);
if(ps2x.Button(PSB_PAD_UP)) {
digitalWrite(MOTORA_1,LOW); digitalWrite(MOTORA_2,HIGH);
digitalWrite(MOTORB_1,HIGH); digitalWrite(MOTORB_2,LOW);
analogWrite(ENB, 1023); analogWrite(ENA, 1023);
Serial.println("Move forward");
}
if(ps2x.Button(PSB_PAD_RIGHT)) {
digitalWrite(MOTORA_1,HIGH); digitalWrite(MOTORA_2,LOW);
digitalWrite(MOTORB_1,HIGH); digitalWrite(MOTORB_2,LOW);
analogWrite(ENB, 1023); analogWrite(ENA, 1023);
Serial.println("Turn right");
}
if(ps2x.Button(PSB_PAD_LEFT)) {
digitalWrite(MOTORA_1,LOW); digitalWrite(MOTORA_2,HIGH);
digitalWrite(MOTORB_1,LOW); digitalWrite(MOTORB_2,HIGH);
analogWrite(ENB, 1023); analogWrite(ENA, 1023);
Serial.println("Turn left");
}
if(ps2x.Button(PSB_PAD_DOWN)) {
digitalWrite(MOTORA_1,HIGH); digitalWrite(MOTORA_2,LOW);
digitalWrite(MOTORB_1,LOW); digitalWrite(MOTORB_2,HIGH);
analogWrite(ENB, 1023); analogWrite(ENA, 1023);
Serial.println("Move back");
}
if (!ps2x.Button(PSB_PAD_DOWN) && !ps2x.Button(PSB_PAD_UP) && !ps2x.Button(PSB_PAD_RIGHT) && !ps2x.Button(PSB_PAD_LEFT)) {
analogWrite(ENB, 0); analogWrite(ENA, 0);
}
delay(50);
}
Sketch #2 – Stick Analógico e Botões L2/R2
// PS2 Tank by Igor Fonseca @2019
#include
#define ENA 3
#define MOTORA_1 4
#define MOTORA_2 5
#define MOTORB_1 8
#define MOTORB_2 7
#define ENB 6
int motor_right_speed = 0;
int motor_left_speed = 0;
PS2X ps2x;
int error = 0;
byte type = 0;
byte vibrate = 0;
void setup() {
pinMode(ENA, OUTPUT); pinMode(MOTORA_1, OUTPUT); pinMode(MOTORA_2, OUTPUT);
pinMode(ENB, OUTPUT); pinMode(MOTORB_1, OUTPUT); pinMode(MOTORB_2, OUTPUT);
digitalWrite(ENA,0); digitalWrite(ENB,0);
Serial.begin(57600);
error = ps2x.config_gamepad(13,11,10,12, true, true);
if(error == 0) Serial.println("Found Controller, configured successful");
else if(error == 1) Serial.println("No controller found, check wiring or reset the Arduino");
else if(error == 2) Serial.println("Controller found but not accepting commands");
else if(error == 3) Serial.println("Controller refusing to enter Pressures mode, may not support it.");
type = ps2x.readType();
switch(type) {
case 0: Serial.println("Unknown Controller type"); break;
case 1: Serial.println("DualShock Controller Found"); break;
case 2: Serial.println("GuitarHero Controller Found"); break;
}
}
void loop() {
if(error == 1) return;
ps2x.read_gamepad(false, vibrate);
int nJoyL = ps2x.Analog(PSS_LX);
nJoyL = map(nJoyL, 0, 255, 1023, -1023);
int motor_right_speed = 1023;
int motor_left_speed = 1023;
if (nJoyL < 0) motor_right_speed = motor_right_speed + nJoyL;
if (nJoyL > 0) motor_left_speed = motor_left_speed - nJoyL;
if(ps2x.Button(PSB_R2)) {
digitalWrite(MOTORA_1,LOW); digitalWrite(MOTORA_2,HIGH);
digitalWrite(MOTORB_1,HIGH); digitalWrite(MOTORB_2,LOW);
analogWrite(ENA, motor_right_speed); analogWrite(ENB, motor_left_speed);
}
if(ps2x.Button(PSB_L2)) {
digitalWrite(MOTORA_1,HIGH); digitalWrite(MOTORA_2,LOW);
digitalWrite(MOTORB_1,LOW); digitalWrite(MOTORB_2,HIGH);
analogWrite(ENA, motor_right_speed); analogWrite(ENB, motor_left_speed);
}
if(!ps2x.Button(PSB_L2) && !ps2x.Button(PSB_R2)) {
analogWrite(ENA, 0); analogWrite(ENB, 0);
}
delay(50);
}
Sketch #3 – Dois Sticks Analógicos (Direção Diferencial)
// PS2 Tank by Igor Fonseca @2019
#include
#define ENA 3
#define MOTORA_1 4
#define MOTORA_2 5
#define MOTORB_1 8
#define MOTORB_2 7
#define ENB 6
PS2X ps2x;
int error = 0;
byte type = 0;
byte vibrate = 0;
void setup() {
pinMode(ENA, OUTPUT); pinMode(MOTORA_1, OUTPUT); pinMode(MOTORA_2, OUTPUT);
pinMode(ENB, OUTPUT); pinMode(MOTORB_1, OUTPUT); pinMode(MOTORB_2, OUTPUT);
digitalWrite(ENA,0); digitalWrite(ENB,0);
Serial.begin(57600);
error = ps2x.config_gamepad(13,11,10,12, true, true);
if(error == 0) Serial.println("Found Controller, configured successful");
else if(error == 1) Serial.println("No controller found, check wiring or reset the Arduino");
else if(error == 2) Serial.println("Controller found but not accepting commands");
else if(error == 3) Serial.println("Controller refusing to enter Pressures mode, may not support it.");
type = ps2x.readType();
switch(type) {
case 0: Serial.println("Unknown Controller type"); break;
case 1: Serial.println("DualShock Controller Found"); break;
case 2: Serial.println("GuitarHero Controller Found"); break;
}
}
void loop() {
if(error == 1) return;
ps2x.read_gamepad(false, vibrate);
int nJoyL = ps2x.Analog(PSS_LY);
int nJoyR = ps2x.Analog(PSS_RY);
nJoyL = map(nJoyL, 0, 255, 1023, -1023);
nJoyR = map(nJoyR, 0, 255, -1023, 1023);
if(nJoyR > 50) {
digitalWrite(MOTORA_1,HIGH); digitalWrite(MOTORA_2,LOW);
analogWrite(ENA, 1023);
}
if(nJoyR < -50) {
digitalWrite(MOTORA_1,LOW); digitalWrite(MOTORA_2,HIGH);
analogWrite(ENA, 1023);
}
if (abs(nJoyR) < 50) analogWrite(ENA, 0);
if(nJoyL > 50) {
digitalWrite(MOTORB_1,HIGH); digitalWrite(MOTORB_2,LOW);
analogWrite(ENB, 1023);
}
if(nJoyL < -50) {
digitalWrite(MOTORB_1,LOW); digitalWrite(MOTORB_2,HIGH);
analogWrite(ENB, 1023);
}
if (abs(nJoyL) < 50) analogWrite(ENB, 0);
delay(50);
}
Sketch #4 – Apenas Stick Esquerdo
// PS2 Tank by Igor Fonseca @2019
#include
#define ENA 3
#define MOTORA_1 4
#define MOTORA_2 5
#define MOTORB_1 8
#define MOTORB_2 7
#define ENB 6
int motor_right_speed = 0;
int motor_left_speed = 0;
PS2X ps2x;
int error = 0;
byte type = 0;
byte vibrate = 0;
void setup() {
pinMode(ENA, OUTPUT); pinMode(MOTORA_1, OUTPUT); pinMode(MOTORA_2, OUTPUT);
pinMode(ENB, OUTPUT); pinMode(MOTORB_1, OUTPUT); pinMode(MOTORB_2, OUTPUT);
digitalWrite(ENA,0); digitalWrite(ENB,0);
Serial.begin(57600);
error = ps2x.config_gamepad(13,11,10,12, true, true);
if(error == 0) Serial.println("Found Controller, configured successful");
else if(error == 1) Serial.println("No controller found, check wiring or reset the Arduino");
else if(error == 2) Serial.println("Controller found but not accepting commands");
else if(error == 3) Serial.println("Controller refusing to enter Pressures mode, may not support it.");
type = ps2x.readType();
switch(type) {
case 0: Serial.println("Unknown Controller type"); break;
case 1: Serial.println("DualShock Controller Found"); break;
case 2: Serial.println("GuitarHero Controller Found"); break;
}
}
void loop() {
if(error == 1) return;
ps2x.read_gamepad(false, vibrate);
int nJoyX = ps2x.Analog(PSS_LX);
int nJoyY = ps2x.Analog(PSS_LY);
nJoyX = map(nJoyX, 0, 255, -1023, 1023);
nJoyY = map(nJoyY, 0, 255, 1023, -1023);
int nMotMixL, nMotMixR;
float fPivYLimit = 1023.0;
float nMotPremixL, nMotPremixR;
int nPivSpeed;
float fPivScale;
if (nJoyY >= 0) {
nMotPremixL = (nJoyX >= 0) ? 1023.0 : (1023.0 + nJoyX);
nMotPremixR = (nJoyX >= 0) ? (1023.0 - nJoyX) : 1023.0;
} else {
nMotPremixL = (nJoyX >= 0) ? (1023.0 - nJoyX) : 1023.0;
nMotPremixR = (nJoyX >= 0) ? 1023.0 : (1023.0 + nJoyX);
}
nMotPremixL = nMotPremixL * nJoyY / 1023.0;
nMotPremixR = nMotPremixR * nJoyY / 1023.0;
nPivSpeed = nJoyX;
fPivScale = (abs(nJoyY) > fPivYLimit) ? 0.0 : (1.0 - abs(nJoyY) / fPivYLimit);
nMotMixL = (1.0 - fPivScale) * nMotPremixL + fPivScale * (nPivSpeed);
nMotMixR = (1.0 - fPivScale) * nMotPremixR + fPivScale * (-nPivSpeed);
motor_left_speed = nMotMixL;
motor_right_speed = nMotMixR;
if (motor_right_speed > 50) {
digitalWrite(MOTORB_1,HIGH); digitalWrite(MOTORB_2,LOW);
} else if (motor_right_speed < -50) {
digitalWrite(MOTORB_1,LOW); digitalWrite(MOTORB_2,HIGH);
} else {
digitalWrite(MOTORB_1,LOW); digitalWrite(MOTORB_2,LOW);
}
if (motor_left_speed > 50) {
digitalWrite(MOTORA_1,LOW); digitalWrite(MOTORA_2,HIGH);
} else if (motor_left_speed < -50) {
digitalWrite(MOTORA_1,HIGH); digitalWrite(MOTORA_2,LOW);
} else {
digitalWrite(MOTORA_1,LOW); digitalWrite(MOTORA_2,LOW);
}
analogWrite(ENA, abs(motor_left_speed));
analogWrite(ENB, abs(motor_right_speed));
if (abs(motor_left_speed) > 50 || abs(motor_right_speed) > 50) Serial.println("Moving!");
delay(50);
}
Esquemáticos


Processo de manufatura
- Construa um Robô de Streaming de Vídeo Controlado por Internet com Arduino e Raspberry Pi
- Unopad: Controlador MIDI Arduino Perfeito para Ableton Live
- Robô Desviador de Obstáculos com Servo: Construa com Arduino e HC-SR04
- Controlar Roomba Create 2 com Arduino e Android: Guia Passo a Passo
- Braço Robótico 6 GDL Controlado por Nunchuk com Arduino Mega
- Controle Dois Motores de Passo com Arduino Nano e Joystick – Tutorial Simples
- Volante Joystick Arduino Personalizado para Jogos
- Crie um Battle Bot Controlado Remotamente com um Controle PS2
- Controle Braço Robótico Arduino via App Android Dedicado
- Robô Comedor com Arduino Nano – Guia Passo a Passo