Sistema de Control de Semáforos Inteligente con Datos en Tiempo Real
Componentes y materiales
| Componente | Cantidad | Notas |
|---|---|---|
| Arduino Yun | 1 | |
| Arduino UNO | 1 | o cualquier otra placa Arduino |
| Sensor ultrasónico HC-SR04 | 1 | |
| DS3231 RTC (Reloj en tiempo real) | 1 | |
| LED (genérico) | 3 | 1 rojo, 1 amarillo, 1 verde |
| Resistencia 330 ohm | 3 | |
| Módulos 433 MHz | 1 par | 1 transmisor, 1 receptor |
| Dispositivo Android | 1 | |
| Tarjeta SD | 1 | |
| Kit de desarrollo rápido AllThingsTalk IOTOPIA | 1 | |
| Cables jumper (genéricos) | 1 set |
Aplicaciones y servicios online
- Arduino IDE
- Android Studio
- Servicio de hosting de base de datos MySQL
Sobre el proyecto
Introducción
El tráfico tiene la capacidad de irritar a los más pacientes y va empeorando. ¿Qué pasaría si pudiéramos cambiar esto con semáforos inteligentes? Hemos creado un Sistema de Información de Semáforos que informa al conductor a qué velocidad debe circular para llegar al cruce y pasar la luz verde sin superar el límite de velocidad máximo. Y cuando el conductor debe esperar inevitablemente la luz roja, le indica cuándo está a punto de ponerse en verde.

Un semáforo envía datos sobre cuánto tiempo permanecerá en verde o el tiempo hasta la próxima luz verde, etc., a una base de datos online. Un GPS o una aplicación en tu smartphone recuperará los datos de la base de datos y calculará la velocidad deseada para pasar la luz verde. Mostrará el tiempo de espera restante hasta el final de la fase roja cuando sea inevitable que tengas que esperar.
Ejemplo
Estás conduciendo en una zona de 70 km/h, respetando el límite. El semáforo que tienes por delante está en rojo y está a punto de ponerse en verde en 30 segundos. Estás a 500 metros del semáforo, así que el sistema te recomendará avanzar hacia la luz a 60 km/h.

Demostración del proyecto
¿Cómo lo hemos hecho?
Para demostrar nuestro proyecto, creamos un semáforo con Arduino Yun. El semáforo consta de 3 LEDs y un Reloj en Tiempo Real (RTC). Las luces cambian a intervalos determinados. El Arduino Yun guarda el tiempo en que el semáforo se pondrá en verde/rojo. Luego, ejecuta un archivo PHP que conecta con la base de datos MySQL online e inserta los datos recibidos del Arduino Yun. Una app Android (creada con Android Studio) recuperará los datos de esa base de datos. Esto se hace mediante otro archivo PHP que devuelve los datos del semáforo en formato JSON. La app calcula la velocidad deseada y mostrará un temporizador de cuenta regresiva cuando no puedas pasar la luz verde.

Para calcular la velocidad deseada, la app necesita conocer la distancia al semáforo. Esto se hace calculando la distancia según las coordenadas GPS. Pero por desgracia, el GPS de un smartphone no es lo suficientemente preciso para demostrar nuestro concepto porque trabajamos a pequeña escala. Por eso usamos el módulo ultrasónico de medición de distancia (HC-SR04). El Arduino Yun recibe la distancia entre el coche y el semáforo vía módulos RF de 433 MHz. Cada vez que el Yun recibe una nueva medición del otro Arduino, actualiza los datos en la base de datos. Ahora, la app puede calcular la velocidad deseada.

