▷ Programación Orientada a Objetos en Arduino: Domina la POO

La Programación Orientada a Objetos (POO) es un paradigma que organiza el código en objetos, los cuales combinan datos y comportamientos en una misma entidad. Aunque Arduino utiliza principalmente C++ (un lenguaje que soporta POO), muchos desarrolladores no aprovechan estas capacidades para crear proyectos más claros y escalables. En este artículo, veremos cómo aplicar POO en Arduino para lograr código más organizado, reutilizable y mantenible.

Los Cuatro Pilares de la POO

La POO se basa en cuatro principios fundamentales que también podemos aplicar en proyectos con Arduino:

Principio Descripción Beneficio en Arduino
Encapsulamiento Ocultar los detalles internos de un objeto y exponer solo una interfaz clara y controlada. Protege el hardware de accesos incorrectos.
Abstracción Mostrar solo lo esencial y simplificar la complejidad interna. Facilita el uso de componentes complejos sin necesidad de entender su implementación.
Herencia Crear nuevas clases basadas en clases ya existentes. Permite extender y reutilizar funcionalidades fácilmente.
Polimorfismo Hacer que distintos objetos puedan responder al mismo mensaje de forma diferente. Facilita la creación de interfaces uniformes para distintos dispositivos.

Ejemplo Práctico: Control de un LED con POO

Como ejemplo, crearemos una clase Led que encapsula toda la lógica necesaria para controlar un LED: encenderlo, apagarlo, regular su brillo y hacerlo parpadear.

Definición de la clase Led

// Led.h - Archivo de cabecera
#ifndef LED_H
#define LED_H

#include <Arduino.h>

class Led {
private:
  int pin;      // Pin del LED
  bool estado;  // Estado actual (true=encendido, false=apagado)
  int brillo;   // Nivel de brillo (0-255)

public:
  // Constructor
  Led(int pinLed);

  // Métodos públicos
  void iniciar();
  void encender();
  void apagar();
  void toggle();
  void setBrillo(int nivel);
  void parpadear(int veces, int duracion);
  bool getEstado();
};
#endif

Implementación de la clase Led

// Led.cpp - Implementación
#include "Led.h"

// Constructor
Led::Led(int pinLed) {
  pin = pinLed;
  estado = false;
  brillo = 255;  // Brillo máximo por defecto
}

// Inicializar pin
void Led::iniciar() {
  pinMode(pin, OUTPUT);
  apagar();
}

// Encender LED
void Led::encender() {
  estado = true;
  analogWrite(pin, brillo);
}

// Apagar LED
void Led::apagar() {
  estado = false;
  analogWrite(pin, 0);
}

// Cambiar estado
void Led::toggle() {
  if (estado) apagar();
  else encender();
}

// Ajustar brillo
void Led::setBrillo(int nivel) {
  brillo = constrain(nivel, 0, 255);
  if (estado) analogWrite(pin, brillo);
}

// Parpadear
void Led::parpadear(int veces, int duracion) {
  for (int i = 0; i < veces; i++) {
    toggle();
    delay(duracion);
  }
}

// Obtener estado
bool Led::getEstado() {
  return estado;
}

Usando la clase Led en el sketch principal

// sketch_principal.ino
#include "Led.h"

// Crear instancias de LED para diferentes colores
Led ledRojo(9);    // LED rojo en pin 9 (PWM)
Led ledVerde(10);  // LED verde en pin 10 (PWM)
Led ledAzul(11);   // LED azul en pin 11 (PWM)


void setup() {
  Serial.begin(9600);

  // Inicializar los LEDs
  ledRojo.iniciar();
  ledVerde.iniciar();
  ledAzul.iniciar();

  Serial.println("Sistema de LEDs inicializado");
}

void loop() {
  // Secuencia de LEDs con diferentes brillos
  ledRojo.setBrillo(255);
  ledRojo.encender();
  delay(1000);

  // Mostrar el estado del LED rojo
  Serial.print("Estado LED rojo: ");
  Serial.println(ledRojo.getEstado() ? "ENCENDIDO" : "APAGADO");

  ledVerde.setBrillo(150);
  ledVerde.encender();
  delay(1000);

  ledAzul.setBrillo(80);
  ledAzul.encender();
  delay(1000);

  // Apagar todos los LEDs
  ledRojo.apagar();
  ledVerde.apagar();
  ledAzul.apagar();
  delay(500);

  // Mostrar el estado del LED rojo
  Serial.print("Estado LED rojo: ");
  Serial.println(ledRojo.getEstado() ? "ENCENDIDO" : "APAGADO");

  // Hacer parpadear el LED verde 3 veces
  ledVerde.parpadear(3, 300);
  delay(1000);
}

