Módulos Arduino CIES
Módulos Arduino CIES
Módulos_Arduino_CIES
Ir al índice
Índice general
8. Anexos 32
8.1. Preparación del software Arduino ········································································· 32
8.1.1. Windows ··································································································· 32
8.1.2. Linux ········································································································ 33
8.1.2.1. Error en puerto serie ············································································· 34
i
Contenido
ii
Contenido
Índice de figuras
Figura 1: Conexión del sensor MPU a la placa controladora ······························································ 4
Figura 2: Vector de aceleración de gravedad y cálculo de la inclinación del sensor, los ejes x, y y z son fijos
respecto al propio sensor. ········································································································· 11
Figura 3: Un mismo modo de rotación de un objeto entorno a su eje z, con dos inclinaciones diferentes del
mismo respecto a tierra. ··········································································································· 12
Figura 4: Salida del monitor al rotar el sensor MPU6050 en su eje X unos 90 grados ···························· 15
Figura 5: Salida del monitor al rotar el sensor MPU6050 en su eje Y unos 90 grados ···························· 16
Figura 6: Modo 1 de funcionamiento del sensor AJ-SR04M, activación por disparo y medida dada como
función de la duración del pulso en señal “echo” ············································································ 20
Figura 7: Modo 4 de funcionamiento del sensor AJ-SR04M, activación por señal en trigger y medida dada
como valor serial ····················································································································· 21
Figura 8: Temporizador digital HCW-M421 ···················································································· 24
Figura 9: Módulo de 8 relés electromecánicos del Instituto FIIIDT ······················································ 25
Figura 10: Modulo de 4 relés de estado sólido, se disparan con nivel bajo en la entrada ························ 25
Figura 11: Diagrama del bobinado simplificado del motor de paso unipolar de 6 cables, las flechas
representan 3 pasos de giro de la tabla 7.1 ·················································································· 29
Figura 12: Fecha y versión del controlador del chip CH340G y similares (Windows) ······························ 32
Figura 13: Opciones del menú herramientas en Arduino IDE 2.3.2 (Windows) ······································ 33
Figura 14: Mapa de pines de Arduino Uno ···················································································· 35
Índice de tablas
Tabla 2.1: Módulos sensores disponibles para Arduino o similares – Octubre 2024 ································· 1
Tabla 3.1: Rangos por defecto del MPU6050 por cada eje ································································· 2
Tabla 3.2: Rangos máximos del MPU6050 por cada eje ···································································· 2
Tabla 7.1: Tabla de pasos en modo half-step de motor de paso unipolar ············································· 29
iii
Contenido
iv
2. Módulos disponibles
1. Introducción
En el presente documento se pretende exponer información referente a módulos compatibles
con Arduino disponibles en CIES – FIIIDT para investigación y desarrollo de proyectos, tanto
internos como externos. Esto puede funcionar como un método de recopilación de datos sobre los
dispositivos disponibles en el instituto.
2. Módulos disponibles
En el laboratorio 235 se tiene un set de componentes y módulos para Arduino de uso general,
los cuales se listan en la tabla siguiente:
Tabla 2.1: Módulos sensores disponibles para Arduino o similares – Octubre 2024
Brújula digital o
magnetómetro soldado en
1 placa HMC5883L 2 Interfaz I2C
Sensor de humedad y
temperatura RH/T soldado en
2 placa HTU21/SHT21 Interfaz I2C
Detección de 20 cm a
Sensor de distancia por 800 cm. Alimentación
5 ultrasonido AJ-SR04M AJ-SR04M 1 3 a 5,5V
Compatible con
diversos perfiles y
protocolos de la pila
Módulo receptor de audio HW de protocolos de
6 770 HW-770 V0.2 2 Bluetooth
Ir al índice 1
Tema 3: Sensor de medición inercial MPU6050
Para el sensor MPU6050, se empezará probando la librería MPU6050 v1.4.1 (de Electronic
Cats), descargable desde el Arduino IDE. Esta librería está basada en la librería jrowberg/i2cdevlib
(visite i2cdevlib/Arduino/MPU6050 at master · jrowberg/i2cdevlib · GitHub para detalles).
Continúa...
Tabla 3.1: Rangos por defecto del MPU6050 por cada eje
El rango de aceleración por defecto está comprendido entre -2g y 2g, siendo g la gravedad de
la tierra cerca del nivel del mar. El MPU permite trabajar hasta con 16g m/s2 para el acelerómetro y
2000 grados /s para el giroscopio por cada eje.
2 Ir al índice
3. Sensor de medición inercial MPU6050
// del estado de pin AD0. Si no se especifica, 0x68 estará implícito (voltaje bajo por
pull down interno)
MPU6050 sensor; //objeto de clase
//las mediciones obtenidas del sensor directamente son: aceleración lineal (por eje) y
velocidad angular (por eje)
// Valores RAW (sin procesar) del acelerometro y giroscopio en los ejes x,y,z
int ax, ay, az; //
int gx, gy, gz;
void setup() {
Serial.begin(9600); //Iniciando puerto serial, altas velocidades pueden impedir una
transmisión correcta
Wire.begin(); //Iniciando I2C
sensor.initialize(); //Iniciando el sensor
void loop() {
// Leer las aceleraciones y velocidades angulares cada 100 ms
sensor.getAcceleration(&ax, &ay, &az);
sensor.getRotation(&gx, &gy, &gz);
Serial.print("g[x y z] \n");
Serial.print(gx); Serial.print(" ");
Serial.print(gy); Serial.print(" ");
Serial.println(gz);
delay(100);
}
El código anterior fue grabado en la placa tipo Arduino con el sensor conectado y ha
funcionado sin errores, sin embargo los valores de medida mostrados hacen referencia a un offset
que no ha sido ajustado. Para resolver esto se requiere calibrar el sensor MPU.
Para obtener la lectura real de aceleración (o velocidad angular) se debe transformar el valor
devuelto por getAcceleration o getRotation (por defecto un entero entre -32768 y 32767), en base
al código previo:
El valor 2*9.8 (2g) corresponde al escalado por defecto (tabla 3.1), este valor puede ser
cambiado sobreescribiendo uno de los registros de configuración del MPU vía I2C (pueden usarse
las funciones de la clase Wire, que son funciones de bajo nivel). Los valores posibles son 2g, 4g,
Ir al índice 3
Tema 3: Sensor de medición inercial MPU6050
8g, y 16g. Ver hoja de datos para más detalles de este y otros registros de configuración.
3.1. Calibración
Para realizar una calibración se usan algoritmos como se muestra en esta sección. La
calibración se realiza en parte debido a que cada módulo es único en lo que se refiere al error del
cero que viene de fábrica. El error de desplazamiento del cero (offset) se refiere a que el sensor
mide pequeñas magnitudes distintas de cero incluso si está completamente nivelado, cuando en
teoría debería medir valores cero (velocidad angular, ángulos y aceleración angular por ejes).
Existen funciones de la clase MPU6050 tanto para establecer como para obtener el offset de
aceleración por cada eje y velocidad angular del sensor. El código usa estas funciones para ajustar
el offset, como se verá a continuación. Las funciones de offset de aceleración son:
Sustituyendo X por Y o Z en las funciones previas se trabaja con los ejes restantes.
4 Ir al índice
3.1. Calibración
// Codigo de calibracion del MPU6050, este codigo solo calibra el sensor
// I2Cdev and MPU6050 deben estar instaladas como librerías
// La libreria MPU6050.h necesita I2Cdev.h, I2Cdev.h necesita Wire.h
#include "I2Cdev.h"
#include "MPU6050.h"
#include "Wire.h"
//las mediciones obtenidas del sensor directamente son: aceleración lineal (por eje) y
velocidad angular (por eje)
MPU6050 sensor(0x68); // crea el objeto sensor, si conecta 2 sensores MPU, estos deberán
tener direcciones I2C diferentes
// Valores RAW (sin procesar) del acelerometro y giroscopio en los ejes x,y,z
int ax, ay, az;
int gx, gy, gz;
void setup() {
Serial.begin(9600); //Iniciando puerto serial
Wire.begin(); //Iniciando I2C
sensor.initialize(); //Iniciando el sensor
Serial.println("Offsets:");
Serial.print(ax_o); Serial.print("\t");
Serial.print(ay_o); Serial.print("\t");
Serial.print(az_o); Serial.print("\t");
Serial.print(gx_o); Serial.print("\t");
Serial.print(gy_o); Serial.print("\t");
Serial.print(gz_o); Serial.print("\t");
Serial.println("nnEnvie cualquier caracter para empezar la calibracion");
// Espera un caracter para empezar a calibrar
while (true){if (Serial.available()) break;}
Serial.println("Calibrando, no mover IMU");
void loop() {
// Leer las aceleraciones y velocidades angulares sin escalar
sensor.getAcceleration(&ax, &ay, &az);
sensor.getRotation(&gx, &gy, &gz);
Ir al índice 5
Tema 3: Sensor de medición inercial MPU6050
f_ay = f_ay-(f_ay>>5)+ay;
p_ay = f_ay>>5;
f_az = f_az-(f_az>>5)+az;
p_az = f_az>>5;
f_gx = f_gx-(f_gx>>3)+gx;
p_gx = f_gx>>3;
f_gy = f_gy-(f_gy>>3)+gy;
p_gy = f_gy>>3;
f_gz = f_gz-(f_gz>>3)+gz;
p_gz = f_gz>>3;
sensor.setXAccelOffset(ax_o);
sensor.setYAccelOffset(ay_o);
sensor.setZAccelOffset(az_o);
sensor.setXGyroOffset(gx_o);
sensor.setYGyroOffset(gy_o);
sensor.setZGyroOffset(gz_o);
counter=0;
} // fin de if
counter++;
} // fin de la funcion loop
6 Ir al índice
3.1. Calibración
puerto serial, pero no los lee en sí. Esto se refiere a los datos que ya han llegado al bufer
previamente. Si el valor devuelto es cero, no hay datos para leer en ese instante. Después de esta
función se suele ejecutar dato=Serial.read(), que retorna el primer byte disponible de la pila del
bufer como un entero, o un -1 si no hay datos para leer. A medida que se leen bytes, el bufer se va
liberando, por ende el valor devuelto por Serial.available() será cada vez menor hasta ser igual a
cero.
Es posible cambiar el tamaño del buffer de lectura, es decir la cantidad de datos que el
Arduino leerá en una sola secuencia, pero si el tamaño se hace muy grande, el código tardará más
en ejecutar cada ciclo loop.
Si los valores medidos no cambian de signo, los valores filtrados p se alejan del cero a medida
que se suman las mediciones de cada magnitud. Los valores de aceleración a x y ay y velocidades
angulares deben ser cercanos a cero, dejando el sensor inmóvil y nivelado. Por cada 100
iteraciones, todos los offset se corrigen sumando o restando una unidad, y esto afecta las
mediciones en el próximo ciclo.
Promedio valores offset ( ax_o ay_o az_o gx_o gy_o gz_o ): -944 -1507 1954 12 32 120
Promedio valores offset ( ax_o ay_o az_o gx_o gy_o gz_o ): -945 -1508 1955 13 33 119
Promedio valores offset ( ax_o ay_o az_o gx_o gy_o gz_o ): -946 -1509 1956 12 32 120
Promedio valores offset ( ax_o ay_o az_o gx_o gy_o gz_o ): -947 -1510 1957 13 33 119
Promedio valores offset ( ax_o ay_o az_o gx_o gy_o gz_o ): -948 -1511 1958 12 34 120
Ir al índice 7
Tema 3: Sensor de medición inercial MPU6050
int mean_ax,mean_ay,mean_az,mean_gx,mean_gy,mean_gz,state=0;
int ax_offset,ay_offset,az_offset,gx_offset,gy_offset,gz_offset;
// Inicializa el MPU
accelgyro.initialize();
// espera de lectura
while (Serial.available() && Serial.read()); // este while libera el bufer
while (!Serial.available()){ // generalmente sera true, hasta pulsar una tecla
Serial.println(F("Presione una tecla para iniciar rutina de calibracion \n"));
delay(1500);
}
while (Serial.available() && Serial.read()); // este while tambien libera el bufer de
los datos provenientes del teclado
// Inicia mensaje
Serial.println("\nMPU6050 Calibration Sketch");
delay(2000);
Serial.println("\nEl sensor debe estar en posición horizontal, no tocarlo hasta que se
termine la rutina.\n");
delay(3000);
// verify connection
Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050
connection failed");
delay(1000);
// reinicia offsets:
accelgyro.setXAccelOffset(0);
accelgyro.setYAccelOffset(0);
accelgyro.setZAccelOffset(0);
accelgyro.setXGyroOffset(0);
accelgyro.setYGyroOffset(0);
accelgyro.setZGyroOffset(0);
} // fin de setup
2 Otro código de calibración se puede encontrar en los códigos de ejemplo de Arduino IDE, que se denomina IMU_ZERO.ino. Dicho ejemplo viene
incluido con la librería MPU6050, descrita en la sección 2.
8 Ir al índice
3.1. Calibración
/////////////////////////////////// Lazo ////////////////////////////////////
void loop() {
if (state==0){
Serial.println("\nLeer sensores por primera vez...");
meansensors(); // suma mediciones y promedia
state++;
delay(1000);
}
if (state==1) {
Serial.println("\nEstablece los nuevos offsets...");
calibration(); // solo terminara si los offset son inferiores que las zonas muertas
state++;
delay(1000);
}
while (i<(buffersize+101)){
// read raw accel/gyro measurements from device
accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); // lee sensores y almacena
// (se descartan las primeras 100 lecturas)
Ir al índice 9
Tema 3: Sensor de medición inercial MPU6050
buff_gz=buff_gz+gz;
}
if (i==(buffersize+100)){ // iteracion i = 1100, se promedian mediciones aquí
mean_ax=buff_ax/buffersize;
mean_ay=buff_ay/buffersize;
mean_az=buff_az/buffersize;
mean_gx=buff_gx/buffersize;
mean_gy=buff_gy/buffersize;
mean_gz=buff_gz/buffersize;
}
i++;
delay(2); // para dar tiempo entre mediciones
}
}
gx_offset=-mean_gx/4;
gy_offset=-mean_gy/4;
gz_offset=-mean_gz/4;
// (el acelerometro generalmente tiene mas ruido que el giroscopio)
while (1){
int ready=0;
accelgyro.setXAccelOffset(ax_offset);
accelgyro.setYAccelOffset(ay_offset);
accelgyro.setZAccelOffset(az_offset);
accelgyro.setXGyroOffset(gx_offset);
accelgyro.setYGyroOffset(gy_offset);
accelgyro.setZGyroOffset(gz_offset);
if (abs(mean_ax)<=acel_deadzone) ready++;
else ax_offset=ax_offset-mean_ax/acel_deadzone; // reajuste de offset
// se obtiene un promedio suficientemente pequeño, o en lugar de ello se corrige el
offset para volver a sumar y promediar
if (abs(mean_ay)<=acel_deadzone) ready++;
else ay_offset=ay_offset-mean_ay/acel_deadzone;
if (abs(16384-mean_az)<=acel_deadzone) ready++;
else az_offset=az_offset+(16384-mean_az)/acel_deadzone;
if (abs(mean_gx)<=giro_deadzone) ready++;
else gx_offset=gx_offset-mean_gx/(giro_deadzone+1);
if (abs(mean_gy)<=giro_deadzone) ready++;
else gy_offset=gy_offset-mean_gy/(giro_deadzone+1);
if (abs(mean_gz)<=giro_deadzone) ready++;
else gz_offset=gz_offset-mean_gz/(giro_deadzone+1);
if (ready==6) break;
}
}
10 Ir al índice
3.2. Valores de inclinación del sensor
termine solo si los valores promedio calculados (mean_ax, mean_ay, ...) son inferiores al valor
establecido de zona muerta.
Todos los valores de promedio y offset que se obtienen en las funciones son valores no
escalados. En realidad no hace falta convertirlos a las unidades físicas asociadas.
El ángulo x es el ángulo que forma el vector de gravedad g con el plano yz del sensor, el
ángulo Y es el ángulo que forma el vector g con el plano xz. Por triángulos rectángulos, se
expresan estos ángulos en función de arcotangentes. Los catetos son básicamente proyecciones
del vector g, como se ve en la figura 2. Se asume el vector g positivo apuntando hacia “arriba” por
simplicidad.
ap2=Accx2 + Accz2
ap tan(y)=tan(roll)=|Accy| / |ap|
tan(y)=|Accy| / sqrt(Accx2 + Accz2)
Figura 2: Vector de aceleración de gravedad y cálculo de la inclinación del sensor, los ejes x, y y z
son fijos respecto al propio sensor.
De forma similar al ángulo y, se determina x, que es el ángulo de proyección de g sobre el
plano yz del sensor, entonces:
Siendo sqrt la función para sacar la raiz cuadrada. En nuestro código se usa directamente la
3 Referencias: https://youtu.be/7VW_XVbtu9k?si=fuFyVvICLSS6YjMB
Ir al índice 11
Tema 3: Sensor de medición inercial MPU6050
// ...
sensor.getAcceleration(&ax, &ay, &az); // valores sin procesar (escalar)
//Calcular los angulos de inclinacion:
float accel_ang_x=atan(ax/sqrt(pow(ay,2) + pow(az,2)))*(180.0/3.14); // radianes
float accel_ang_y=atan(ay/sqrt(pow(ax,2) + pow(az,2)))*(180.0/3.14);
// ...
Para calcular los ángulos de inclinación no hace falta escalar los valores leídos con
getAcceleration(…), ya que la tangente es adimensional.
No se debe confundir los ángulos de rotación de ejes, con los ángulos de inclinación del
sensor, aunque pueden coincidir como casos particulares.
Hay que tener presente que un objeto puede rotar respecto a un eje del mismo, con
inclinaciones diferentes, esto se visualiza mejor en la figura 3. A esto se refiere la diferencia entre
inclinación del sensor y la rotación entorno a un eje.
Eje
perpendicular al
suelo z
Figura 3: Un mismo modo de rotación de un objeto entorno a su eje z, con dos inclinaciones
diferentes del mismo respecto a tierra.
12 Ir al índice
3.3. Valores de rotación con el giroscopio
Donde w es la velocidad medida por el giroscopio en rad/s. Se puede asumir un ángulo inicial
para = 0 antes de entrar en el bucle. Esta fórmula se aplica por cada eje del sensor (x, y, z).
Según el sentido de giro, w y serán positivo o negativo.
// Código para obtener los ángulos de rotación de los ejes del sensor
// Librerias I2C para controlar el mpu6050
// la libreria MPU6050.h necesita I2Cdev.h, I2Cdev.h necesita Wire.h
#include "I2Cdev.h"
#include "MPU6050.h"
#include "Wire.h"
void setup() {
Serial.begin(9600); //Iniciando puerto serial
Wire.begin(); //Iniciando I2C
sensor.initialize(); //Iniciando el sensor
void loop() {
// Leer las velocidades
sensor.getRotation(&gx, &gy, &gz); // sin procesar
Ir al índice 13
Tema 3: Sensor de medición inercial MPU6050
Con este código por lo general se produce un error acumulativo en la medición llamado “drift”,
el cual se debe eliminar o reducir agregando un filtro complementario en el código. Este error se
debe principalmente al ruido en la medición de la velocidad.
El ángulo de rotación del eje X se puede expresar en función del ángulo de proyección del
vector g sobre el plano xz. Cada ángulo de rotación se complementa como en el siguiente código.
// Valores RAW (sin procesar) del acelerometro y giroscopio en los ejes x,y,z
int ax, ay, az;
int gx, gy, gz;
double tiempo_prev;
float dt;
float ang_x, ang_y; // valores previos punto flotante
float ang_x_prev, ang_y_prev;
void setup() {
Serial.begin(9600); //Iniciando puerto serial
Wire.begin(); //Iniciando I2C
sensor.initialize(); //Iniciando el sensor
} // fin de setup
void loop() {
// Leer las aceleraciones y velocidades angulares
sensor.getAcceleration(&ax, &ay, &az);
sensor.getRotation(&gx, &gy, &gz);
14 Ir al índice
3.3. Valores de rotación con el giroscopio
//Mostrar los angulos separadas por un [tab]
delay(50);
}
Las mediciones con ruido del acelerómetro son filtradas por las mediciones del giroscopio en
el eje respectivo. La medición del acelerometro contribuye solo con un 10% del ángulo de giro por
eje. Estas constantes numéricas se pueden cambiar para fines de prueba.
Figura 4: Salida del monitor al rotar el sensor MPU6050 en su eje X unos 90 grados
Hay que tomar en cuenta que el sensor fue colocado sobre una mesa para esta prueba, aún
así puede estar inclinado, ya que la mesa y el edificio donde se ubica pueden tener ángulos de
inclinación pequeños (respecto a tierra) que contribuyen con el desnivel absoluto del sensor.
Una rotación pura en el eje Y de unos 90 grados produjo la salida siguiente en la consola del
IDE Arduino:
Ir al índice 15
Tema 3: Sensor de medición inercial MPU6050
Figura 5: Salida del monitor al rotar el sensor MPU6050 en su eje Y unos 90 grados
Los resultados previos indican que el sensor puede funcionar para determinar su inclinación
aproximada respecto al suelo siempre que se haya calibrado y fijado adecuadamente en un
soporte.
Es posible usar el MPU6050 para realizar sistemas de control en drones o plataformas que
requieran nivelación o control de inclinación. Cabe destacar que este sensor no es de los más
precisos de su tipo, en caso de requerir mediciones de mayor precisión y menos ruido se pueden
adquirir otros modelos de sensores disponibles comercialmente, cuyo modo de funcionamiento es
muy similar al del MPU6050.
16 Ir al índice
3.4. Sistema de control de inclinación (posición angular)
// última revisión: 13-dic-2024
// Librerias I2C para controlar el mpu6050 y el servo
// la libreria MPU6050.h necesita I2Cdev.h, I2Cdev.h necesita Wire.h
#include "I2Cdev.h"
#include "MPU6050.h"
#include "Wire.h"
#include <Servo.h>
float accel_ang_x;
float accel_ang_y;
float dt=0;
double tiempo_prev=0;
float ang_x, ang_y=0; // angulos de ejes del sensor (grados)
float ang_x_prev, ang_y_prev; // valores previos
int refX=45; // angulo arbitrario de la plataforma (entre -90 y 90) respecto a la tierra
int refM=90; // angulo del eje del motor respecto al motor (0 - 180)
//*************************************************************
void setup() {
// SENSOR Y COM SERIAL:
Serial.begin(9600); //Iniciando puerto serial
Wire.begin(); //Iniciando I2C
sensor.initialize(); //Iniciando el sensor
// MOTOR SERVO:
// Iniciamos el servo para que empiece a trabajar con el pin 9
servoMotor.attach(9); // pin digital 9, o D9
delay(1000);
// Inicializamos al ángulo 0 el servomotor
servoMotor.write(90); // 0 a 180, al inicio: 0=plataforma hacia abajo, 90=plataforma
horizontal, 180=plataforma hacia arriba
delay(1000);
do{ // se ejecuta hasta que se nivele la plataforma en X (acoplada al eje del motor)
// Leer las velocidades angulares y aceleraciones
sensor.getRotation(&gx, &gy, &gz); // sin procesar
sensor.getAcceleration(&ax, &ay, &az); // se necesita para corregir error drift
dt = (millis()-tiempo_prev)/1000.0; // en segundos
tiempo_prev=millis(); // guardar el instante actual como previo
Ir al índice 17
Tema 3: Sensor de medición inercial MPU6050
tiempo_prev=millis();
delay(30);
} // fin de setup
//*************************************************************
void loop() {
// Leer las velocidades angulares y aceleraciones
sensor.getRotation(&gx, &gy, &gz); // sin procesar
sensor.getAcceleration(&ax, &ay, &az); // se necesita para corregir error drift
dt = (millis()-tiempo_prev)/1000.0; // en segundos
tiempo_prev=millis(); // guardar el instante actual como previo
// error en X:
ek=refX-ang_x; // error en grados
18 Ir al índice
3.4. Sistema de control de inclinación (posición angular)
flag=1;
refM=180; // nuevo setpoint del eje del motor respecto a caja del motor
}
else{ // cuando está entre 0 y 180 grados entonces...
servoMotor.write(refM+ek); // valor al que quedará rotado el eje hasta la proxima
correccion del error ek
flag=1;
refM=refM+ek; // nuevo setpoint del eje del motor respecto al motor
}
} // else
} // FIN DE IF
}
else{ // cuando está entre 0 y 180 grados...
servoMotor.write(refM+ek);
flag=1;
refM=refM+ek;
} // else
} // else
} // FIN DE IF
delay(3); // para generar un breve retardo
i=i+1;
ek_prev=ek; // error previo (en caso de usarse para algun otro metodo de control)
if(i==5){ // cada n ciclos loop se volverá a escribir pwm
i=0;
flag=0;
} // fin de if
} // fin de loop
Puede observar que no en todos los ciclos de loop se corrige la señal enviada al motor, el
error ek es el incremento que se agrega al ángulo del motor; en este sistema no se puede
implementar un control con parámetros (como PI, PID, …) ya que el servo motor tiene su propio
control de velocidad y posición incorporado. En caso de usar otro mecanismo que conecte la
plataforma con el eje del motor, se debe determinar el error de sensor e k, el ángulo inicial y final del
sensor αk, y con estos datos se determina el incremento requerido en el angulo del eje del motor
(ángulo respecto al cajetin del motor).
Ir al índice 19
Tema 4: Sensor de distancia por ultrasonido AJ-SR04M
servo motor usando el código de la sección anterior, este ha funcionado sin inconvenientes.
Primero el sensor MPU fue calibrado según lo descrito en la sección de calibración, antes de
ejecutar el código de control.
Los otros modos básicamente transmiten un dato serial codificado por el pin echo hacia el
exterior. El módulo puede encargarse internamente de disparar el sensor y enviar periódicamente
la medida, o en su lugar se pueden enviar pulsos al pin trigger del sensor, cada vez que se quiere
obtener una medición (el resto del tiempo el módulo permanecerá en reposo).
Figura 6: Modo 1 de funcionamiento del sensor AJ-SR04M, activación por disparo y medida
dada como función de la duración del pulso en señal “echo”
20 Ir al índice
5. Sensor de distancia por ultrasonido HC-SR04 y similares
Figura 7: Modo 4 de funcionamiento del sensor AJ-SR04M, activación por señal en trigger y
medida dada como valor serial
// Rutina para probar el sensor HC-SR04, en modo GPIO (usando Trigger y Echo).
// Mauricio Hernandez
#define TRIG 8
#define ECHO 9
#define LED 10
#define TIMEOUT 200000 // timeout, tiempo de espera en microsegundos
// el sensor está diseñado para medir cada al menos 50ms o 60ms
// el ancho del pulso Echo durará unos 36 ms si no se detecta objeto (cuando la onda no
retorna)
// se debe permitir al menos 10ms entre el final del pulso Echo y el siguiente flanco de
subida en Trigger
void setup() {
Serial.begin(9600);
pinMode(TRIG,OUTPUT);
pinMode(ECHO,INPUT);
pinMode(LED,OUTPUT);
digitalWrite(TRIG,LOW); // se coloca a cero
Ir al índice 21
Tema 5: Sensor de distancia por ultrasonido HC-SR04 y similares
void loop() {
tp=medirTiempo(); // tp en microsegundos
//calculo de distancia en cm:
if (tp<=30000) {
distancia=v*tp/2;
Serial.print("Distancia en cm: ");
Serial.println(distancia);
Serial.println("\n");
}
else {
Serial.print("Ausencia de objeto u objeto muy alejado");
Serial.println("\n");
distancia=0;
}
} // fin de loop
22 Ir al índice
6. Temporizador digital programable HCW-M421
El panel frontal de botones permite configurar, activar y pausar el módulo. Puede ser
alimentado a traves de las borneras de alimentación (6 – 30 V), o alternativamente por puerto
USB. Tiene una entrada digital Trigger, que al recibir un pulso inicia el funcionamiento en el modo
seleccionado.
En modo de reposo OFF, haga una pulsación corta del botón SET para ver un resumen del
modo actual y los valores de parámetros en el display (OP, CL, LOOP). Los modos disponibles
son:
P1.2: Es igual que P1.1, expecto que un nuevo flanco durante el transcurso de OP reinicia la
cuenta OP, quedando el relé activado, hasta que termine el tiempo OP normalmente.
P1.3: En este caso, el inicio funciona como los dos anteriores. Un flanco en el transcurso de
OP finaliza la cuenta OP y el relé se apaga, quedando listo para un nuevo flanco.
P-2: El relé se activa después de transcurrido el tiempo CL, cada vez que se recibe un flanco
de subida en Trigger. El relé se mantiene activo durante el tiempo OP. Un flanco durante el
transcurso de OP es ignorado.
P3.1: Activa el relé durante el tiempo OP y se desactiva durante el tiempo CL de forma cíclica,
el número de veces fijado en LOOP. Si ocurre un flanco durante el conteo, el relé se apaga y se
detiene el ciclo.
P3.2: Igual que P3.1, pero funciona sin necesidad de flanco en Trigger, se activa al energizar
el módulo.
Mantenga una pulsación larga en SET para ingresar al listado de modos. Puede navegar por
los modos pulsando UP/DOWN.
Para elegir uno de los modos haga una pulsación corta del botón SET. Al hacer esto se
muestra durante unos segundos en pantalla alguno de los parámetros correspondientes (CL, OP,
LOOP) seguido de su valor, pulse UP/DOWN para cambiar el valor. Cuando este listo pase al
siguiente parámetro pulsando SET, y así de forma cíclica. Cuando termine con todos los
parámetros haga una pulsación larga en SET para volver al modo de reposo inicial.
Ir al índice 23
Tema 7: Otros módulos y dispositivos
Finalmente pulse STOP (pulso corto) para pasar a modo activo (ON en pantalla). El
dispositivo queda en espera de un flanco de subida en Trigger.
24 Ir al índice
7.2. Servo motores
Otros módulos disponibles son 2 módulos de 4 relés de estado sólido cada uno, el cual se
muestra en la figura 10. El modelo del relé es el G3MB-202P, este tipo de relé maneja corriente
alterna. La tensión de operación es de 5 V para el control. Cada relé tiene una capacidad de 2A,
hasta 240VAC. La corriente de trabajo es de unos 12mA por relé.
Figura 10: Modulo de 4 relés de estado sólido, se disparan con nivel bajo en la entrada
Estos relés están especificados como “disparador por nivel bajo” (Low level trigger), lo cual
significa que se activan con un nivel de voltaje lógico bajo. Se pueden conectar al Arduino
directamente.
Ir al índice 25
Tema 7: Otros módulos y dispositivos
Se debe tomar en cuenta el peso de la carga de tal manera que no supere el peso límite que
puede mover un servo motor (generalmente dado como torque en Kg.cm). Como regla general, en
un servo con un par-motor de 2 Kg.cm, el producto del radio en el que cuelga la carga y su peso P
(o en su defecto la componente del peso perpedicular al radio), no debe superar el valor de 2 * g.
Por ejemplo, a un radio r = 2 cm del eje del motor, solo se podría colocar 1 kilos de carga (2/r)
máximo (carga con centro de masa lo mas cerca posible del punto de radio r = 2 cm).
Por lo general los servomotores tienen una caja reductora de las revoluciones (RPM) del eje
del motor, para trabajar en la zona de operación de mayor torque de salida.
Por lo general se usa una secuencia de 4 pasos (4 estados de energización) para hacer girar
el rotor, en cada paso se energizan las dos bobinas, de un paso al siguiente se invierte el sentido
de corriente de una bobina, en el próximo paso se invierte la corriente de la otra bobina, y así en lo
sucesivo. Esto se ve en el ejemplo de código siguiente el cual fue probado con motores de paso
bipolares.
Moviendo un motor paso a paso 4 cables NEMA en ambos sentidos con Arduino, sin usar
librería
26 Ir al índice
7.3. Motor de paso
// Siempre estan encendidas ambas bobinas en cada paso, en el paso siguiente se invierte
la corriente de una bobina, y luego en la otra bobina, y así en lo sucesivo.
// Cada bobina se ha conectado a un puente H (L298N).
void setup()
{
// Serial.begin(115200);
pinMode(IN1, OUTPUT); // los pines 1 y 2 son los terminales de una bobina, los pines 3 y
4 son para la otra bobina
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
}
void loop()
{ while(steps_left>0)
{
stepper() ; // Avanza un paso, no hay retardos internos
steps_left-- ; // Un paso menos
delay(tr); // esto controla la frecuencia de los pasos, colocar 10 como
mínimo (10 es aprox 100Hz)
//(con tr de 40ms, la medición manual de tiempo de vuelta es cercana 2.6 seg)
}
delay(1000); // tiempo entre giros del motor
Direction=!Direction; // inversión de giro condicional y reset del total de pasos
restantes.
steps_left=STEPS;
}
SetDirection();
}
Ir al índice 27
Tema 7: Otros módulos y dispositivos
En el ejemplo se usa el retardo propio del lazo loop añadiendo además retardos explícitos con
delay(tr) para establecer la velocidad de giro del motor. Los motores de paso típicamente manejan
frecuencias cercanas a 60 Hz (pasos por segundo). La variable Steps indexa el paso que se va a
usar en cada iteración, el operador residuo se encarga de “reiniciar” el valor de Steps a cero
cuando llega a 4 (o -4), como se explica en el código. La función stepper() es la encargada de
realizar cada paso estableciendo los voltajes en los 4 pines respectivos, y en general no produce
retardo apreciable. El sentido de giro del motor lo define el modo de cambio de Steps
(descendente o ascendente), que está en función del valor de Direction (1 o 0).
Cuando se requiera detener y posicionar el rotor en un ángulo fijo solo hay que detener el
avance de pasos dejando el motor en uno de los pasos de la secuencia (por ejemplo {1,0,1,0}), sin
desenergizar las bobinas, ya que al hacerlo el rotor queda libre de girar y el motor no aplica par.
Cada paso es un ángulo fijo de rotación que depende de la fabricación de motor (número de
polos).
Los pasos por vuelta (PPR por siglas) del motor dependen de su construcción, en específico
de la cantidad de pares de polos norte-sur en la periferia interior del estator. Para más detalles del
funcionamiento interno del motor de paso, puede consultar información disponible en Internet.
Valores típicos de PPR son 64 y 49 pasos, entre otros. En realidad se suele hablar de medios
pasos (half step), cuando un polo del rotor se alinea justo al frente de un polo opuesto del estator, y
además puede colocarse en el medio entre dos polos adyacentes del estator.
El motor de 6 cables se suele manejar como uno de 5 cables conectando las tomas centrales.
Las tomas centrales se conectan a neutro y se alimentan las bobinas con un voltaje positivo en sus
extremos, en una cierta secuencia. Se explica el modo de 8 pasos con ayuda de la figura 11 y la
tabla 7.1. Cada bobina A y B se divide en dos mitades (fases + y -) por la toma central, se muestra
la secuencia de encendido de las fases en el tiempo, dando un total de 8 pasos que se repiten
cíclicamente. Un valor 1 en la tabla 7.1 indica que se energiza esa fase con un voltaje alto en el
extremo no común. Un cero indica voltaje cero.
28 Ir al índice
7.3. Motor de paso
Fase -
Bobina B
Fase + Fase -
Paso 5
GND
Paso 6
Paso 7
Bobina A
Fase +
GND
Figura 11: Diagrama del bobinado simplificado del motor de paso unipolar de 6 cables, las
flechas representan 3 pasos de giro de la tabla 7.1
Bobina A Bobina B
1 1 0 0 0
2 1 0 1 0
3 0 0 1 0
4 0 1 1 0
5 0 1 0 0
6 0 1 0 1
7 0 0 0 1
8 1 0 0 1
Ir al índice 29
Tema 7: Otros módulos y dispositivos
Observe que en ningún paso de la tabla 7.1 se alimentan dos fases de una misma bobina,
siempre de bobinas diferentes, esto se debe tomar en cuenta al momento de conectar
correctamente el motor al controlador.
El diagrama de la figura 11 es una simplificación de las bobinas del motor, que realiza una
vuelta completa con 8 pasos. La mayoría de motores realiza muchos más pasos en una vuelta,
debido a la distribución de las bobinas en la periferia del estator.
Los motores de paso también se clasifican por la construcción del rotor, existen los de imán
permanente, de reluctancia variable (rotor sin polos magnéticos) y los híbridos, estos últimos
tienen un rotor magnetizado con polos norte y sur alineados con el propio eje del rotor.
/* ----------------------------------------------------------------
Moviendo un motor paso a paso de 6 cables (o de 5 cables) en ambos sentidos con Arduino,
sin usar librería
30 Ir al índice
7.3. Motor de paso
{1, 0, 0, 1}
}; // arreglo del modo half, medios pasos
void setup()
{
// Serial.begin(115200);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
}
void loop()
{ while(steps_left>0)
{
stepper() ; // Avanza un paso, no hay retardos internos
steps_left-- ; // Un paso menos
delay(tr); // esto controla la frecuencia de los pasos, colocar 10 como
mínimo (10 es aprox 100Hz)
//
}
delay(1000);
Direction=!Direction; // inversión de giro y reset del total de pasos restantes.
steps_left=STEPS;
}
void SetDirection()
{
if(Direction)
Steps++;
else
Steps--;
// Uso de operador residuo
Steps = ( Steps + 8 ) % 8 ; // al ingresar step = 8 (o -8), se devuelve step = 0
//al ingresar Step = -1, se devuelve Step = 7, Step = -2 devuelve Step = 6, y así
sucesivamente
}
El código anterior muestra cómo controlar de forma sencilla un motor de paso unipolar
mediante la secuencia de 8 pasos 6. La función Stepper es la encargada de establecer cada paso,
escribiendo en los pines de salida. La función SetDirection() va cambiando el valor de Steps entre
0 y 7 para indexar cada paso en el arreglo Paso.
Ir al índice 31
Tema 8: Anexos
8. Anexos
8.1.1. Windows
Se puede hacer la instalación del Arduino IDE en Windows, versión legacy (1.8.19), además
del driver del chip CH340G para la comunicación UART del IDE con placas clon de Arduino. Puede
usarse también una versión más reciente del IDE Arduino (2.3.2 o posterior).
Figura 12: Fecha y versión del controlador del chip CH340G y similares (Windows)
Una vez abierto el IDE, seleccione en el menú Herramientas la placa Arduino a utilizar. El
programador seleccionado7 para las placas Nano clon usualmente es el AVRISP mkii, pero puede
probar con otro. Se selecciona generalmente el procesador objetivo ATMega328p con
bootloader8 antiguo para usarlo con la placa Nano. Estas opciones están en el menú Herramientas
del IDE de Arduino.
7 En Arduino IDE se hace clic en Herramientas > Programador y luego en el programador que tenga conectado con el microcontrolador objetivo.
8 El bootloader es un microcódigo del controlador ATMega que contiene la configuración necesaria para que inicie ya sea como lo hace en una placa
Arduino, o bien como otro microsistema que no sea Arduino.
32 Ir al índice
8.1. Preparación del software Arduino
Figura 13: Opciones del menú herramientas en Arduino IDE 2.3.2 (Windows)
Las librerías se colocan en la carpeta Library de la instalación de Arduino IDE 1.8.x. Se debe
colocar la directiva “include” en el código para incluir una librería, por ejemplo así: “include pwm.h”.
Las librerías constan de ficheros h y cpp.
La versión de Arduino IDE 2.3.2 (o superior) por defecto instala las librerías en la carpeta
Documentos/Arduino/libraries del usuario de Windows.
8.1.2. Linux
En el caso de Linux hay algunos pasos adicionales para realizar correctamente la instalación
del IDE, se requiere tener permisos para acceder al puerto serie desde la aplicación Arduino IDE.
Puede descargar el instalador del IDE comprimido disponible en el sitio web, se sugiere
descomprimir en la carpeta “Home” u otra conocida. Este tiene unos archivos de shell llamados
Arduino-setup.sh e install.sh o similar. Ejecute el archivo Arduino-setup en primer lugar, luego el
archivo install:
./Arduino-setup.sh $USER
./install.sh
sudo ./install.sh
Ir al índice 33
Tema 8: Anexos
Para tener permisos de usar el puerto serie se puede añadir el usuario Linux al grupo
propietario del fichero de puerto serie, dicho grupo debe tener los permisos de lectura y escritura
sobre el fichero de puerto serie. Abra el Arduino IDE, conecte la placa y ejecute lo siguiente en
terminal Linux para desplegar detalles de los grupos del archivo de puerto serie:
ls -l /dev/ttyUSB0
ttyUSB0 es el fichero de puerto serie (puede tener otro nombre en su sistema). El nombre del
fichero se puede ver en la ventana principal de Arduino IDE, en el puerto al que se conecta la
placa. Se debe mostrar a la salida algo como:
En el ejemplo el grupo propietario se llama dialout y tiene permisos de escritura y lectura (rw)
sobre el fichero. Se agrega el usuario Linux al grupo dialout en este caso:
username es el nombre de usuario de la sesión Linux que se está usando. Se debe tener
cuidado de no omitir la opción -a, esta opción activa la modalidad de añadir nuevo grupo, en lugar
de sustituir los grupos actuales a los que pertenece username.
34 Ir al índice
8.2. Pinout Arduino
Los pines para PWM están designados del mismo modo en Arduino Nano y Uno: PD3, PD5,
PD6, PB1, PB2, PB3. En el código se identifican respectivamente como 3, 5, 6, 9, 10, 11. En el IDE
se usa A0, A1, … para hacer referencia a los pines de entrada analógica.
void loop() {
val = analogRead(potpin); // en el pin son valores de 0 a 5 voltios
val = map(val, 0, 1023, 0, 180); // pasa el valor leido (0-1023) a grados (0-180)
myservo.write(val); // val es un valor en grados
delay(15); // tiempo de espera
}
Ir al índice 35