Control II
Ingeniería Electrónica.
Universidad del Magdalena.
Ciro Rueda, Jose Gutierrez, Holman Ortega
Resumen del proyecto.
Para este proyecto se realizó una
interfaz básica de usuario en Processing, mediante la cual se puede controlar
el movimiento de nuestro hidrodeslizador, la comunicación inalámbrica entre el
PC y el bote se lleva a cabo mediante comunicación serial por medio de un par
de módulos Xbee configurados para comunicación punto a punto.
Que es un
hidrodeslizador?
Un hidrodeslizador o bote pantanero,
como algunos la conocerán es una embarcación impulsada únicamente por el flujo
de aire provocado por una gran hélice, la dirección de un hidrodeslizador,
normalmente corre por cuenta de unos timones que direccionan dicho flujo de
aire, cumpliendo con estas premisas básicas se construyó nuestro modelo de
hidrodeslizador, teniendo en cuenta un compartimiento para ubicar la electrónica
del proyecto.
![]() |
| Prototipo de hidrodeslizador usado en el proyecto. |
Control del hidrodeslizador.
Para el control de la dirección se planeó usar
un controlador PID encargado de la posición
de los timones, por medio de un potenciómetro acoplado mecánicamente a un motor
DC.
![]() |
| Diagrama de control de posición por PID |
Sin embargo debido a las características del sistema físico a controlar, que en este caso se trataría de un sistema tipo 1 se encontró que para el control de este tipo de sistemas y para este en particular basta con a constante proporcional del controlador, es decir un controlador proporcional. Debido a esto la mejor opción, a nivel estructural de eficiencia y practicidad fue implementar un servomotor de modelismo, puesto que estos poseen el sistema de potenciómetro, motor y sistema de control proporcional en un montaje estándar, fácil y rápido de implementar, para más información del funcionamiento y la estructura interna de un servomotor pueden dirigirse a aquí ó aquí.
Para la propulsión se usó un
motor brushless usado en aeromodelismo, el cual al tratarse de un motor AC, necesita
su propio circuito de control y alimentación, en ultimas gracias a dicho sistema
de control este motor puede implementarse de igual forma que un servomotor común. Véase.
![]() |
| Motor brushless Turnigy empleado en el proyecto |
Para el control de este “par de servos”
se usó un Arduino Uno el cual activara y cambiara la señal de control de los
mismos dependiendo de los datos que reciba a través de su puerto serial.
![]() |
| Tarjeta de desarrollo Arduino Uno |
El encargado de enviar los datos
mencionados anteriormente no es más que una pequeña interfaz en Processing, la
cual transmite las pulsaciones de una serie de teclas hechas por el usuario hacia el Arduino uno que
es el encargado de traducirlas a comandos de control.
![]() |
| Interfaz implementada en Processing |
Para
lograr la transmisión inalámbrica de los datos, como se mencionó anteriormente
se usaron un par de modulos Xbee configurados en comunicación punto a punto,
uno de ellos conectado por usb al pc mediante una tarjeta Xbee Explorer, y el
otro acoplado al Arduino uno mediante una tarjeta Xbee Shield.
![]() |
| Tarjeta Xbee Explorer |
![]() |
| Tarjeta Xbee Shield |
Processing.
La idea de la interfaz en Processing
no es más que enseñarle al usuario los controles para el manejo del
hidrodeslizador y transmitir las acciones del usuario mediante el puerto
serial.
Hay que tener en cuenta que la
interfaz, no debe ser muy llamativa ni presentar demasiada información al
usuario, puesto que este debe concentrarse principalmente en la posición y
trayectoria actual del bote, partiendo de tales consideraciones y objetivos se creó
el siguiente código:
import processing.serial.*;
Serial myPort;
PImage A;//Imagen para la tecla A
PImage D;//Imagen para la tecla D
PImage W;//Imagen para la tecla W
PImage M;//Imagen para la tecla M
PImage K;//Imagen para la tecla K
PImage Ap;//Imagen para la tecla A presionada
PImage Dp;//Imagen para la tecla D presionada
PImage Wp;//Imagen para la tecla W presionada
PImage Mp;//Imagen para la tecla M presionada
PImage Kp;//Imagen para la tecla K presionada
int v;
void setup() {
background(0);//fondo de interfaz en negro
size(290, 420);//escala de la interfaz
v=1;//Se establece una velocidad inicial para el Brushless
//Se cargan las imagenes correspondientes a cada tecla
A=loadImage("A.png");
D=loadImage("D.png");
W=loadImage("W.png");
K=loadImage("K.png");
M=loadImage("M.png");
//Se cargan las imagenes correspondientes a cada pulsación
Ap=loadImage("Apress.png");
Dp=loadImage("Dpress.png");
Wp=loadImage("Wpress.png");
Mp=loadImage("Mpress.png");
Kp=loadImage("Kpress.png");
//Se dibuja en pantalla cada tecla en un arreglo vertical
image(A, 10, 100, 60, 60);
image(W, 10, 20, 60, 60);
image(M, 10, 340, 60, 60);
image(D, 10, 180, 60, 60);
image(K, 10, 260, 60, 60);
//Se pon un rotulo junto a cada tecla para notificar
// al usuario sobre la funcion de cada una.
textSize(32);
fill(0, 102, 153);
text("Avanza!!", 90, 60);
text("Derecha!!", 90, 140);
text("Izquierda!!", 90, 220);
text("Acelera!!", 90, 300);
text("Desacelera!!", 90, 380);
//Se inicializa la comunicacion serial
myPort = new Serial(this, Serial.list()[0], 9600);
}
//Se detecta cuando alguna de las
//teclas designadas se ha presionado
//cuando esto sucede se representa la pulsacion y
//se envia el caracter correspondiente a la tecla
//por el puerto serial, el caracter se envia en mayusculas
//para poder identificar que la tecla ha sido pulsada
void keyPressed() {
if (key=='a') {
myPort.write(65);
image(Ap, 10, 100, 60, 60);
}
if (key=='w') {
myPort.write(87);
image(Wp, 10, 20, 60, 60);
println(v);
myPort.write("+v+");
}
if (key=='m') {
//para las teclas k y m no se envian datos cuando son
//presionada, unicamente cuando se sueltan dichas teclas
image(Mp, 10, 340, 60, 60);
}
if (key=='d') {
myPort.write(68);
image(Dp, 10, 180, 60, 60);
}
if (key=='k') {
image(Kp, 10, 260, 60, 60);
}
}
//Se detecta cuando alguna de las teclas designadas se ha
//soltado cuando esto sucede se vuelve a la imagen de tecla por
//defecto y se envia el caracter correspondiente a la tecla
//por el puerto serial, el caracter se envia en minusculas
//para poder identificar que la tecla ha sido soltada
void keyReleased() {
if (key=='a') {
myPort.write(97);
image(A, 10, 100, 60, 60);
}
if (key=='w') {
myPort.write(119);
image(W, 10, 20, 60, 60);
}
if (key=='m') {//cada que se suelta m la velocidad
//actual se reduce, siempre que sea mayor que 1,
//ademas se envia el dato de la nueva velocidad.
myPort.write(109);
image(M, 10, 340, 60, 60);
if (v>1) {
v=v-1;
println(v);
myPort.write("+v+");
}
}
if (key=='d') {
myPort.write(100);
image(D, 10, 180, 60, 60);
}
if (key=='k') {//cada que se suelta k la velocidad
//actual aumenta, siempre que sea menor que 9,
//ademas se envia el dato de la nueva velocidad.
image(K, 10, 260, 60, 60);
if (v<9) {
v=v+1;
println(v);
myPort.write("+v+");
}
}
}
Algo que hay que tener en cuenta
para este código es que si bien se podían enviar todos los datos en una sola
trama, se prefirió enviar los datos de manera independiente, sin embargo solo
cuando se produzca un evento en el teclado, lo cual se puede traducir en una
mayor eficiencia en la comunicación, además de una mayor facilidad para la determinación
y resolución de problemas.
Arduino.
Quien realiza la mayor parte de
trabajo es nuestra placa de Arduino, pues tiene que tomar los datos enviados
por Processing vía serial e interpretarlos para el proceso de control, debido a
que la transmisión se lleva a cabo únicamente cuando ocurre un evento de teclado
en el pc, será muy difícil que se sature el buffer del módulo receptor Xbee o de la placa Arduino, por lo que bien
podemos dejar la tarjeta leyendo datos constantemente o esperando hasta recibir
un dato por el puerto, sin embargo se recomienda leer el puerto solo cuando hay
datos disponibles en el buffer, con el fin de ahorrar batería. Lo cual es mucho
más indispensable en el receptor que en el transmisor puesto que el primero
funciona con baterías, mientras que el último depende de la alimentación del
puerto USB del PC.
Según o anterior el código para la placa Arduino
fue el siguiente:
#include <Servo.h>//se incluye la libreria servo para controlar
//la direccion y la velocidad
Servo motor;//se define una variable servo para el Brushless
Servo paletas;//se define la variable servo para la direccion
int v;//se declara una variable temporal para el valor de velocidad
//puesto que el dato de velocidad es enviado solo cuando ocurre un
//cambio en esta.
int w;//se declara una variable temporal para la accion de avance.
char rx=' ';//se declara una variable temporal para almacenar
//el dato entrante y poder evaluarla.
void setup(){
Serial.begin(9600);//se inicializa la comunicacion serial.
//se declaran los pueros correspondientes a las señales de
//control de direccion y velocidad.
motor.attach(6);
paletas.attach(9);
}
void loop(){
if (Serial.available()) {//se procede solo si hay datos en el buffer del puerto
rx = Serial.read();//se lee el dato recibido y se almacena temporalmente
//si el dato es D se mueven los timones hacia la derecha (servo en 30 grados)
if(rx=='D'){
paletas.write(30);
}
//si el dato es d o a se mueven los timones hacia el centro (servo en 100 grados)
if(rx=='d'||rx=='a'){
paletas.write(100);
}
//si el dato es d o a se mueven los timones hacia a izquierda(servo en 170 grados)
if(rx=='A'){
paletas.write(170);
}
//si el dato esta comprendido entre 1 y 9 significa que es un dato de velocidad, por lo que segun que valor ha llegado
//se le asigna un valor en milisegundos a la señal de contro del motor brushless
if(rx=='1'){
v=1600;
}
if(rx=='2'){
v=1650;
}
if(rx=='3'){
v=1700;
}
if(rx=='4'){
v=1750;
}
if(rx=='5'){
v=1800;
}
if(rx=='6'){
v=1850;
}
if(rx=='7'){
v=1900;
}
if(rx=='8'){
v=1950;
}
if(rx=='9'){
v=2000;
}
//si el dato es W significa que el usuario
//ha oprimido W con el fin de hacer avanzar el bote
//esto se almacena como una variable temporal con valor de 1
//si por el contrario es w(minuscula) significa que el usuario
//ha soltado la tecla y por consiguiente el bote ha de detenerse
if(rx=='W'){
w=1;
}
if(rx=='w'){
w=0;
}
if(w==1){//si la variable de avance es 1 se escribe el valor correnspondiente
//a la velocidad actual en la señal de control del brushless
motor.writeMicroseconds(v);
}
if(w==0){//si la variable de avance es 0 se escribe 1500ms para la duracion del
//pulso de control, lo que se traduce en detener el motor brushless
motor.writeMicroseconds(1500);
}
delay(10);//un periodo de espera para estabilidad de la lectura y control
}
}
Conclusiones.
Con la implementación de estos códigos
y la estructura de control establecida, se logró el control inalámbrico del
hidrodeslizador, de una manera fácil práctica, y sobre todo eficiente tanto energéticamente
como a nivel de comunicaciones, además se consiguió que este proyecto sea fácil
de comprender y re-implementar en un proyecto a mayor escala, esto último
debido principalmente a las herramientas de software y hardware libre
implementadas tales como Arduino y Processing.









No hay comentarios:
Publicar un comentario