Ejemplo de Herencia: LedRGB (con composición)

La herencia permite crear nuevas clases basadas en otras ya existentes. Esto evita repetir código y facilita extender funcionalidades. En este caso, partimos de la clase Led y creamos una nueva clase LedRGB, que controla un LED RGB compuesto por tres LEDs (rojo, verde y azul).

Definición de la clase LedRGB

// LedRGB.h
#ifndef LEDRGB_H
#define LEDRGB_H

#include "Led.h"

class LedRGB {
private:
  Led rojo;
  Led verde;
  Led azul;

public:
  LedRGB(int pinR, int pinG, int pinB)
    : rojo(pinR), verde(pinG), azul(pinB) {}

  void iniciar() {
    rojo.iniciar();
    verde.iniciar();
    azul.iniciar();
  }

  void setColor(int r, int g, int b) {
    rojo.setBrillo(r);
    verde.setBrillo(g);
    azul.setBrillo(b);

    rojo.encender();
    verde.encender();
    azul.encender();
  }

  void apagar() {
    rojo.apagar();
    verde.apagar();
    azul.apagar();
  }
};
#endif

Uso de las clases  Led + LedRGB

// sketch_principal.ino
#include "Led.h"
#include "LedRGB.h"


// Crear instancias de LED para diferentes colores
Led ledRojo(9);    // LED rojo en pin 9 (PWM)
Led ledVerde(10);  // LED verde en pin 10 (PWM)
Led ledAzul(11);   // LED azul en pin 11 (PWM)

// Crear instancia de LedRGB
LedRGB ledRGB(3, 5, 6);  // Pines R=3, G=5, B=6


void setup() {
  Serial.begin(9600);

  // Inicializar los LEDs
  ledRojo.iniciar();
  ledVerde.iniciar();
  ledAzul.iniciar();

  // Inicializar LedRGB
  ledRGB.iniciar();

  Serial.println("Sistema de LEDs inicializado");
}

void loop() {
  // Secuencia de LEDs con diferentes brillos
  ledRojo.setBrillo(255);
  ledRojo.encender();
  delay(1000);

  // Mostrar el estado del LED rojo
  Serial.print("Estado LED rojo: ");
  Serial.println(ledRojo.getEstado() ? "ENCENDIDO" : "APAGADO");

  ledVerde.setBrillo(150);
  ledVerde.encender();
  delay(1000);

  ledAzul.setBrillo(80);
  ledAzul.encender();
  delay(1000);

  // Apagar todos los LEDs
  ledRojo.apagar();
  ledVerde.apagar();
  ledAzul.apagar();
  delay(500);

  // Mostrar el estado del LED rojo
  Serial.print("Estado LED rojo: ");
  Serial.println(ledRojo.getEstado() ? "ENCENDIDO" : "APAGADO");

  // Hacer parpadear el LED verde 3 veces
  ledVerde.parpadear(3, 300);
  delay(1000);

  //Encender color rojo led RGB
  Serial.println("Led Rgb");
  ledRGB.setColor(255, 0, 0);
  delay(1000);
  ledRGB.apagar();  //aPAGAR LED RGB
  delay(1000);
}

En este ejemplo, LedRGB reutiliza la lógica de Led para cada uno de sus canales (rojo, verde y azul). Gracias a la herencia y a la composición de objetos, podemos controlar un LED RGB sin duplicar código, aprovechando las funcionalidades ya desarrolladas en la clase Led.

Ventajas de Usar POO en Arduino

  • Código más organizado: Agrupa datos y comportamientos relacionados
  • Reutilización: Puedes usar la misma clase en múltiples proyectos
  • Mantenibilidad: Es más fácil hacer cambios sin romper otras partes del código
  • Abstracción: Oculta la complejidad del hardware detrás de interfaces simples
  • Escalabilidad: Facilita la adición de nuevas funcionalidades
⚠️ Consideraciones de rendimiento: Aunque la POO ofrece muchos beneficios, en Arduino con recursos limitados, debes ser consciente del uso de memoria. Evita crear demasiados objetos o usar herencia muy profunda que pueda consumir memoria.

Conclusión

La Programación Orientada a Objetos en Arduino puede transformar la manera en que desarrollas tus proyectos, haciendo tu código más organizado, reutilizable y mantenible. Aunque requiere un cambio de mentalidad respecto a la programación procedural tradicional, los beneficios a largo plazo son significativos.

Comienza con clases simples como la clase Led presentada aquí y gradualmente avanza hacia estructuras más complejas. Pronto descubrirás que la POO te permite crear proyectos de Arduino más sofisticados con menos esfuerzo y código más limpio.

0/Post a Comment/Comments