Publicidad

sábado, 17 de junio de 2017

Coche RC Laser

Coche radiocontrol con Servo-Láser


En este proyecto vamos a añadir a nuestro coche de control remoto un láser apuntado por dos servos.
Uno de los servos mueve el láser en el eje X, el otro en el eje Y, de esa forma apuntamos el láser dónde queramos.

Y para añadir más complejidad al proyecto, en este coche los motores serán paso a paso. A cambio ganamos en precisión de movimientos.

El láser tiene una construcción modular, por lo que se puede instalar en cualquier tipo de vehículo que se os ocurra. Es un láser de 5mW, pero con uno de potencia suficiente podríamos quemar objetivos.

El coche está construido totalmente a mano, partiendo de una lámina de metacrilato a modo de chasis y el soporte de los motores es un perfil en U sacado de una canaleta para cables como las empleadas por los electricistas.

Detalle de los servos.




Esquema
El shield para motores de Adafruit es perfecto para ese proyecto, ya que permite controlar dos servos y dos motores paso a paso en la misma tarjeta.

Conectamos el receptor de infrarrojos en el pin D2 ya que es el único que no se usa. Y para que el diodo láser no esté permanentemente encendido, en lugar de conectarlo a 5V directamente, lo vamos a conectar al pin A0 y lo encenderemos a voluntad con el mando a distancia.

Los pines analógicos de arduino también se pueden utilizar como entradas/salidas digitales con tan solo configurarlo así en el setup.





Sketch

#include <AccelStepper.h>
#include <AFMotor.h>
#include <IRremote.h>
#include <Servo.h>

// two stepper motors one on each port
AF_Stepper motor1(64, 1);
AF_Stepper motor2(64, 2);

int receiverpin = 2; 
IRrecv irrecv(receiverpin); 
decode_results results;

Servo servoH;  // create servoH object to control a servo 
Servo servoV;  // create servoV object to control a servo                
 
int posH=80;
int posV=80;
boolean laser=0;

// you can change these to DOUBLE or INTERLEAVE or MICROSTEP!
// wrappers for the first motor!
void forwardstep1() {  
  motor1.onestep(FORWARD, DOUBLE);
}
void backwardstep1() {  
  motor1.onestep(BACKWARD, DOUBLE);
}
// wrappers for the second motor!
void forwardstep2() {  
  motor2.onestep(FORWARD, DOUBLE);
}
void backwardstep2() {  
  motor2.onestep(BACKWARD, DOUBLE);
}

// Motor shield has two motor ports, now we'll wrap them in an AccelStepper object
AccelStepper stepper1(forwardstep1, backwardstep1);
AccelStepper stepper2(forwardstep2, backwardstep2);

//Funciones para los motores

void goForward()
{
  stepper1.move(4000);
  stepper2.move(-4000);  
}

void goBackward()
{
  stepper1.move(-4000);
  stepper2.move(4000);    
}
void turnRight()
{
  stepper1.move(-1100);
  stepper2.move(-1100);    
}
void turnLeft()
{
  stepper1.move(1100);
  stepper2.move(1100);    
}
void turnRight45()
{
  stepper1.move(-550);
  stepper2.move(-550);    
}
void turnLeft45()
{
  stepper1.move(550);
  stepper2.move(550);    
}


void setup()
{  
  Serial.begin(9600); 
  irrecv.enableIRIn();
  
  stepper1.setMaxSpeed(600);
  stepper1.setAcceleration(300);
  stepper2.setMaxSpeed(600);
  stepper2.setAcceleration(300);
  
  servoH.attach(10); 
  servoV.attach(9); 
  
  pinMode(A0, OUTPUT);
}

