Universidad Anáhuac México Norte
Proyecto Final
Estacionamiento con Automatizaciones en Arduino
Programación Estructurada de Microcontroladores
Leonardo Velasco Ojeda
Emilio Arriaga Guzmán
Índice
Introducción........................................................................................................................... 2
Descripción del proyecto...................................................................................................... 3
Funcionalidades................................................................................................................. 3
Lista de componentes........................................................................................................... 4
Simulación.............................................................................................................................. 8
Enlace................................................................................................................................ 8
Esquema Eléctrico................................................................................................................. 9
Circuito..................................................................................................................................12
Diagrama de Flujo del Código............................................................................................ 15
FOTOGRAFÍAS, VIDEOS Y DESCRIPCIÓN........................................................................ 19
RESULTADOS....................................................................................................................... 23
CONCLUSIONES.................................................................................................................. 24
BIBLIOGRAFÍA..................................................................................................................... 25
CÓDIGO.................................................................................................................................27
1
Estacionamiento Automatizado
Introducción
En la actualidad, los sistemas inteligentes aplicados al control vehicular y a la gestión de
estacionamientos han adquirido una relevancia significativa en entornos urbanos,
comerciales y residenciales. La creciente necesidad de soluciones automatizadas que
optimicen el uso del espacio, reduzcan los tiempos de espera y mejoren la experiencia de
los usuarios ha impulsado el desarrollo de tecnologías orientadas a la automatización y
supervisión de estos sistemas. En este contexto, los estacionamientos inteligentes
representan una alternativa eficiente y sostenible frente a los métodos tradicionales de
gestión.
El presente trabajo tiene como objetivo el diseño e implementación de un prototipo funcional
que permita explorar las posibilidades que ofrece la automatización en espacios de
estacionamiento, aplicando principios de electrónica, programación en sistemas embebidos
y análisis de datos. A través de este proyecto se busca no solo demostrar la viabilidad
técnica de integrar múltiples dispositivos para el control de acceso, iluminación y monitoreo,
sino también fomentar un enfoque de diseño orientado a la eficiencia operativa y a la
experiencia del usuario.
Un componente fundamental en el desarrollo de este sistema es la programación, ya que
permite coordinar el funcionamiento de sensores, actuadores y dispositivos de salida
mediante estructuras de control lógicas y eficientes. La implementación en lenguaje C++
para la plataforma Arduino implica el uso de condicionales, bucles, funciones y estructuras
de datos que garantizan una respuesta precisa y coherente ante los estímulos del entorno.
Además, la programación facilita la modularidad del sistema, permitiendo su escalabilidad y
mantenimiento, así como la integración de nuevas funcionalidades sin comprometer la
estabilidad general del conjunto. De este modo, la lógica de control se convierte en el eje
que articula cada elemento del sistema para lograr un comportamiento autónomo e
inteligente.
Desde una perspectiva académica y formativa, este desarrollo permite fortalecer habilidades
de análisis, diseño y resolución de problemas reales mediante el uso de tecnologías
accesibles, versátiles y con potencial de implementación en escenarios reales.
2
Descripción del proyecto
El proyecto consiste en la implementación de un prototipo de estacionamiento inteligente a
pequeña escala, controlado mediante una placa Arduino. Este sistema integra diversos
sensores y dispositivos de salida que trabajan de forma conjunta para automatizar las
funciones principales de un estacionamiento: el control de acceso, la gestión de iluminación,
la detección de vehículos y la visualización en tiempo real del estado del estacionamiento.
El objetivo es demostrar cómo la tecnología embebida puede aplicarse eficazmente en la
optimización de recursos y en la mejora de la experiencia del usuario.
Funcionalidades
1. Control de acceso automatizado
○ Apertura y cierre de una pluma de acceso mediante el accionamiento de un
servomotor.
Activación remota del mecanismo a través de un control infrarrojo (IR), que
permite enviar comandos específicos para abrir o cerrar la barrera.
2. Gestión remota del sistema de iluminación
○ Control de luces LED RGB mediante el mismo control IR, con posibilidad de
seleccionar entre siete colores distintos.
○ Opción de encendido y apagado remoto de la iluminación general del
estacionamiento.
3. Ajuste automático de la intensidad lumínica
○ Regulación automática del brillo de las luces en función de dicha detección,
con el fin de mejorar la visibilidad.
4. Indicadores visuales por espacio de estacionamiento
○ Detección del estado de cada plaza mediante sensores ultrasónicos que
identifican la presencia de un vehículo.
○ Implementación de LEDs RGB colocados en cada plaza de estacionamiento.
El color verde indica un espacio disponible, mientras que el rojo señala que
está ocupado.
5. Conteo en tiempo real de espacios disponibles
○ Monitoreo constante del número de espacios libres u ocupados dentro del
estacionamiento.
○ Visualización clara de esta información en un display de 7 segmentos
ubicado en la entrada del sistema, lo cual permite al usuario saber si hay
3
disponibilidad antes de ingresar.
6. Registro y análisis de datos de uso
○ Captura de información sobre los eventos de entrada y salida de vehículos.
○ Análisis de los datos para determinar tiempos de ocupación.
Estas funcionalidades se coordinan a través de un programa desarrollado en C++ para la
plataforma Arduino, que garantiza una interacción precisa y en tiempo real entre los
diferentes módulos del sistema. El diseño modular permite futuras expansiones, como la
integración con aplicaciones móviles o el monitoreo remoto vía internet.
Lista de componentes
Componente Imagen
Protoboard
Mini protoboard
4
Resistencias
Jumpers H-h H-m M-m
Micro servomotor
Display de 7 segmentos
5
Fotorresistor
Receptor Infrarrojo
Tira de 12 Neo Pixels
Control remoto por IR
6
Sensor de distancia ultrasónico
LEDs rojos
LEDs verdes
7
Simulación
Enlace
https://www.tinkercad.com/things/34RX7iwIANs-exquisite-luulia-curcan/editel?returnTo=https
%3A%2F%2Fwww.tinkercad.com%2Fdashboard&sharecode=bMWrnoMiUpD33gRhmRJ9N
HJvmnf6-wOjthEDQiorFLY
8
Esquema Eléctrico
9
10
11
Circuito
12
13
14
Diagrama de Flujo del Código
15
16
17
18
Fotografías
19
20
21
Vídeo
https://photos.app.goo.gl/GEPyGWx5ZbGDCPyg9
Descripción
Se simuló el funcionamiento de un estacionamiento inteligente, integrando tanto
características típicas de sistemas automatizados modernos como funciones innovadoras
que mejoran la experiencia del usuario.
El sistema se desarrolló utilizando sensores ultrasónicos para la detección de vehículos en
los espacios cuya implementación permite un monitoreo del tiempo de ocupación; acceso
mediante una pluma que utiliza un servomotor; tiras y LEDs para la señalización visual, y un
display de 7 segmentos para mostrar información relevante como el número de espacios
disponibles; implementación de un remoto para control del acceso de vehículos y el color
de la iluminación cuya intensidad es regulada automáticamente mediante un fotorresistor.
22
RESULTADOS
El estacionamiento funcionó de la forma esperada a como lo es en un entorno real.
Aplicamos exitosamente varios sensores y estructuras de datos para el funcionamiento de
nuestro estacionamiento inteligente, simulando de una manera muy acertada el cómo
funciona un estacionamiento en tiempo real.
El sistema implementado permite recopilar y analizar datos en tiempo real sobre el uso de
los cajones de estacionamiento mediante sensores ultrasónicos. Utilizando tres variables
principales (tiempoOcupado, duracionOcupado y estadoPrevio), se registran
eventos de ocupación y liberación, calculando dos métricas clave y posibles acorde a este
proyecto:
1. Tiempo promedio de ocupación por cajón: : Una vez que el sensor ultrasónico
detecta un objeto, comienza un conteo sobre el tiempo que hay un auto estacionado
en ese cajón específicamente, esto podría ayudar a estimar ingresos en caso de ser
un estacionamiento de paga o a encontrar patrones en los usuarios.
La fórmula para calcular el tiempo promedio usamos la siguiente fórmula:
float promedio = conteoUsos[i] > 0 ?
(totalOcupado[i] / conteoUsos[i]) / 1000.0 :
0;
Para este caso, bajo una simulación de 5 minutos obtenemos los siguientes
resultados:
2. Tasa de ocupación por cajón: Esta métrica nos indicaría cuáles son los cajones
donde más autos suelen estacionarse, ayudando a identificar las zonas del
estacionamiento las cuales se usan en mayor o menor medida, pudiendo tomar
acciones preventivas como el redireccionamiento de tráfico a estas zonas con poca
ocupación.
La fórmula utilizada es:
3. float tasa = (totalOcupado[i] * 100.0) / tiempoTotal;
23
El análisis hecho en una simulación de 5 minutos fue el siguiente:
24
Nuestro prototipo de estacionamiento inteligente no solo cumple con las funciones básicas
de control de acceso y disponibilidad, sino que también sienta las bases para el análisis de
datos y la optimización continua del sistema.
25
CONCLUSIONES
Gracias a este proyecto, pudimos aplicar de manera práctica los conocimientos adquiridos a
lo largo del curso, además de aprender de forma autónoma el uso de diversos componentes
electrónicos. La combinación entre electrónica y programación nos permitió crear una
solución innovadora a un problema común en nuestra vida cotidiana, como lo es la gestión
eficiente de espacios de estacionamiento.
Este proyecto demuestra que, con componentes accesibles y una lógica de diseño clara, es
posible desarrollar sistemas inteligentes capaces de recolectar, interpretar y actuar sobre
datos en tiempo real. Además de cumplir con su función operativa, nuestro prototipo sienta
las bases para aplicaciones más avanzadas, como la visualización de métricas, la
predicción de afluencia, implementación de un sistema de cobro automatizado e incluso una
autonomía total del sistema, además de una experiencia de usuario más eficiente y
personalizada.
Las posibilidades que ofrecen los microcontroladores en este tipo de soluciones son
prácticamente infinitas, y es nuestra responsabilidad como futuros ingenieros conocer a
fondo su funcionamiento y potencial. Este tipo de proyectos no solo fortalece nuestras
habilidades técnicas, sino también nuestro compromiso con el desarrollo de tecnología útil,
accesible y orientada a mejorar la calidad de vida en nuestro entorno.
26
BIBLIOGRAFÍA
Adafruit. (Marzo, 2025). AdaFruit Neopixel. Consultado el 05 de mayo del 2025 de:
https://docs.arduino.cc/libraries/adafruit-neopixel/
Joachimsmeyer, Armin (Septiembre, 2024). IR Remote. Consultado el 05 de mayo del 2025
de: https://docs.arduino.cc/libraries/irremote/
27
CÓDIGO
#include <IRremote.hpp>
#include <Servo.h>
#include <Adafruit_NeoPixel.h>
//---- CONFIGURACIÓN DE PINES ----
const int PHOTORESISTOR_PIN = A7;
const int IR_PIN = 11;
const int SERVO_PIN = 28;
// a, b, c, d, e, f, g
const int DISPLAY_PINS[] = {7, 8, 6, 5, 4, 3, 2};
// Tira led
const int NUM_PIXELS = 8;
const int LED_STRIP = 12;
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUM_PIXELS, LED_STRIP,
NEO_GRB + NEO_KHZ800);
//---- ESTRUCTURAS DE DATOS ----
// Definir la estructura para el sensor ultrasónico
struct Ultrasonico {
int triggerPin;
int echoPin;
bool estado;
};
// Definir la estructura para los LEDs
struct Led {
int greenPin;
int redPin;
};
// Estructura de botones del control remoto
struct RemoteButtons {
constexpr static uint8_t POWER = 0x9; // Activar / Desactivar pluma
constexpr static uint8_t CERO = 0x16; // Activar
constexpr static uint8_t ONE = 0xC; // Desactivar
constexpr static uint8_t TWO = 0x18; // Blanco
constexpr static uint8_t THREE = 0x5E; // Sin luz
constexpr static uint8_t FOUR = 0x8; // Rojo
constexpr static uint8_t FIVE = 0x1C; // Verde
constexpr static uint8_t SIX = 0x5A; // Azul
constexpr static uint8_t SEVEN = 0x42; // Amarillo
constexpr static uint8_t EIGHT = 0x52; // Magenta
constexpr static uint8_t NINE = 0x4A; // Cian
28
} buttons;
//---- ARREGLOS PARA PARA CONTROLAR CAMBIOS ----
Ultrasonico parkingSpot[3] = {
{40, 41, false}, // Espacio 1
{44, 45, false}, // Espacio 2
{48, 49, false} // Espacio 3
};
Led parkingLight[3] = {
{42, 43},
{46, 47},
{50, 51}
};
// Colores LED strip (orden acorde a los botones)
uint32_t ledColors[] = {
pixels.Color(255, 255, 255), // Blanco
pixels.Color(0, 0, 0), // Sin luz
pixels.Color(255, 0, 0), // Rojo
pixels.Color(0, 255, 0), // Verde
pixels.Color(0, 0, 255), // Azul
pixels.Color(255, 255, 0), // Amarillo
pixels.Color(255, 0, 255), // Magenta
pixels.Color(0, 255, 255) // Cian
};
// Dígitos del display
const bool displayDigits[10][7] = {
{true, true, true, true, true, true, false}, // 0
{false, true, true, false, false, false, false}, // 1
{true, true, false, true, true, false, true}, // 2
{true, true, true, true, false, false, true}, // 3
};
//---- VARIABLES ----
uint32_t selectedColor = ledColors[0]; // Color de la tira LED
inicialmente blanco
int lightValue = 0; // Intensidad de la luz
bool gate = false; // Estado de la pluma
int numSpots = 3; // Spots disponibles
int prevBrightness = -1; // Para evitar actualizar si no
hay cambio
unsigned long tiempoOcupado[3] = {0, 0, 0}; // Marca de tiempo
29
cuando se ocupó
unsigned long duracionOcupado[3] = {0, 0, 0}; // Duración actual
bool estadoPrevio[3] = {false, false, false}; // Para detectar
cambios de estado
// Variables adicionales mínimas para las métricas
unsigned long totalOcupado[3] = {0, 0, 0}; // Tiempo total
acumulado
unsigned int conteoUsos[3] = {0, 0, 0}; // Veces que se ha
ocupado
Servo servoMotor;
// ---- SETUP ----
void setup() {
Serial.begin(9600);
pixels.begin();
// Configurar pines de sensores ultrasónicos y LEDs
for (int i = 0; i < 3; i++) {
pinMode(parkingSpot[i].triggerPin, OUTPUT);
pinMode(parkingSpot[i].echoPin, INPUT);
pinMode(parkingLight[i].greenPin, OUTPUT);
pinMode(parkingLight[i].redPin, OUTPUT);
}
// Configurar pines del display de 7 segmentos
for (int i = 0; i < 7; i++) {
pinMode(DISPLAY_PINS[i], OUTPUT);
}
// Inicializar arrays de métricas
memset(totalOcupado, 0, sizeof(totalOcupado));
memset(conteoUsos, 0, sizeof(conteoUsos));
IrReceiver.begin(IR_PIN, ENABLE_LED_FEEDBACK); //IR receiver
servoMotor.attach(SERVO_PIN); // Servo motor
desactivar(); // Se cierra le pluma
}
30
// ---- BUCLE DE EJECUCIÓN ----
void loop() {
estado_spot();
int libres = contar_spots(); // Guardar espacios libres
if (IrReceiver.decode()) {
uint8_t code = IrReceiver.decodedIRData.command;
// Activar / desactivar pluma solo si hay lugar disponible
if ((code == buttons.POWER || code == buttons.CERO) && !gate &&
libres > 0) {
activar();
} else if ((code == buttons.POWER || code == buttons.ONE) && gate)
{
desactivar();
} else {
cambiar_color(code);
}
IrReceiver.resume();
}
ajustar_luz();
// Generar reporte cada 5 minutos
static unsigned long ultimoReporte = 0;
if(millis() - ultimoReporte > 300000) {
generarReporte();
ultimoReporte = millis();
}
delay(300);
}
// ---- FUNCIONES ----
// Función para cerrar la pluma
void desactivar() {
gate = false;
Serial.println("Desactivando pluma...");
servoMotor.write(0);
}
31
// Función para abrir la pluma
void activar() {
gate = true;
Serial.println("Activando pluma...");
servoMotor.write(90);
}
// Función para medir la distancia en cm con el ultrasónico
long medirDistancia(int trigger, int echo) {
digitalWrite(trigger, LOW);
delayMicroseconds(2);
digitalWrite(trigger, HIGH);
delayMicroseconds(10);
digitalWrite(trigger, LOW);
long duracion = pulseIn(echo, HIGH, 30000); // timeout de 30ms
if (duracion == 0) return 999; // si no hay respuesta, valor muy alto
return duracion / 58;
}
// Función que valida si los espacios de estacionamiento están ocupados
// y cambia el estado de los LEDs
void estado_spot(){
for (int i = 0; i < 3; i++) {
int distancia = medirDistancia(parkingSpot[i].triggerPin,
parkingSpot[i].echoPin);
Serial.print("Sensor ");
Serial.print(i + 1);
Serial.print(": ");
Serial.println(distancia);
bool ocupadoAhora = distancia < 10;
// Detectar cambio de estado: LIBRE -> OCUPADO
if (!estadoPrevio[i] && ocupadoAhora) {
tiempoOcupado[i] = millis(); // Marca de tiempo al ocupar
}
// Si sigue ocupado, mostrar cuánto tiempo ha estado ocupado
if (ocupadoAhora) {
32
duracionOcupado[i] = millis() - tiempoOcupado[i];
Serial.print(">> Tiempo ocupado del spot ");
Serial.print(i + 1);
Serial.print(": ");
Serial.print(duracionOcupado[i] / 1000.0);
Serial.println(" segundos");
}
// Actualizar LEDs
if (ocupadoAhora) {
digitalWrite(parkingLight[i].greenPin, LOW);
digitalWrite(parkingLight[i].redPin, HIGH);
} else {
digitalWrite(parkingLight[i].greenPin, HIGH);
digitalWrite(parkingLight[i].redPin, LOW);
}
// Guardar estados actualizados
estadoPrevio[i] = ocupadoAhora;
parkingSpot[i].estado = ocupadoAhora;
Serial.print("Estado spot ");
Serial.print(i + 1);
Serial.println(ocupadoAhora ? ": OCUPADO" : ": LIBRE");
Serial.println(" -------------------- ");
Serial.println("");
}
}
// Función que valida los espcio de estacionamiento disponibles
// y los muestra en el display de 7 segmentos
int contar_spots() {
int num = 0;
for (int i = 0; i < 3; i++) {
if (parkingSpot[i].estado) num++;
}
num = 3 - num;
num = constrain(num, 0, 3); // evitar overflow
for (int i = 0; i < 7; i++) {
33
digitalWrite(DISPLAY_PINS[i], displayDigits[num][i]);
}
return num;
}
void ajustar_luz() {
lightValue = analogRead(PHOTORESISTOR_PIN);
Serial.print("Fotorresistor: ");
Serial.println(lightValue);
// Mapear de 0 (poca luz) a 600 (mucha luz)
// para que haya más brillo con menos luz
int brightness = map(lightValue, 0, 600, 255, 0);
brightness = constrain(brightness, 0, 255);
// Solo actualizar si el brillo cambió
if (brightness != prevBrightness) {
pixels.setBrightness(brightness);
color_tiraLED();
prevBrightness = brightness;
}
}
// Función que cambiar el color de la tira LED dependiendo del código
// recibido del control remoto
void cambiar_color(uint8_t code) {
switch (code) {
case buttons.TWO: selectedColor = ledColors[0]; break; // Blanco
case buttons.THREE: selectedColor = ledColors[1]; break; // Sin luz
case buttons.FOUR: selectedColor = ledColors[2]; break; // Rojo
case buttons.FIVE: selectedColor = ledColors[3]; break; // Verde
case buttons.SIX: selectedColor = ledColors[4]; break; // Azul
case buttons.SEVEN: selectedColor = ledColors[5]; break; //
Amarillo
case buttons.EIGHT: selectedColor = ledColors[6]; break; // Magenta
case buttons.NINE: selectedColor = ledColors[7]; break; // Cian
default: return; // No hacer nada si no es un botón de color
}
color_tiraLED();
}
// Aplicar color a la tira LED
34
void color_tiraLED(){
for (int i = 0; i < pixels.numPixels(); i++) {
pixels.setPixelColor(i, selectedColor);
}
pixels.show();
}
void actualizarMetricas() {
for(int i = 0; i < 3; i++) {
// Usamos el estado actual del parkingSpot
bool ocupadoAhora = parkingSpot[i].estado;
// Detección de cambios
if(ocupadoAhora && !estadoPrevio[i]) {
tiempoOcupado[i] = millis(); // Registra inicio de ocupación
}
else if(!ocupadoAhora && estadoPrevio[i]) {
// Calcula duración y actualiza acumuladores
duracionOcupado[i] = millis() - tiempoOcupado[i];
totalOcupado[i] += duracionOcupado[i];
conteoUsos[i]++;
// Log inmediato
Serial.print("Cajón ");
Serial.print(i+1);
Serial.print(" liberado. Tiempo: ");
Serial.print(duracionOcupado[i] / 1000.0);
Serial.println(" segundos");
}
estadoPrevio[i] = ocupadoAhora;
}
}
void generarReporte() {
unsigned long tiempoTotal = millis() / 1000; // Segundos desde inicio
Serial.println("\n=== REPORTE ESTADÍSTICO ===");
Serial.println("Cajón | Ocupación | Tiempo Promedio");
Serial.println("------|-----------|----------------");
for(int i = 0; i < 3; i++) {
float tasa = (totalOcupado[i] * 100.0) / tiempoTotal;
35
float promedio = conteoUsos[i] > 0 ?
(totalOcupado[i] / conteoUsos[i]) / 1000.0 : 0;
Serial.print(i+1);
Serial.print(" ");
Serial.print(tasa, 1);
Serial.print("% ");
Serial.print(promedio, 1);
Serial.println(" seg");
// Mostrar también duración actual si está ocupado
if(parkingSpot[i].estado) {
Serial.print(" >> Ocupado actualmente por: ");
Serial.print((millis() - tiempoOcupado[i]) / 1000.0);
Serial.println(" segundos");
}
}
}
36