Sensor capacitivo
Los sensores capacitivos se utilizan comúnmente para la detección de objetos. Pueden utilizarse, por ejemplo, para detectar el paso de un objeto en una cinta transportadora o para detectar el nivel de un líquido en un tanque. Los sensores capacitivos se usan en pantallas táctiles o como interruptores. En esta entrada veremos cómo crear un sensor capacitivo utilizando un simple conductor y un microcontrolador.
Principio de funcionamiento
Un sensor capacitivo funciona como una antena que genera un campo eléctrico. Cuando un material se acerca a la antena, cambiará la capacidad de este campo. El microcontrolador detecta esta diferencia y puede determinar la proximidad del objeto. Con esta tecnología, es posible transformar cualquier objeto conductor en un sensor.
Motor paso a paso 28BYJ-48 y AccelStepper
Objetivos
- Montar un pequeño motor paso a paso 28BYJ-48 con su adaptador.
- Escribir un primer programa de control utlizando la librería AccelStepper.
Material requerido
|
|
|
|
|
|
|
Motor paso a paso
Vamos a usar un pequeño motor paso a paso unipolar, muy común en el mundo Arduino por su pequeño tamaño y bajo coste, el 28BYJ-48 y el adaptador que suele venir con él, basado en el chip ULN2003A.
El 28BYJ-48 tiene 64 pasos por vuelta y un reductor interno con una relación de 1/64. En conjunto hacen 4096 pasos por vuelta
Ya vimos como utilizar estos motores de forma manual en otra entrada, en ese caso se mandaban las señales una a una a cada bobina.
Ahora veremos como utilizar este motor paso a paso utilizando la librería AccelStepper.
Instalación de la biblioteca AccelStepper
Para controlar el motor paso a paso con lArduino, utilizaremos la librería AccelStepper. Esta librería permite mover fácilmente el motor un número definido de pasos, establecer su velocidad, aceleración y mucho más.
Puede consultar la documentación de la biblioteca AccelStepper aquí.
Pasos para instalar la librería AccelStepper en el IDE de Arduino:
Haz clic en el menú “Programa” -> Incluir librería -> Administrar bibliotecas… Busca “AccelStepper”. Instala la biblioteca AccelStepper de Mike McCauley. En este ejercicio se utilizó la versión 1.64.0.
Primer ejemplo de código
#include <AccelStepper.h>
#include <MultiStepper.h>
const int vuelta = 2048; // Cambia esto para ajustar el número de pasos por revolución.
// ULN2003 Motor Driver Pins
#define IN1 5 // puedes usar D1
#define IN2 4 // puedes usar D2
#define IN3 14 // puedes usar D5
#define IN4 12 // puedes usar D6
// initialize the stepper library
AccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4);
void setup() {
// initialize the serial port
Serial.begin(115200);
// set the speed and acceleration
stepper.setMaxSpeed(500);
stepper.setAcceleration(100);
// set target position
stepper.moveTo(vuelta);
}
void loop() {
// check current stepper motor position to invert direction
if(stepper.distanceToGo() == 0){
stepper.moveTo(-stepper.currentPosition());
Serial.println(«Changing direction»);
}
// move the stepper motor (one step at a time)
stepper.run();
}
Explicación del código
En el código, primero se debe incluir la biblioteca AccelStepper.h.
#include <AccelStepper.h>
Se debe definir el número de pasos por revolución del motor paso a paso, en este caso es de 2048:
const int stepsPerRevolution = 2048; // cambiar esto para ajustar el número de pasos por revolución
Luego se deben definir los pines de entrada del motor. En este ejemplo, se conectan a los pines 5, 4, 14 y 12, pero se pueden usar cualquier pin.
Se debe inicializar una instancia de la biblioteca AccelStepper llamada stepper. Pasa como argumentos: AccelStepper::HALF4WIRE para indicar que se está controlando el motor paso a paso con cuatro cables y los pines de entrada. En el caso del motor paso a paso 28BYJ-48, el orden de los pines es IN1, IN3, IN2, IN4, puede ser diferente para otros motores.
AccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4);
En el setup(), inicializa el Monitor Serial a una velocidad de baudios de 115200.
Usa el método setMaxSpeed() para establecer la velocidad máxima del motor paso a paso. Pasa como argumento la velocidad en pasos por segundo. La función run() acelerará hasta la velocidad establecida por esta función.
Se establece la aceleración usando el método setAcceleration(). Pasa como argumento la aceleración en pasos por segundo.
Luego, se usa el método moveTo() para establecer una posición objetivo. Luego, la función run() intentará mover el motor (como máximo un paso por llamada) desde la posición actual a la posición objetivo establecida por la llamada más reciente a esta función. Estamos estableciendo la posición objetivo en 2048 (que es una vuelta completa en el caso de este motor).
stepper.moveTo(vuelta);
En el loop(), haremos girar el motor paso a paso en sentido horario y antihorario.
Primero, verificamos si el motor ya ha alcanzado su posición objetivo. Para hacer eso, podemos usar la función distanceToGo() que devuelve los pasos desde la posición actual hasta la posición objetivo.
Cuando el motor alcanza su posición objetivo, significa que la función distanceToGo() devolverá 0 y la siguiente declaración if será verdadera.
if (stepper.distanceToGo() == 0){
Cuando el motor alcanza su posición objetivo, establecemos una nueva posición objetivo, que es la misma que la posición actual pero en dirección opuesta.
stepper.moveTo(-stepper.currentPosition());
Finalmente, llama a stepper.run() para mover el motor un paso a la vez en el loop().
stepper.run();
La función run() sondea el motor y lo mueve si es necesario, implementando aceleraciones y desaceleraciones para alcanzar la posición deseada. Debes llamar a esta función tan frecuentemente como sea posible, pero al menos una vez por el intervalo de tiempo mínimo de paso, preferiblemente en el loop().
Segundo ejemplo de código
#include <AccelStepper.h>
const int stepsPerRevolution = 2048;
// ULN2003 Motor Driver Pins
#define IN1 5 // puedes usar D1
#define IN2 4 // puedes usar D2
#define IN3 14 // puedes usar D5
#define IN4 12 // puedes usar D6
// Define el motor paso a paso y los pines que se utilizarán
AccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4);
void setup() {
// Establece la velocidad máxima y la aceleración del motor
stepper.setMaxSpeed(1000);
stepper.setAcceleration(100);
}
void loop() {
// Mueve el motor 2048 pasos en una dirección
stepper.move(stepsPerRevolution );
stepper.runToPosition();
// Espera 1 segundo
delay(1000);
// Mueve el motor 2048 pasos en la dirección opuesta
stepper.move(-stepsPerRevolution );
stepper.runToPosition();
// Espera 1 segundo
delay(1000);
}
runToPosition()
Mueve el motor (con aceleración/desaceleración) a la posición objetivo y lo bloquea hasta que esté en la posición. No utilizar este método en bucles, ya que bloquea.
runToNewPosition()
runToNewPosition( long position)
Mueve el motor (con aceleración/desaceleración) a la nueva posición objetivo y lo bloquea hasta que esté en posición. No utilizar este método en bucles, ya que bloquea.
Sensor Óptico infrarrojo TCRT5000
El Sensor Óptico TCRT5000 es un sensor ideal para detectar un cambio en la superficie sobre la cual está trabajando, El módulo incluye un sensor TCRT5000 óptico reflectivo infrarrojo, incluye el circuito Integrado LM393 como comparador de voltaje, es ideal para la detección de productos en bandas transportadoras y líneas de producción, líneas en robots de carreras seguidores de línea y sumos, aunque podemos encontrarle utilidad en cualquier otro proyecto electrónico que deseemos realizar.
El TCRT5000 es un sensor que incluye el emisor y el receptor en el mismo empaquetado. El módulo funciona con IR lo que lo hace inmune a la luz visible.
Módulo de pantalla de matriz de puntos LED I2C
El HT16K33 es un pequeño chip que tiene la capacidad de controlar una matriz multiplexada de 16×8 (es decir, 128 LED individuales). El protocolo de comunicación es I2C, por lo que utiliza solo 2 pines y puede tener hasta 8 direcciones I2C seleccionables, lo que da un total de 8 matrices, cada una de las cuales controla 16×8 LED para un total de 1024 LED.
A diferencia otros shield de LED, este módulo no tiene salidas para conectar otro módulo de LEDs.
Todo el control de LED se realiza a través de I2C utilizando la librería de interfaz HT16K33. Esto significa que SDA y SCL deben estar conectados con los pines A4 y A5.
La dirección predeterminada es 0x70 pero puede cambiar la dirección a 0x71-0x77 mediante un puente y soldando en los pines de dirección.
Software
Deberás instalar las siguientes librerías para utilizar este módulo.
Abra el administrador de librerías del IDE de Arduino:
Robot Mecanum (Karla y Alberto)
Vamos a construir un robot con las siguientes caracteristicas:
-Impreso en 3D
-Tendra ruedas mecanum
-Sensor de distancia
-Display 16×8 leds
-2 sensores de proximidad
-Bluetooth
-2 baterias de 9v
-4 motores servo 360º
El robot tiene que realizar tres pruebas:
-Prueba de recorrer el laberinto.
La prueba constará de un laberinto diseñado con trozos de cartón que servirán como paredes. Para montarlo usaremos unas piezas que servirán como puente de unión diseñadas en 3D.
El objetivo principal del robot será salir del laberinto, controlado por el usuario, desde el inicio del laberinto. Para hacerlo, usará los sensores que detectarán los huecos de pared libre y así, dirigirse hacia ellos, hasta llegar a la salida.
MATERIAL:
– Shield para arduino nano
– Arduino nano
-4 servo motores sg90 de 360º
-Sensor de distancia HC-SR04
-Display
-Bluetooth HC-06
-4 ruedas mecanum
-Cables dupont
-2 conectores de baterias de 9V
-Interruptor
-2 baterias de 9V
Material 3D:
Robot Mecanum (Ianna+ClaudiaM)
Vamos a construir un robot con las siguientes caracteristicas:
-Impreso en 3D
-Tendra ruedas mecanum
-Sensor de distancia
-Display 16×8 leds
-2 sensores de proximidad
-Bluetooth
-2 baterias de 9v
-4 motores servo 360º
LOS ROBOTS DEBERÁN REALIZAR LA SIGUIENTE PRUEBA:
El robot será guiado a través del móvil por Bluetooth para que salga de un laberinto en el menor tiempo posible. Ganará el que, cronometrándolo, sea el más rápido y ocupe el menor tiempo.
El laberinto estará diseñado con trozos de cartón que servirán de paredes, para poder montarlo contendrá unas piezas que servirán como puente de unión diseñadas en 3D.
El objetivo principal del robot será salir de forma autónoma desde el inicio del laberinto. Para hacerlo, usará los sensores que detectarán los huecos de pared libre y así, dirigirse hacia ellos, hasta llegar a la salida.
PARTES DEL ROBOT:
- Shield nano:
- Arduino nano: parte programada:
- Servo motor de 360º(x4):
- Sensor de distancia HC-SR04:
- Módulo de sensor sigue-líneas:
- Sensor de proximidad (x4):
- Display 16×8 LEDS:
- Módulo Bluetooth HC-06:
- Ruedas Mecanum (x4):
- Cables dupont:
- Conectores de batería de 9V (x2):
- Batería de 9V (x2):
- Interruptor:
Robot Mecanum Claudia y Santi
Este robot consta de unas ruedas mecanum como base de diseño. Además llevará un sensor de distancia y otros dos sensores de proximidad para poder llevar a cabo todas las pruebas propuestas, junto con dos baterías de 9 v, 4 motores de servo 360 y Display 16*8. Estará impreso en 3D y se podrá usar mediante Bluetooth.
La prueba que realizara constará de un laberinto diseñado con trozos de cartón que servirán de paredes, para poder montarlo contendrá unas piezas que servirán como puente de unión diseñadas en 3D.
El objetivo principal del robot será salir de forma autónoma desde el inicio del laberinto. Para hacerlo, usará los sensores que detectarán los huecos de pared libre y así, dirigirse hacia ellos, hasta llegar a la salida. Se tendrá que hacer en el tiempo mínimo posible.
Los materiales que usaremos serán los siguientes:
Un shield nano, donde pondremos el arduino nano para introducir hacer funcionar el código que será introducido en el arduino nano. De esta forma será más fácil de conectar.
Un arduino nano donde pondremos el código que programaremos.
4 servo motores SG90 de 360º
Sensor de distancia HC-SR04
Módulo de sensor (sigue líneas)
2 sensores de proximidad
Un display de 16×8 leds.
Un módulo BlueTooth HC-06.
4 ruedas mecanum 48 mm.
cables DuPont.
2 conectores para batería de 9 V.
Dos baterías de 9 v.
Un interruptor.
ESP8266-12E Interrupciones y temporizadores
Las interrupciones nos permiten detectar cambios en el estado de GPIO sin la necesidad de verificar constantemente su valor actual. Con las interrupciones, cuando se detecta un cambio, se activa un evento (se llama a una función).
Como ejemplo, detectaremos movimiento usando un sensor de movimiento PIR: cuando se detecta movimiento, el ESP8266 inicia un temporizador y enciende un LED durante una cantidad predefinida de segundos. Cuando el temporizador termina la cuenta regresiva, el LED se apaga automáticamente.
Para crear una interrupción, hay que llamar a attachInterrupt() y pasarle como argumentos el pin de interrupción GPIO, la ISR (función a llamar) y el modo. La función ISR debe tener declarado el atributo ICACHE_RAM_ATTR. El modo puede ser CAMBIO, ASCENSO o DESCENSO.
attachInterrupt(digitalPinToInterrupt(GPIO), ISR, mode);
Las interrupciones ESP8266
Las interrupciones son útiles para hacer que las cosas sucedan automáticamente en los programas de microcontroladores y pueden ayudar a resolver problemas de temporización.
Con las interrupciones, no se necesita verificar constantemente el valor del pin actual. Cuando se detecta un cambio, se activa un evento: se llama a una función. Esta función se llama rutina de servicio de interrupción (ISR).
Cuando ocurre una interrupción, el procesador detiene la ejecución del programa principal para ejecutar una tarea y luego regresa al programa principal.
Esto es especialmente útil para activar una acción cuando se detecta movimiento o cuando se presiona un botón sin la necesidad de verificar constantemente su estado.
Función attachInterrupt()
Para configurar una interrupción en el IDE de Arduino, se utiliza la función attachInterrupt(), que acepta como argumentos: el pin de interrupción GPIO, el nombre de la función a ejecutar y el modo:
attachInterrupt(digitalPinToInterrupt(GPIO), ISR, mode);
El primer argumento es una interrupción GPIO. Se debe usar digitalPinToInterrupt(GPIO) para configurar el GPIO real como un pin de interrupción. Por ejemplo, si se desea utilizar GPIO 14 como interrupción, escribir en el setup():
digitalPinToInterrupt(14);
El ESP8266 admite interrupciones en cualquier GPIO, excepto GPIO16.
El segundo argumento de la función attachInterrupt() es el nombre de la función que se llamará cada vez que se active la interrupción: la rutina de servicio de interrupción (ISR).
La función ISR debe ser lo más simple posible, para que el procesador vuelva rápidamente a la ejecución del programa principal.
El mejor enfoque es señalar al código principal que la interrupción ha ocurrido mediante el uso de una variable global y dentro del bucle () verificar y borrar esa bandera y ejecutar el código.
Los ISR deben tener ICACHE_RAM_ATTR antes de la definición de la función para ejecutar el código de interrupción en la RAM.
Modos de interrupción
El tercer argumento es el modo y hay 3 modos diferentes:
- CHANGE: para activar la interrupción siempre que el pin cambie de valor, por ejemplo, de ALTO a BAJO o de BAJO a ALTO;
- FALLING: para cuando el pin pasa de HIGH a LOW;
- RISING: para disparar cuando el pin va de BAJO a ALTO.
Para nuestro ejemplo, usaremos el modo RISING, porque cuando el sensor de movimiento PIR detecta movimiento, el GPIO al que está conectado pasa de BAJO a ALTO.
Los temporizadores ESP8266 NodeMCU.
Queremos que el LED permanezca encendido durante un número predeterminado de segundos después de que se detecte movimiento. En lugar de usar una función de retraso dela() que bloquea su código y no le permite hacer nada más durante un número determinado de segundos, usaremos un temporizador.
delay() vs millis()
La función delay() acepta un solo número int como argumento. Este número representa el tiempo en milisegundos que el programa debe esperar hasta pasar a la siguiente línea de código.
delay (tiempo en milisegundos);
Cuando se llama a delay(1000), el programa se detiene en esa línea durante 1 segundo. delay() es una función de bloqueo. Las funciones de bloqueo evitan que un programa haga cualquier otra cosa hasta que se complete esa tarea en particular. Si necesita que se realicen varias tareas al mismo tiempo, no puede usar delay(). Para la mayoría de los proyectos, debe evitar el uso de retrasos y utilizar temporizadores en su lugar.
Usando una función llamada millis(), podemos devolver la cantidad de milisegundos que han pasado desde que se inició el programa por primera vez.
milis();
¿Por qué es útil esa función? Porque al usar algunas matemáticas, puede verificar fácilmente cuánto tiempo ha pasado sin bloquear su código.
Parpadeando un LED usando millis() (sin demora)
El siguiente fragmento de código muestra cómo se puede usar la función millis() para crear un proyecto de parpadeo. Enciende un LED durante 1000 milisegundos y luego lo apaga.
// constants won't change. Used here to set a pin number :
const int ledPin = 26; // the number of the LED pin
// Variables will change :
int ledState = LOW; // ledState used to set the LED
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0; // will store last time LED was updated
// constants won't change :
const long interval = 1000; // interval at which to blink (milliseconds)
void setup() {
// set the digital pin as output:
pinMode(ledPin, OUTPUT);
}
void loop() {
// here is where you'd put code that needs to be running all the time.
// check to see if it's time to blink the LED; that is, if the
// difference between the current time and last time you blinked
// the LED is bigger than the interval at which you want to
// blink the LED.
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
Esquema
Montar el sensor de movimiento PIR y un LED en el ESP8266. Conectaremos el LED a GPIO 12 (D6) y el pin de datos del sensor de movimiento PIR a GPIO 14 (D5).
Importante: el sensor de movimiento PIR Mini AM312 utilizado en este proyecto funciona a 3,3 V. Sin embargo, si está utilizando otro sensor de movimiento PIR como el HC-SR501, funciona a 5V. Puede modificarlo para que funcione a 3,3 V o simplemente alimentarlo con el pin Vin.
Código:
Se puede cargar el código tal como está, o se puede modificar la cantidad de segundos que se enciende el LED después de detectar movimiento. Simplemente cambie la variable timeSeconds con la cantidad de segundos que desee.
#define timeSeconds 10
// Set GPIOs for LED and PIR Motion Sensor
const int led = 12;
const int motionSensor = 14;
// Timer: Auxiliary variables
unsigned long now = millis();
unsigned long lastTrigger = 0;
boolean startTimer = false;
// Checks if motion was detected, sets LED HIGH and starts a timer
ICACHE_RAM_ATTR void detectsMovement() {
Serial.println("MOTION DETECTED!!!");
digitalWrite(led, HIGH);
startTimer = true;
lastTrigger = millis();
}
void setup() {
// Serial port for debugging purposes
Serial.begin(115200);
// PIR Motion Sensor mode INPUT_PULLUP
pinMode(motionSensor, INPUT_PULLUP);
// Set motionSensor pin as interrupt, assign interrupt function and set RISING mode
attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);
// Set LED to LOW
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
}
void loop() {
// Current time
now = millis();
// Turn off the LED after the number of seconds defined in the timeSeconds variable
if(startTimer && (now - lastTrigger > (timeSeconds*1000))) {
Serial.println("Motion stopped...");
digitalWrite(led, LOW);
startTimer = false;
}
}
ESP8266-12E (NodeMCU) ADC – Leer valores analógicos.
Entradas analógicas (ADC)
Tanto ESP8266-12E como ESP8266-07 tienen un pin ADC al que se puede acceder fácilmente. Esto significa que esas placas ESP8266 pueden leer señales analógicas.
ESP8266 ADC Especificaciones
Cuando se refiera al pin ADC ESP8266, a menudo escuchará estos diferentes términos indistintamente:
- ADC (Convertidor de analógico a digital)
- TOUT
- Pin6
- A0
- Pin analógico 0
Todos estos términos se refieren al mismo pin en el ESP8266.
Resolución ADC ESP8266
El pin ADC tiene una resolución de 10 bits, lo que significa que obtendrá valores entre 0 y 1023.
Rango de voltaje de entrada ESP8266
El rango de voltaje de entrada del pin ADC ESP8266 es de 0 a 1 V si está utilizando el chip de forma independiente. Sin embargo, la mayoría de las placas de desarrollo ESP8266 vienen con un divisor de voltaje interno, por lo que el rango de entrada es de 0 a 3,3 V. Entonces, en resumen:
Leer un valor analógico con el ESP32 significa medir niveles de voltaje variables entre 0 V y 3,3 V.
A la tensión medida se le asigna entonces un valor entre 0 y 4095, en el que 0 V corresponde a 0 y 3,3 V corresponde a 4095. Cualquier tensión entre 0 V y 3,3 V recibirá el valor correspondiente en el medio.
ADC es no lineal
Idealmente, esperaría un comportamiento lineal al usar los pines ESP32 ADC. Sin embargo, eso no sucede. Lo que obtendrá es un comportamiento como se muestra en el siguiente gráfico:
Este comportamiento significa que su ESP32 no puede distinguir 3,3 V de 3,2 V. Obtendrá el mismo valor para ambos voltajes: 4095.
Lo mismo sucede para valores de voltaje muy bajos: para 0 V y 0.1 V obtendrá el mismo valor: 0. Debe tener esto en cuenta cuando use los pines ESP32 ADC.
Como ejemplo, mostraremos cómo leer valores analógicos de un potenciómetro.
Pin analógico ESP8266
Con el kit ESP8266 12-E NodeMCU y otras placas de desarrollo ESP8266, es muy fácil acceder al A0, simplemente conecte un cable de puente al pin.
Función analogRead()
Leer una entrada analógica usando el IDE de Arduino es tan simple como usar la función analogRead(). Acepta como argumento, el GPIO que se quiere leer:
analogRead (GPIO);
Esquema
Si está utilizando una placa de desarrollo ESP8266, siga el siguiente diagrama esquemático.
Código
const int analogInPin = A0; // ESP8266 Analog Pin ADC0 = A0
int sensorValue = 0; // value read from the pot
void setup() {
// initialize serial communication at 115200
Serial.begin(115200);
}
void loop() {
// read the analog in value
sensorValue = analogRead(analogInPin);
// print the readings in the Serial Monitor
Serial.print("sensor = ");
Serial.print(sensorValue);
delay(1000);
}