//Funciones para los servos 
//Funcion 1
void servoH_dcha()
{
  if (posH >= 15)
  {
    posH--;
    servoH.write(posH);
    delay(500);
  }
  if (posH < 15)
  {
    posH=posH+5;
    servoH.write(posH);
    delay(500);
  }
}
//Funcion 2
void servoH_izqda()
{
  if (posH <= 165)
  {
    posH++;
    servoH.write(posH);
    delay(500);
  }
  if (posH > 165)
  {
    posH=posH-5;
    servoH.write(posH);
    delay(500);
  }
}
//Funcion 3
void servoV_arriba()
{
  if (posV <= 165)
  {
    posV++;
    servoV.write(posV);
    delay(500);
  }
  if (posV > 165)
  {
    posV=posV-5;
    servoV.write(posV);
    delay(500);
  }
}
//Funcion 4
void servoV_abajo()
{
  if (posV >= 15)
  {
    posV--;
    servoV.write(posV);
    delay(500);
  }
  if (posV < 15)
  {
    posV=posV+5;
    servoV.write(posV);
    delay(500);
  }
}
//Funcion 5 Home
void Home()
{
  servoH.write(80);
  servoV.write(80);
  delay(500);
}

//Funcion LaserONOFF

void laserONOFF()
{
  if (laser==0){
    digitalWrite(A0, HIGH);
  }
  if (laser==1){
    digitalWrite(A0, LOW);
  }
  laser=!laser;
  delay(500);
}


void translateIR()
{
  switch(results.value)
  
  {
    case 0xD05: laserONOFF(); break;  // Laser ON/OFF 
    case 0x505: laserONOFF(); break;  // Laser ON/OFF 
        
    case 0xD02: goForward(); break;  // Go Forward 
    case 0x502: goForward(); break;  // Go Forward 
        
    case 0xD08: goBackward(); break; // Go Backward 
    case 0x508: goBackward(); break; // Go Backward 
        
    case 0xD06: turnRight(); break;  // turn Right 90º
    case 0x506: turnRight(); break;  // turn Right 90º
        
    case 0xD09: turnRight45(); break;  // turn Right 45º
    case 0x509: turnRight45(); break;  // turn Right 45º
        
    case 0xD04: turnLeft(); break;   // turn Left 90º
    case 0x504: turnLeft(); break;   // turn Left 90º    
    
    case 0xD07: turnLeft45(); break;   // turn Left 45º
    case 0x507: turnLeft45(); break;   // turn Left 45º
        
    case 0xD35: servoH_dcha(); break;  //PLAY
    case 0x535: servoH_dcha(); break;  //PLAY    
    
    case 0xD36: servoH_izqda(); break; //STOP
    case 0x536: servoH_izqda(); break; //STOP

    case 0xD00: servoV_arriba(); break;  //CERO
    case 0x500: servoV_arriba(); break;  //CERO    
    
    case 0xD30: servoV_abajo(); break;   //PAUSE
    case 0x530: servoV_abajo(); break;   //PAUSE    
    
    case 0xD1C: Home(); break; //RANDOM
    case 0x51C: Home(); break; //RANDOM
    
    
  }
}


void loop()
{
   if (irrecv.decode(&results))
  {
    translateIR();
    irrecv.resume(); // receive the next value
    //Serial.println(results.value, HEX); 
    //Serial.println(laser);  
  }
 
  stepper1.run();
  stepper2.run();
}

Señales Digitales

En esta práctica encendemos un led mediante un pulsador.
Conectamos el led en D4 y el pulsador en D12, los configuramos como salida y entrada respectivamente.
La resistencia R2 conectada a D12 se llama "pull down" y se pone para conectar a tierra D12, así nos aseguramos que previo a pulsar S1 hay un cero en D12.


Esquema


Código

int switch = 0;
void setup(){
pinMode(4,OUTPUT);
pinMode(12,INPUT);
Serial.begin(9600);
}
void loop(){
switch = digitalRead(12);
if (switch == HIGH) {
digitalWrite(4, HIGH);
}
else {
digitalWrite(4, LOW);
}
}



Proyecto 2b


En el siguiente ejercicio añadimos más complejidad al circuito, con dos pulsadores y tres leds.
Si pulsamos S1 se enciende LED3, si pulsamos S2 se enciende LED3, si pulsamos S1 y S2, se encienden los tres leds.


Esquema
Sketch

