Este proyecto utiliza un ESP32 junto con un mando PS4 para controlar luces, motor y otras funciones. A lo largo de este tutorial explicaremos el código detallado, el hardware necesario y cómo implementar esta solución en tu vehículo DIY.
Materiales necesarios:
- ESP32 (Wemos D1 Mini32 en este ejemplo).
- Mando PS4.
- Driver de motor BTS7960.
- Luces LED y sus controladores.
- Resistencias 1K.
- Fuentes de alimentación según el diseño.
- TIP120 o IRLZ44N x3 o más según sea necesario para controlar luces.
- Visual Studio Code
Esquema de conexiones:
Componente | Pin ESP32 |
---|---|
Luces nocturnas y largas | GPIO27 |
Intermitente derecho | GPIO22 |
Intermitente izquierdo | GPIO21 |
Amplificador Bluetooth | GPIO33 |
Luz trasera | GPIO25 |
BTS7960 EN | GPIO19 |
BTS7960 L_PWM | GPIO26 |
BTS7960 R_PWM | GPIO18 |
Batería (voltaje analógico) | A0 |
Configuración del código
El siguiente código configura el ESP32 para recibir comandos del mando PS4 y controlar luces y el motor a través del driver BTS7960.
#include <PS4Controller.h>
// Pines para luces
#define LUZ_NOCTURNA_Y_LARGAS 27 // Pin compartido para luces nocturnas y largas
#define INTERMITENTE_DERECHO 22
#define INTERMITENTE_IZQUIERDO 21
#define LUZ_TRASERA 25 // Pin para las luces traseras
#define AMPLIFICADOR_BLUETOOTH 33 // Pin para el amplificador Bluetooth
// Pines del BTS7960 (Motor)
#define BTS7960_L_PWM 26
#define BTS7960_R_PWM 18
#define BTS7960_EN 19
// Pin para medir la batería
#define PIN_BATERIA A0 // Pin analógico conectado a la batería
// Variables para luces
bool luzNocturnaActiva = false;
bool luzLargasActiva = false;
bool intermitenteDerechoActivo = false;
bool intermitenteIzquierdoActivo = false;
bool warningsActivos = false;
bool amplificadorActivo = false;
unsigned long tiempoIntermitente = 0;
bool estadoIntermitente = false;
// Variables para el control del motor
int velocidadMotor = 0;
int direccionActual = 0; // 0: detenido, 1: adelante, -1: atrás
// Variables para la batería
float voltajeBateria = 0.0;
const float VOLTAJE_MINIMO = 10.0; // Voltaje mínimo (batería vacía)
const float VOLTAJE_MAXIMO = 12.6; // Voltaje máximo (batería cargada)
// Configuración inicial
void setup() {
Serial.begin(115200);
// Configuración de pines
pinMode(LUZ_NOCTURNA_Y_LARGAS, OUTPUT);
pinMode(LUZ_TRASERA, OUTPUT);
pinMode(INTERMITENTE_DERECHO, OUTPUT);
pinMode(INTERMITENTE_IZQUIERDO, OUTPUT);
pinMode(AMPLIFICADOR_BLUETOOTH, OUTPUT);
pinMode(BTS7960_EN, OUTPUT);
// Configurar PWM para BTS7960 y luces
ledcSetup(0, 5000, 8);
ledcAttachPin(BTS7960_L_PWM, 0);
ledcSetup(1, 5000, 8);
ledcAttachPin(BTS7960_R_PWM, 1);
ledcSetup(2, 5000, 8); // PWM para luces nocturnas y largas
ledcAttachPin(LUZ_NOCTURNA_Y_LARGAS, 2);
ledcSetup(3, 5000, 8); // PWM para luces traseras
ledcAttachPin(LUZ_TRASERA, 3);
//CAMBIAR LA MAC POR LA DEL EQUIPO DE ULTIMA CONEXION CON EL MANDO
if (PS4.begin("XX:XX:XX:XX:XX:XX")) {
Serial.println("Esperando conexión con el mando PS4...");
} else {
Serial.println("Error al iniciar la conexión Bluetooth.");
}
}
// Función para controlar las luces nocturnas y largas
void controlarLuces(bool nocturna, bool largas) {
if (largas) {
ledcWrite(2, 233); // Aproximadamente 11V
} else if (nocturna) {
ledcWrite(2, 100); // Aproximadamente 8V
} else {
ledcWrite(2, 0); // Apagar las luces
}
}
// Función para controlar las luces traseras. AJUSTAR PARAMETROS SEGUN VOLTAJES NECESARIOS
void controlarLuzTrasera(bool nocturna, bool parado) {
if (parado) {
Serial.println("Luces traseras: Modo freno activado");
ledcWrite(3, 20); // PWM más alto para luz de freno
} else if (nocturna) {
Serial.println("Luces traseras: Modo nocturno");
ledcWrite(3, 5); // PWM bajo para luz trasera en modo nocturno
} else {
Serial.println("Luces traseras: Apagadas");
ledcWrite(3, 0); // Apagar luces traseras
}
}
// Función para controlar el motor con BTS7960
void controlarMotor(int direccion, int velocidad) {
velocidad = constrain(velocidad, 0, 255);
digitalWrite(BTS7960_EN, HIGH);
if (direccion == 1) { // Adelante
ledcWrite(0, velocidad);
ledcWrite(1, 0);
} else if (direccion == -1) { // Atrás
ledcWrite(0, 0);
ledcWrite(1, velocidad);
} else { // Detenido
digitalWrite(BTS7960_EN, LOW);
ledcWrite(0, 0);
ledcWrite(1, 0);
}
}
// Manejar intermitentes y warnings
void manejarIntermitentes() {
unsigned long tiempoActual = millis();
if (warningsActivos) {
if (tiempoActual - tiempoIntermitente >= 500) {
tiempoIntermitente = tiempoActual;
estadoIntermitente = !estadoIntermitente;
digitalWrite(INTERMITENTE_DERECHO, estadoIntermitente ? HIGH : LOW);
digitalWrite(INTERMITENTE_IZQUIERDO, estadoIntermitente ? HIGH : LOW);
}
} else {
if (intermitenteDerechoActivo) {
if (tiempoActual - tiempoIntermitente >= 500) {
tiempoIntermitente = tiempoActual;
estadoIntermitente = !estadoIntermitente;
digitalWrite(INTERMITENTE_DERECHO, estadoIntermitente ? HIGH : LOW);
}
} else {
digitalWrite(INTERMITENTE_DERECHO, LOW);
}
if (intermitenteIzquierdoActivo) {
if (tiempoActual - tiempoIntermitente >= 500) {
tiempoIntermitente = tiempoActual;
estadoIntermitente = !estadoIntermitente;
digitalWrite(INTERMITENTE_IZQUIERDO, estadoIntermitente ? HIGH : LOW);
}
} else {
digitalWrite(INTERMITENTE_IZQUIERDO, LOW);
}
}
}
// Loop principal
void loop() {
if (PS4.isConnected()) {
// Luces nocturnas (Circle)
if (PS4.Circle()) {
luzNocturnaActiva = !luzNocturnaActiva;
if (!luzNocturnaActiva) luzLargasActiva = false; // Apagar largas si nocturnas se desactivan
controlarLuces(luzNocturnaActiva, luzLargasActiva);
Serial.println(luzNocturnaActiva ? "Luces nocturnas encendidas" : "Luces nocturnas apagadas");
delay(200);
}
// Luces largas (Square)
if (PS4.Square()) {
luzLargasActiva = !luzLargasActiva;
if (luzLargasActiva) {
controlarLuces(false, true); // Activar largas
} else {
controlarLuces(luzNocturnaActiva, false); // Volver a nocturnas si estaban activas
}
Serial.println(luzLargasActiva ? "Luces largas encendidas" : "Luces largas apagadas");
delay(200);
}
// Intermitentes (R1 y L1)
if (PS4.R1()) {
intermitenteDerechoActivo = !intermitenteDerechoActivo;
Serial.println(intermitenteDerechoActivo ? "Intermitente derecho activado" : "Intermitente derecho desactivado");
delay(200);
}
if (PS4.L1()) {
intermitenteIzquierdoActivo = !intermitenteIzquierdoActivo;
Serial.println(intermitenteIzquierdoActivo ? "Intermitente izquierdo activado" : "Intermitente izquierdo desactivado");
delay(200);
}
if (PS4.Triangle()) {
warningsActivos = !warningsActivos;
Serial.println(warningsActivos ? "Warnings activados" : "Warnings desactivados");
delay(200); // Evitar rebotes
}
// Regular velocidad con R2 y L2
int valorR2 = PS4.R2Value(); // Rango de 0 a 255
int valorL2 = PS4.L2Value(); // Rango de 0 a 255
if (valorR2 > 0) {
direccionActual = 1; // Adelante
velocidadMotor = valorR2;
} else if (valorL2 > 0) {
direccionActual = -1; // Atrás
velocidadMotor = valorL2;
} else {
direccionActual = 0; // Detenido
velocidadMotor = 0;
}
controlarMotor(direccionActual, velocidadMotor);
// Controlar luces traseras
bool frenoActivo = (direccionActual == 0 && velocidadMotor == 0);
controlarLuzTrasera(luzNocturnaActiva, frenoActivo);
// Manejar intermitentes
manejarIntermitentes();
} else {
Serial.println("Mando desconectado. Esperando conexión...");
delay(1000);
}
}
Configuración en PlatformIO
El archivo platformio.ini
contiene la configuración necesaria para este proyecto:
[env:wemos_d1_mini32]
platform = espressif32
board = wemos_d1_mini32
framework = arduino
; Configurar el monitor serial a 115200
monitor_speed = 115200
; Dependencias necesarias
lib_deps =
https://github.com/aed3/PS4-esp32.git
Resultado final
Con esta configuración, el ESP32 puede:
- Activar y desactivar luces nocturnas y largas mediante el botón circulo y cuadrado del mando PS4.
- Controlar intermitentes y warnings con los botones
L1
, R1 y triángulo. - Ajustar la dirección y velocidad del motor con
R2
yL2
.
Esta implementación es ideal para proyectos de vehículos DIY, proporcionando un sistema de control sencillo pero completo.
Para más proyectos, visita nuestra web principal.