Instrucciones
- Crear una base de datos MySQL online (usamos freemysqlhosting.net)
- Añadir tabla 'TrafficL_data' a la base de datos: ver esquema en imagen
- Configurar el hardware (transmisor) - Ver esquema 'Arduino transmitter'
- Subir 'Arduino Transmitter Code' al Arduino
- Conectar Arduino Yun a tu red WiFi
- Acceder al servidor Linux de Arduino YUN con Putty:
Si ves el error '-ash: nano: not found', instala nano:opkg update opkg install php5-mod-mysqli opkg install php5-cli nano /mnt/sda1/MySQL_UpdateTrafficLData.phpopkg install nanochmod 755 /mnt/sda1/MySQL_UpdateTrafficLData.php /mnt/sda1/MySQL_UpdateTrafficLData.php nano /mnt/sda1/MySQL_UpdateDistance.php chmod 755 /mnt/sda1/MySQL_UpdateDistance.php /mnt/sda1/MySQL_UpdateDistance.php - Configurar el hardware (receptor Arduino Yun) - Ver esquema 'Arduino Yun receiver'
- Subir 'Arduino Receiver & MySQLdb' al Arduino Yun
- Abrir el Monitor Serie - Deberías ver salida similar a las capturas
- Archivos de Android Studio: activity_main.xml, MainActivity.java, AndroidManifest.xml, strings.xml (*cambia la URL)
- Subir el proyecto Android Studio a tu smartphone
Instrucciones para ESP8266 [adicional]
Es posible usar un módulo basado en ESP8266 en lugar del más caro Arduino Yun:
- Crear cuenta en 000webhost.com
- Crear un sitio web
- Crear una nueva base de datos
- Subir 'CreateTable.php' y 'PostDemo.php' con el gestor de archivos. Cambiar 'username', 'password' y 'dbname' en ambos archivos.
- Crear nueva tabla: Seleccionar 'CreateTable.php' y clic en 'view'
- Instalar paquetes para ESP8266 en Arduino: Añadir URL en Archivo → Preferencias:
https://arduino.esp8266.com/stable/package_esp8266com_index.json - Seleccionar placa, puerto COM... y subir
ESP8266PostDemo.inoa tu placa basada en ESP8266 (ej. NodeMcu V3 ESP8266 12E).
Nota: El código actualiza la base de datos cada 10 segundos con valores aleatorios para pruebas. Si logras actualizar la base de datos, puedes modificar los procedimientos void MySQL_UpdateTrafficLData() y void MySQL_UpdateDistance() en el código de 'Arduino Receiver & MySQLdb'.
Consejo: No intentes implementar todo a la vez. Primero prueba cada componente por separado. Si todos funcionan bien, combina los diferentes componentes. Siéntete libre de pedir ayuda en los comentarios describiendo tu problema con el mayor detalle posible.
Código
- Arduino Transmitter Code
- Arduino Receiver & MySQLdb
- MySQL_UpdateTrafficLData.php
- MySQL_UpdateDistance.php
- EchoJSON.php
- MainActivity.java
- AndroidManifest.xml
- strings.xml
- activity_main.xml
Arduino Transmitter Code
/* IOTOPIA - 2016-2017 - Traffic Light Information System (Transmisor)
* by Pieter Luyten & Joppe Smeets
* Envía distancia a otro Arduino vía módulos RF 433MHz
* RF 433MHz: tx_pin → pin 3
* HC-SR04: trig_pin → pin 5, echo_pin → pin 6
*/
#define tx_pin 3
#define trig_pin 5
#define echo_pin 6
#include <VirtualWire.h>
#include "HCSR04.h"
HCSR04 ultrasonic(trig_pin,echo_pin);
int distance;
char CharMsg[21];
void setup() {
Serial.begin(9600);
vw_setup(2000);
vw_set_tx_pin(tx_pin);
}
void loop() {
distance = ultrasonic.Ranging(CM);
while(distance < 0) distance = ultrasonic.Ranging(CM);
sprintf(CharMsg, "%d,", distance);
vw_send((uint8_t *)CharMsg, strlen(CharMsg));
vw_wait_tx();
Serial.print("Distancia (cm): ");
Serial.println(distance);
delay(250);
}
Arduino Receiver & MySQLdb
/* IOTOPIA - 2016-2017 - Traffic Light Information System (Receptor + Subida a MySQL)
* by Pieter Luyten & Joppe Smeets
* Recibe distancia de otro Arduino vía RF
* Sube datos de semáforo y distancia a base de datos MySQL
*/
#define RedLED 5
#define OrangeLED 6
#define GreenLED 7
#define rx_pin 9
#include <VirtualWire.h>
#include <TimeAlarms.h>
#include <Wire.h>
#include "RTClib.h"
#include <Process.h>
long UnixTime_green_1, UnixTime_red_1, UnixTime_green_2, UnixTime_red_2;
long s_till_orange;
RTC_DS3231 rtc;
char StringReceived[22];
boolean i;
int interval = 5;
int distance;
void setup() {
rtc.begin();
Serial.begin(9600);
Bridge.begin();
vw_setup(2000);
vw_set_rx_pin(rx_pin);
vw_rx_start();
Alarm.timerRepeat(interval, UpdateTrafficLData);
Alarm.timerRepeat(1, PrintCurrentTime);
pinMode(GreenLED, OUTPUT);
pinMode(OrangeLED, OUTPUT);
pinMode(RedLED, OUTPUT);
digitalWrite(GreenLED, LOW);
digitalWrite(OrangeLED, LOW);
digitalWrite(RedLED, LOW);
Serial.println("Setup finished");
}
void loop() {
Alarm.delay(0);
RF_Listen();
}
void RF_Listen() {
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
if (vw_get_message(buf, &buflen)) {
int a;
for (a = 0; a < buflen; a++) StringReceived[a] = char(buf[a]);
sscanf(StringReceived, "%d", &distance);
MySQL_UpdateDistance();
Serial.print("Distancia: ");
Serial.println(distance);
}
memset(StringReceived, 0, sizeof(StringReceived));
}
void UpdateTrafficLData() {
DateTime now = rtc.now();
if (i == 1) {
UnixTime_green_1 = now.unixtime() + interval + 1;
UnixTime_red_1 = now.unixtime() + 2 * interval + 1;
UnixTime_green_2 = now.unixtime() + 3 * interval + 1;
UnixTime_red_2 = now.unixtime() + 4 * interval + 1;
MySQL_UpdateTrafficLData();
i = 0;
} else {
UnixTime_red_1 = now.unixtime() + interval + 1;
UnixTime_green_1 = now.unixtime() + (2 * interval) + 1;
UnixTime_red_2 = now.unixtime() + 3 * interval + 1;
UnixTime_green_2 = now.unixtime() + 4 * interval + 1;
MySQL_UpdateTrafficLData();
i = 1;
}
Serial.print(" Green_1 at "); Serial.print(UnixTime_green_1);
Serial.print(" Red_1 at "); Serial.print(UnixTime_red_1);
Serial.print(" Green_2 at "); Serial.print(UnixTime_green_2);
Serial.print(" Red_2 at "); Serial.println(UnixTime_red_2);
}
void MySQL_UpdateTrafficLData() {
long dataArray[4]={UnixTime_green_1, UnixTime_red_1, UnixTime_green_2,UnixTime_red_2};
Process p;
p.begin("/mnt/sda1/MySQL_UpdateTrafficLData.php");
for (int b = 0; b < 4; b++) p.addParameter(String(dataArray[b]));
p.run();
while (p.available() > 0) { char c = p.read(); Serial.print(c); }
Serial.flush();
}
void MySQL_UpdateDistance() {
Process p;
p.begin("/mnt/sda1/MySQL_UpdateDistance.php");
p.addParameter(String(distance));
p.run();
while (p.available() > 0) { char c = p.read(); Serial.print(c); }
Serial.flush();
}
void PrintCurrentTime() {
DateTime now = rtc.now();
SetLEDsTrafficL();
Serial.print(now.hour(), DEC); Serial.print(':');
Serial.print(now.minute(), DEC); Serial.print(':');
Serial.print(now.second(), DEC); Serial.print(" ");
Serial.println(now.unixtime());
}
void SetLEDsTrafficL() {
DateTime now = rtc.now();
s_till_orange = UnixTime_red_1 - now.unixtime();
if (i == 0) { digitalWrite(GreenLED, LOW); digitalWrite(OrangeLED, LOW); digitalWrite(RedLED, HIGH); }
if (i == 1 && s_till_orange <= 3) { digitalWrite(GreenLED, LOW); digitalWrite(OrangeLED, HIGH); digitalWrite(RedLED, LOW); }
if (i == 1 && s_till_orange > 3) { digitalWrite(GreenLED, HIGH); digitalWrite(OrangeLED, LOW); digitalWrite(RedLED, LOW); }
}
MySQL_UpdateTrafficLData.php
#!/usr/bin/php-cli
<?php
$UnixTime_green_1 = $argv[1];
$UnixTime_red_1 = $argv[2];
$UnixTime_green_2 = $argv[3];
$UnixTime_red_2 = $argv[4];
$DBServer = 'yourServerName';
$DBUser = 'yourUserName';
$DBPass = 'yourPassword';
$DBName = 'yourDBName';
$conn = new mysqli($DBServer, $DBUser, $DBPass, $DBName);
if ($conn->connect_error) { trigger_error('Database connection failed: ' . $conn->connect_error, E_USER_ERROR); }
$sql = "UPDATE TrafficL_data SET UnixTime_green_1='$UnixTime_green_1', UnixTime_red_1='$UnixTime_red_1', UnixTime_green_2='$UnixTime_green_2', UnixTime_red_2='$UnixTime_red_2' WHERE id=1";
if($conn->query($sql) === false) { trigger_error('Wrong SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR); }
else { echo "Data inserted!\n"; }
?>
MySQL_UpdateDistance.php
#!/usr/bin/php-cli
<?php
$Distance = $argv[1];
$DBServer = 'yourServerName';
$DBUser = 'yourUserName';
$DBPass = 'yourPassword';
$DBName = 'yourDBName';
$conn = new mysqli($DBServer, $DBUser, $DBPass, $DBName);
if ($conn->connect_error) { trigger_error('Database connection failed: ' . $conn->connect_error, E_USER_ERROR); }
$sql = "UPDATE TrafficL_data SET Distance='$Distance' WHERE id=1";
if($conn->query($sql) === false) { trigger_error('Wrong SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR); }
else { echo "Distance inserted!\n"; }
?>
EchoJSON.php
<?php
define('HOST','yourServerName');
define('USER','yourUserName');
define('PASS','yourPassword');
define('DB','yourDBName');
$con = mysqli_connect(HOST,USER,PASS,DB);
$sql = "select * from TrafficL_data";
$res = mysqli_query($con,$sql);
while($row = mysqli_fetch_array($res,MYSQLI_BOTH)){
printf('[ { "TrafficLArray":[ { "UnixTime_green_1":"%s", "UnixTime_red_1":"%s", "UnixTime_green_2":"%s", "UnixTime_red_2":"%s", "Distance":"%s" } ] } ]',
$row['UnixTime_green_1'], $row['UnixTime_red_1'],$row['UnixTime_green_2'],$row['UnixTime_red_2'],$row['Distance']);
}
mysqli_close($con);
?>
MainActivity.java (extracto)
package com.example.xxx.xxx;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity {
TextView results, recSpeed;
String JsonURL = "YourURLhere";
RequestQueue requestQueue;
private final static double maxSpeed = 18; // cm/s
private double speed;
public final static int NUMBER_OF_ENTRIES = 2;
long[] unixTimesGreen = new long[NUMBER_OF_ENTRIES];
long[] unixTimesRed = new long[NUMBER_OF_ENTRIES];
private double distance;
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private Future> timingTask;
public void tick(long milliseconds) {
timingTask = scheduler.scheduleAtFixedRate(new Runnable() {
public void run() { updateTable(); }
}, 0, milliseconds, TimeUnit.MILLISECONDS);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
results = (TextView) findViewById(R.id.jsonData);
recSpeed = (TextView) findViewById(R.id.recommendedSpeed);
updateTable();
tick(500);
}
// ... métodos updateTable(), updateTextView(), speedCalc() ...
}
Esquemas
Módulo RF 433MHz (Transmisor): tx_pin → pin 3
Módulo HC-SR04: trig_pin → pin 5, echo_pin → pin 6
Módulo RF 433MHz (Receptor): rx_pin → pin 3
Semáforo (3 LEDs): RedLED → pin 5, OrangeLED → pin 6, GreenLED → pin 7
DS3231 (RTC): SCL → SCL (pin 3 en Arduino Yun), SDA → SDA (pin 2 en Arduino Yun)


Proceso de manufactura
- Faroles de Gas: Evolución, Diseño y Fabricación Moderna
- Puntero Láser: Diseño, Fabricación y Resumen de Seguridad
- El Caleidoscopio: De la Ciencia de Brewster al Diseño Moderno
- Semáforos: Ingeniería, Historia e Innovaciones Futuras
- Diodos Emisores de Luz (LED): Desde sus Inicios a Vidas de 100 Años
- Semáforo Inteligente: Iluminación Vial Adaptativa con IoT
- Control de luces altas impulsado por IA mejora visión nocturna evitando deslumbramiento
- Accesorios para Tiras LED: Conecta, Controla y Personaliza tu Iluminación
- Ebook de sistemas de soldadura robótica: claves de inversión para fabricantes
- Diseño de Sistemas ToF de Onda Continua Alta Precisión: Visión General Completa
- Análisis técnico de una bombilla LED inteligente Sengled: despiece y revisión de conectividad Zigbee