int rightswitch = 0;
int leftswitch = 0;
void setup(){
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(7,INPUT);
pinMode(8,INPUT);
Serial.begin(9600);
}
void loop(){
rightswitch = digitalRead(7);
leftswitch = digitalRead(8);
if (rightswitch == HIGH) {
digitalWrite(2, HIGH);
}
else {
digitalWrite(2, LOW);
}
if (leftswitch == HIGH) {
digitalWrite(4, HIGH);
}
else {
digitalWrite(4, LOW);
}
if (rightswitch == HIGH && leftswitch == HIGH) {
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
delay(250);
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
delay(250);
}
else {
digitalWrite(3, LOW);
}
}



Proyecto 2c


En el siguiente ejercicio añadimos un tercer pulsador.
Si pulsamos S1 y S2 se encienden LED2, LED3.
Si pulsamos S2 y S3 se encienden LED3, LED4.
Si pulsamos S1, S2 y S3, se enciende LED3.


Esquema
Sketch

int rightswitch = 0;
int leftswitch = 0;
int centerswitch = 0;
void setup(){
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(7,INPUT);
pinMode(8,INPUT);
pinMode(9,INPUT);
Serial.begin(9600);
}
void loop(){
centerswitch = digitalRead(8);
leftswitch = digitalRead(9);
rightswitch = digitalRead(7);
if (leftswitch == HIGH && centerswitch == HIGH) {
digitalWrite(4, HIGH);
digitalWrite(3, HIGH);
}
else {
digitalWrite(4, LOW);
digitalWrite(3, LOW);
}
if (rightswitch == HIGH && centerswitch == HIGH) {
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
}
else {
digitalWrite(2, LOW);
digitalWrite(3, LOW);
}
if (rightswitch==HIGH && leftswitch==HIGH && centerswitch==HIGH) {
digitalWrite(3, HIGH);
}
else {
digitalWrite(3, LOW);
}
}


Links


Fresadora CNC

Tan solo hay que modificar ligeramente la torre del eje Z para alojar una multiherramienta tipo Dremel (u otra similar). El plano está disponible para descargar, en formato SketchUp al final de la página. Para el resto de detalles constructivos de la CNC, montaje mecánico, esquemas y calibraciones, por favor consulta el Proyecto 39.1.


Diseño 3D con SketchUp

Montaje de la torre

Una vez terminado el montaje de la torre y de la herramienta de fresado, sólo queda generar el archivo gcode que contiene la pieza a mecanizar. Para el diseño de las piezas vamos a utilizar SketchUp Make y la extensión para tallado en 3D SketchUcam. Puedes descargar la extensión en la página de El Profe García.

Echa un vistazo a este vídeo y a este otro para ver como añadir la extensión SketchUcam y cómo diseñar piezas con SketchUp Make. Gracias de nuevo a El Profe García.

Ambos videotutoriales son sencillos y fáciles de seguir. Con ellos he diseñado la primera pieza y tengo que decir que ha funcionado a la primera.

En el siguiente vídeo puedes ver la CNC trabajando.

Fresadora CNC con Arduino


Se trata de una abrazadera soporte para la fresadora -concretamente una Dremel 3000- ya que la que estaba utilizando originalmente la mecanicé a mano, y el ajuste era mejorable. Es curioso que la primera pieza que hago con la CNC es para la propia CNC. Esto la convierte en una máquina capaz de autoreplicarse parcialmente. Dejo el archivo para descargar al final de la página.

Por cierto, la fresa que he utilizado es de acero, de forma rectangular y 3,2mm de diámetro, más detalles aqui.



A continuación una captura de pantalla de como he configurado SketchUcam. No sé hasta qué punto el parámetro Spindle Speed es importante, en algunos vídeos lo sitúan en 15.000 y en otros en 400. Tendré que hacer más pruebas para ver cómo afecta al funcionamiento de la CNC.


Lo que sí he modificado a la baja respecto de los vídeos mencionados anteriormente es la velocidad de fresado Feed Rate y Plunge Rate. Ya que se trata de una CNC casera, prefiero ser conservador, por lo menos al principio, y evitar dañar la máquina o romper la fresa por ir demasiado deprisa.

Otra opción importante es marcar el check box Generate Multipass y seleccionar una profundidad baja. Por ejemplo, para fresar las dos piezas que componen la abrazadera soporte de la Dremel, he utilizado metacrilato de 10mm de espesor. Al ser un material tirando a duro, he marcado la opción Generate Multipass y he seleccionado una profundidad de 0,5mm por cada pasada, de forma que la fresa va desbastando 0,5mm cada pasada. Puede parecer poco, pero mejor ir despacio a tener que comprar una fresa.

En este vídeo hay más información sobre cómo configurar SketchUcam.

Mi recomendación es que empecéis seleccionando poca profundidad -incluso con plástico o DM- y vayáis incrementando la velocidad a medida que hacéis pruebas. Si veis que la fresadora avanza con soltura -sin atascarse- probad a subir la profundidad a 1 ò 2 mm. La velocidad de fresado depende de varios factores; la potencia de la fresadora, el par que suministran los motores y del tipo de fresa, si es de calidad, si está más o menos afilada, etc...

Por ejemplo, las máquinas con transmisión correa dentada tienen mayor velocidad que las que utilizan varilla roscada, pero por contra transmiten menos par de giro que las de varilla.

Para trabajar con maderas y plásticos blandos, poliestireno y similares, la transmisión por correa dentada es una buena opción. Por contra, en las máquinas para fresar maderas y plásticos duros, aluminio y metales blandos, la transmisión por varilla roscada o tornillo sinfin es casi obligatorio.

Bien, una vez configurado SketchUcam, ya podemos diseñar la pieza y generar el archivo gcode como vimos en los videotutoriales más arriba. El archivo, se envía a la CNC con el Universal Gcode Sender.

Antes de enviar el archivo a la CNC, podemos simular su funcionamiento con el software CAMmotics, así verificamos que el archivo se ha generado correctamente.

Abrir el programa CAMotics, ir a File, Open Proyect.



Por defecto CAMotics no reconoce los archivos .cnc por lo que hay que seleccionar All files (*.*) en la carpeta donde se guarde el archivo de SketchUp


Ir a ViewHide Surface. Después clic en el icono PLAY para simular el funcionamiento



Si la simulación es correcta, ya podemos enviar el archivo a la CNC. Abrimos el Universal Gcode Sender, conectamos el Arduino al PC , seleccionamos el puerto COM que corresponda y clic en Open.


Llevamos manualmente la CNC a la posición Home, en los tres ejes y pulsamos en Reset Zero. La posición Home para el eje Z es aquella donde la fresa hace contacto con la pieza.




Clic en para seleccionar el archivo gcode con el dibujo.
Clic en para enviar el archivo a la CNC, la máquina comenzará a trabajar la pieza.

¡Suerte con vuestra máquina!



Iré ampliando este tutorial, en la medida que realice más pruebas con la CNC.
Trataré de aportar aquí la mayor información posible para que cada uno saque el máximo partido a su máquina.




ċ
Planos torre y archivos gcode.rar 
(337k)

Adj Power Supply with Voltage & Current Meter



El proyecto que traigo a continuación es una ampliación del tutorial sobre fuentes de alimentación y multímetros.

Por un lado vamos a hacer una fuente de alimentación de laboratorio, ajustable, con dos tensiones de salida, una positiva y otra negativa. A la que vamos a añadir un voltímetro y un amperímetro hechos como no, con Arduino.

Hacer un voltímetro con Arduino es muy fácil. Las tensiones de hasta 5 voltios se pueden medir directamente en las entradas analógicas y luego convertir la medida en un valor de tensión. Sirve por ejemplo para medir la carga de una pila.

Pero cuando la tensión que queremos medir es de por ejemplo 30 voltios, hay que atenuar la señal para no dañar el Arduino. Esto se consigue fácilmente con un divisor de tensión.

En la figura de abajo tenemos un voltímetro sencillo. Suponiendo que la corriente que circula hacia la entrada A0 es despreciable, la tensión que medimos en A0 es Vref / 6 es decir que tenemos una atenuación x6, lo que nos permite medir tensiones de hasta 30 voltios. Sustituyendo R2 por una resistencia de 10M tendríamos una atenuación x11.



Pero ¿qué sucede si la tensión que queremos medir es negativa y superior a 5 voltios? Por un lado tenemos que atenuarla y además convertirla en una tensión positiva. Para ello vamos a utilizar un amplificador operacional configurado como amplificador-inversor. Eligiendo las resistencias R3 y R4 de igual valor tenemos una ganancia = -1 con lo que la tensión de salida es igual a la de entrada, pero positiva.



Utilizar amplificadores operacionales para adaptar la señal, añade una pequeña complicación a nuestro circuito, y es que necesitamos una alimentación auxiliar de +-12V ó +-15V para que funcionen correctamente. ¡Qué aburrido sería esto si todo funcionase a la primera!

Para solucionar este problema añadiremos una fuente auxiliar hecha con un par de reguladores L7812 y L7912. Aprovecharemos la salida de +12V para alimentar el Arduino.



Bueno, ya tenemos la parte del voltímetro solucionada. Ahora vamos a por el amperímetro.

Para medir la corriente vamos a utilizar un sensor de efecto Hall ACS-712. Este módulo es capaz de medir corrientes de hasta 5 amperios AC / DC. También hay modelos de 20 y 30 amperios.

Su funcionamiento es muy sencillo, se conecta según el esquema, se alimenta con 5V del Arduino y en el pin Output entrega una tensión proporcional a la corriente que circula por la carga. Esta salida se conecta directamente al Arduino dado que su valor oscila entre 1,5 y 3,5V para el modelo de 5 amperios.

Para saber más sobre sensores de corriente consulta el blog electrodragon y la página de Henry´s Bench



Ya sabemos la teoría sobre cómo hacer un voltímetro y un amperímetro con Arduino, ahora vamos a la práctica.

A continuación el esquema de la fuente de laboratorio con dos tensiones ajustables de manera independiente. Para más información consultar los datasheet de los CI´s LM317 y LM337.




Seguidamente podéis ver la fuente auxiliar de +-12V para el operacional y el Arduino, el divisor de tensión para atenuar la tensión de entrada y el adaptador de señal para poder conectarla a los pines analógicos.


El amplificador operacional utilizado es el LF347N, pero serviría cualquiera de propósito general. 

Como este encapsulado dispone de cuatro amplificadores, he utilizado dos de ellos en la configuración Seguidor de Tensión o Buffer No Inversor,  para aislar la tensión de referencia, de los pines analógicos del Arduino. Con esto conseguimos que la tensión que queremos medir no se vea afectada por conectarla a la entrada analógica de nuestra tarjeta Arduino.

Como buenos observadores que sois, os habréis dado cuenta de que en el divisor de tensión he utilizado un trimmer en lugar de una resistencia. Esto es por dos razones; en primer lugar para modificar la atenuación en función de la tensión que queramos medir, así el mismo circuito serviría para medir tensiones de hasta 30 ó 55 voltios. Y en segundo lugar se consigue afinar la atenuación para que sea lo más precisa posible, es decir que si VCC son 30 voltios, en la entrada del operacional tengamos realmente 5 voltios.



Y por último el esquema completo que incluye la fuente, las alimentaciones auxiliares, el adaptador de señal, el Arduino y un display LCD de 16x2 caracteres ya conocido por todos vosotros de proyectos anteriores.

Alimentamos el Arduino con 12V de la fuente auxiliar a través del pin VIN y con la salida de 5V alimentamos el display y los dos sensores de corriente.  


Un par de observaciones antes de continuar.

En los sensores de corriente hay que tener en cuenta el sentido en el que circula la corriente, ya que éste influye en la medida que se obtiene. Si la corriente fluye como en la imagen, Vout se incrementa con la corriente, si la corriente circula en sentido contrario, Vout se decrementa al subir la corriente que circula por el sensor. El amperímetro aquí expuesto funciona conectando la carga como se muestra en la imagen.

También indicar que estos sensores tiene un pequeño offset. En ausencia de corriente circulando por el sensor, entregan una tensión de salida que puede llevar a medidas erróneas. Para solucionarlo he incluido en el sketch un función que se ejecuta una sola vez al arrancar el Arduino. Esta función lee el valor del offset, lo guarda en una variable y se resta al valor leído para que coincida con el valor real. Para que el cálculo del offset sea correcto hay que tener la precaución de no conectar ninguna carga hasta que Arduino haya finalizado su cálculo.

En segundo lugar indicar un problema que tuve durante el desarrollo del voltímetro, por si a alguno os pasa.
Resulta que en ocasiones la medida daba resultados muy dispares y el display se venía abajo, fallaba, se iba la lectura.

Descubrí que los leds del backlight del display consumen casi 360mA lo que hace que el regulador interno de 5V del Arduino funcione al límite de corriente, lo que ocasiona caídas de tensión por debajo de 5V y un mal funcionamiento general. 

Solución, colocar una pequeña resistencia de 22 ó 47 ohmios a la entrada del backlight para limitar el consumo del mismo. Se pierde algo de brillo en el display, pero se gana en estabilidad y buen funcionamiento.




Una imagen de la fuente terminada





Por problemas de espacio en el display he acortado los nombres de las variables a la hora de mostrarlas por pantalla.

En el Sketch he utilizado VCC e ICC para la tensión y la corriente positivas y VEE e IEE para las negativas. 

La tensión y corriente positivas se muestran como VC e I en la fila superior y VE e I en la fila inferior.


Sketch

/*
  Dual voltage & Current Meter with Auto Offset Adjust
  
*/

#include <LiquidCrystal.h>
LiquidCrystal lcd(4, 5, 6, 7, 8, 9); // pins for RS, E, DB4, DB5, DB6, DB7

// Variables for the voltmeter
int RawVCC = 0;
float VCC = 0;
float auxVCC = 0;
int RawVEE = 0;
float VEE = 0;
float auxVEE = 0;

//Variables fot the ammeter
float ICC = 0;
float offset1 = 0;
float IEE = 0;
float offset2 = 0;

boolean ofst = 0;

void setup()
{
lcd.begin(16, 2);
lcd.clear();
}

// Function to calculate ICC offset
// Do not connect any load until Arduino finishes calculating the offset.
float offset1Adj()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("calc. offset");
  lcd.setCursor(0, 1);
  lcd.print("please wait...");
  delay(2000);  // to allow time for stabilizing offset
  for(int i = 0; i < 1000; i++) {
  offset1 = offset1 + (.0264 * analogRead(A3) -13.51);
  delay(2);
  }
  
  return offset1;
}

// Function to calculate IEE offset
float offset2Adj()
{
  
  for(int j = 0; j < 1000; j++) {
  offset2 = offset2 + (.0264 * analogRead(A2) -13.51);
  delay(2);
  }
  ofst = 1; // to calculate offset once at the beginning
  return offset2;
}

  
  

void loop()
{
  if (ofst == 0) 
    {
    offset1 = offset1Adj();
    offset2 = offset2Adj();
    }
    
  float average1 = 0;
  for(int i = 0; i < 1000; i++) {
  average1 = average1 + (.0264 * analogRead(A3) -13.51);
  delay(1);
  }
  
  float average2 = 0;
  for(int j = 0; j < 1000; j++) {
  average2 = average2 + (.0264 * analogRead(A2) -13.51);
  delay(1);
  }
  
  RawVCC = analogRead(A1);
  auxVCC = map(RawVCC, 0, 1023, 0, 300);
  VCC = (auxVCC / 10.0);
  
  RawVEE = analogRead(A0);
  auxVEE = map(RawVEE, 0, 1023, 0, 300);
  VEE = (auxVEE / 10.0);
  
    
  ICC = (average1 - offset1) ; // offset adjust
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("VC=");
  lcd.print(VCC,1);
  if (VCC <10){
    lcd.print("  I=");
    }
  if (VCC >= 10){
    lcd.print(" I=");
    }  
  lcd.print(ICC,0);
  lcd.print("mA");
  
  IEE = (average2 - offset2) ; // offset adjust
  lcd.setCursor(0, 1);
  lcd.print("VE=");
  lcd.print(VEE,1);
  if (VEE <10){
    lcd.print("  I=");
    }
  if (VEE >= 10){
    lcd.print(" I=");
    }  
  lcd.print(IEE,0);
  lcd.print("mA");
  
   
    
}



Links

Henrys Bench: ACS712 Current Sensor

Electrodragon: ACS712 Current Sensor

Publicidad