jueves, 8 de febrero de 2024

LILYGO TTGO SIM7000G + TRACCAR

 Guía para conectar el lilygo TTGO SIM7000G a la Plataforma Traccar (plataforma de seguimiento y posición de código abierto para vehículos)


Lilygo SIM7000G

                                                        Traccar Software (Open Source) 

Este proyecto consiste en vincular las populares tarjetas LILYGO SIM7000G a la Plataforma Traccar. El Módem 7000G dispone de comunicación GSM/GPRS NBIOT y LTEM, además de tener un módem GPS integrado, lo que lo convierte en una solución perfecta para desarrollar soluciones que involucren geoposicionamiento en tiempo real. El lenguaje utilizado es ARDUINO y utilizo la biblioteca TINYGSM https://github.com/vshymanskyy/TinyGSM/tree/master Las funcionalidades constan de lo siguiente:


  • Envío de coordenadas geográficas
  • Lectura remota de un Pin digital
  • Escritura remota en un pin digital
  • Frecuencia de envío de datos configurable

*Nota: Las funcionalidades pueden extenderse a diferentes comodidades como lectura de sensores RS485, lectura de canales analógicos, sensores de temperatura, humedad, etc.

👉 Se trata de un ratreador GPS basado en la popular tarjeta Lilygo ttgo SIM7000G. Esta tarjeta trae comunicacione GPRS/LTEM/NBIOT, además de traer un modem gps lo que lo hace muy compacto. Empleo un Simcard de https://lnkd.in/e_vfpSks

lo que facilita la comunicacion en red móvil, ya que estas simcards estan optimizadas para este tipo de aplicaciones.

✅ La tarjeta se enlaza a la plataforma de rastreo vehicular Traccar. Una plataforma open source que tambien es popular, y lo mejor que lo puedes usar en línea.

✅El Objetivo de este proyecto fue mantener el seguimiento de un activo físico que esta en movimiento registrando su posicionamiento en un mapa y descargar la data o reportes en cualquier momento, además de poder enviar comandos desde la plataforma para aperturar o cerrar un actuador, tambien la de leer una entrada digital y conocer su estado.

✅En síntesis les dejo el enlace de mi github donde se encuentra la guía y codigo fuente para implementar, veo mucho pontencial en aplicaciones de seguimiento.


domingo, 4 de septiembre de 2022

Instalar Mosquitto Broker (MQTT) en Wondows 10


 MQTT es el protocolo de comunicación más popular en Internet de las cosas (IoT). Se utiliza para mover datos entre aplicaciones y dispositivos IoT industriales, como sensores, máquinas, PLC y más.MQTT conecta de manera eficiente a los clientes en el borde, en la nube y en infraestructuras híbridas mediante un patrón de comunicación de publicación/suscripción (Pub/Sub) y siempre tiene un intermediario (clúster) en su núcleo.





Archivos de descargar:


https://mega.nz/folder/Og0F0Q7D#GVw4o3hbW5lyV6QoIWXLiw

Robot Minisumo de Competencia

Robot Minisumo de Competencia



Muy Pronto...

sábado, 2 de marzo de 2019

Comparacion de reguladores de Voltaje

Comparacion de reguladores de Voltaje 



  • En esta prueba se uso una fuente de poder con un amperimetro integrado.
  • La prueba se realizo a 12V en la entrada de cada regulador.
  • los reguladores no tenían conectada ninguna carga a la salida, porlo que las mediciones son en estado de reposo.


Estos son los resultados:

I) LM317 :             1mA
II) 7805:                 3mA
III) AMS 1117:      4mA
IV) LM25965:       5mA


jueves, 21 de diciembre de 2017

Robot Minisumo PID




Hace  meses que no escribia un post sobre robots, y que mejor momento para hacerlo en estas vacaciones, asi que ahi vamos roboteros!
Nota: Este post lo estaré editando constantemente sobre la marcha.



La teoría con la cual vamos a partir es las de utilizar un controlador PID (controlador proporcional integral derivativo) para que el robot rastree a su oponente usando las características propias de un controlador PID, bien es sabido que un controlador PID es mas eficiente y mas preciso que un controlador ON/OFF, este ultimo es muy utilizado en las competencias de robots minisumos y sumos en sus algoritmos de detección. Al usar el controlador ON/OFF surgen muchos inconvenientes en el cual he visto que competidores se van topando para programar a sus robots, por ejemplo, que pasa si quiero subir la velocidad de los motores al giro? Pues el robot empezara a oscilar de un lado a otro como si se volviera loco. y en ese trance, pues el robot pierde energía y al estar asi de inestable, pues el contrincante le gana la partida, porque lo detecto mas rapido.
Con un controlador PID operando estos problemas son superados dando una ventaja sobre el oponente ala vez que el robot gasta menos energia.


Materiales:
-Chasis robot Minisumo + cuchillas(con medidas oficiales)
-llantas de goma + Aro de aluminio
-Arduino Nano
-Sensores Sharp 340K
-Driver TB6612FNG
-baterias lipo 500mA
-Motores fingertech 22:1
- resistencias de 1 ohm , 10 kohm, 330ohm, capacitore ceramico de 100nf , capacitor electrolitico 100uf, pulsadores, leds jumpers.

Para este Ejemplo se usan 3 Sensores digitales, Pero también se puede extender a muchos más sensores. Siguiendo la misma idea que es la de ponderar los pesos de los sensores en función del numero. Mientras mas sensores existan, la resolución es mayor, por ende la precisión del PID Aumenta. Si el numero de sensores es mínimo, pues  vuelve a ser como un control ON/OFF. 
Es cierto que las siempre sera necesario calibrar las contantes Integral, derivativa y proporcional que van acordes al sistema físico: Peso, tamaño, centro de gravedad, constante de rozamiento, relación par-motor, velocidad, etc... Modelar un sistema así es complejo... Una alternativa mas razonables es empezar calibrando con ensayo y error hasta paulatinamente ir reduciendo las oscilaciones. Empezar aumentando la constante proporcional, y luego el diferencial... y si es necesario (aunque no seria recomendable para cuando se usen pocos sensores) calibrar la constante integral.

ESQUEMÁTICO:


PID 3 SENSORES y MOTORES Mini MAXON (RUMI)

//Entradas
  #define b_start       18
  #define b_stop        17
  #define boton1        14
  #define boton2        15
  #define boton3        16

  #define sensor_i      4
  #define sensor_c      3
  #define sensor_d      2
  //Salidasr
  #define led1          5
  #define mi1       9
  #define mi2       8
  #define pwmi      11   //~
  #define md1       7
  #define md2       6
  #define pwmd      10   //~
  //variables

////////////////CONFIGURACION DE VARIABLES DE ROBOT MINISUMO RUMI////////////////////
/////////////////////////MOTORES MAXON, 3 SENSORES //////////////////////////////////

/////////////////Delay de seguridad////////////////////////
long delay_salida=5000;    //5 segundos
////////////////////////////////////////////////////////////////////
////////////////Salida  giro tipo "licuadora"///////////////////////
int izq_l_i=-195;    //por default: -195   , caso salida izquierda, motor izquierdo retrocede
int der_l_i=195;    //por defaul: 195    ,caso salida izquierda, motor derecho  avanza
int izq_l_d=195;    //por default: 195   , caso salida derecha, motor izquierdo avanza
int der_l_d=-195;    //por defaul: -195    , caso salida derecha, motor derecho retrocede
/////////////////////////////////////////////////////////////////////
//////////////// Salida giro tipo "coja"/////////////////////////////
int izq_c_i=20;       //por default: 20   , caso salida izquierda, motor izquierdo avanza
int der_c_i=255;        //por default:255     ,caso salida izquierda, motor derecho  avanza
int izq_c_d=255;       //por default: 255   ,caso salida derecha, motor izquierdo avanza
int der_c_d=20;        //por default:20     ,caso salida derecha, motor derecho avanza
long tiempo_c=90000;   //por default:90000  ,tiempo que permanece haciendo coja
int izq_c_i_l=-200;     //default: -200       ,terminado el tiempo giro licuadora, caso salida izquierda, motor izquierdo retrocede
int der_c_i_l=200;     //default: 200       ,terminado el tiempo giro licuadora, caso salida izquierda, motor derecho avanza
int izq_c_d_l=200;     //default: 200       ,terminado el tiempo giro licuadora, caso salida derecha, motor izquierdo avanza
int der_c_d_l=-200;     //default: -200       ,terminado el tiempo giro licuadora, caso salida derecha, motor derecho retrocede
//////////////////////////////////////////////////////////

////////////////Frenos de contorno////////////////////////
int izq_f_i=-120;     ///Default:-120   retorno a la izquierda, motor izquierdo retrocede
int der_f_i=200;      ///Default:200    retorno a la izquierda, motor derecho avanza
int izq_f_d=200;      ///Default:200    retorno a la derecha, motor izquierdo avanza
int der_f_d=-120;     ///Default:-120   retorno a la derecha, motor derecho retrocede
////////////////////Constantes PID////////////////////////
int velocidad=255; //aqui cambias velocidad  0-100        //
float KP=35.78;  //25.78  , 35.78                               //
float KD=110;     //20     ,50                           //
float KI=0;     //       ,0                            //
                          //
////////////////////////////////////////////////////////
 
/////////////Otras Variables auxiliares///////////////////////////////////////
  int _numSensors=3; //cantidad de sensores usados
  int sensors_values[3]; //numero de sensores usados
  int last_value=0;
 
  int btn1=0,btn2=0,btn3=0;
  int s1=0,s2=0,s3=0;
  int posicion;
  int proporcional=0;
  int integral=0;
  int derivativo=0;
  int proporcional_pasado=0;
  int salida_control=0;
  int caso=0;
//////////////////////////////////////////////////////

void setup() {
delay(50);
motores(0,0);
pinMode(boton1,INPUT);
pinMode(boton2,INPUT);
pinMode(boton3,INPUT);
pinMode(boton3,INPUT);
pinMode(b_start,INPUT);
pinMode(b_stop,INPUT);

pinMode(sensor_i,INPUT);
pinMode(sensor_c,INPUT);
pinMode(sensor_d,INPUT);

pinMode(13,OUTPUT);
pinMode(led1,OUTPUT);
pinMode(mi1,OUTPUT);
pinMode(mi2,OUTPUT);
pinMode(pwmi,OUTPUT);
pinMode(md1,OUTPUT);
pinMode(md2,OUTPUT);
pinMode(pwmd,OUTPUT);
digitalWrite(13,HIGH);
Serial.begin(115200);

while(true)
{
  botones();
  if(btn1==1){caso=1;digitalWrite(13,LOW);delay(delay_salida);} //izquierda
  if(btn2==1){caso=2;digitalWrite(13,LOW);delay(2000);}//estrategia
  if(btn3==1){caso=3;digitalWrite(13,LOW);delay(delay_salida);} //derecha
  botones();
  int b_s=digitalRead(b_start);

    if(b_s==1)
     {
      if(caso==1)
      {
         sensores();
         motores(izq_l_i,der_l_i);
         if(s1==1 || s2==1 || s3==1)
         {
            break;
         }
      }

      if(caso==2)
      {
          s1=0,s2=0,s3=0;
          while(true)
          {
             botones();
             if(btn1==1)//izquierda coja
             {
                digitalWrite(13,HIGH);
                delay(delay_salida);
                long k=0;
                motores(izq_c_i,der_c_i);
                while(true)
                {           
                  sensores();
                  k++;
                  if(k==tiempo_c)
                  {
                    digitalWrite(led1,HIGH);
                    motores(izq_c_i_l,der_c_i_l);
                    k=0;
                  }
                  if(s1==1 || s2==1 || s3==1)
                  {
                      break;
                  }
                }
              break;
             }
               if(btn2==1)// defrente con con semicoja a la izquierda
             {
                digitalWrite(13,HIGH);
                delay(delay_salida);
                long k=0;
                motores(140,250);
                while(true)
                {           
                  sensores();
                  k++;
                  if(k==20000)
                  {
                    digitalWrite(led1,HIGH);
                    motores(-180,180);
                    k=0;
                  }
                  if(s1==1 || s2==1 || s3==1)
                  {
                      break;
                  }
                }
              break;
             }
           
             if(btn3==1)//derecha coja
             {
                digitalWrite(13,HIGH);
                delay(delay_salida);
                long k=0;
                motores(izq_c_d,der_c_d);
                while(true)
                {           
                  sensores();
                  k++;
                  if(k==tiempo_c)
                  {
                    digitalWrite(led1,HIGH);
                    motores(izq_c_d_l,der_c_d_l);
                    k=0;
                  }
                  if(s1==1 || s2==1 || s3==1)
                  {
                      break;
                  }
                }
              break;
             } 
          }
          break;
      }
     
   if(caso==3)
   {
      sensores();
      motores(izq_l_d,der_l_d);
      if(s1==1 || s2==1 || s3==1)
      {
         break;
      }
   }
  }
 
  }
}

void loop()
{
 led_run();  //led palpitando
//Serial.println(posicion);  //imprime posicion de robot
 tracking3();                //seguimiento pid robot
 frenos_contorno();          // retorno de robot cuando no se ha sensado
 //delay(1);
 if(s1==1&&s2==1&&s3==1){motores(255,255);}
}
  int l;
void led_run()
{
  l++;
  if(l==15){  digitalWrite(led1,!digitalRead(led1));l=0;}
 
}

void frenos_contorno()
{
  if(posicion>=20)
  {
    motores(izq_f_i,der_f_i);
    while(true)
    {
          sensores();
          if(s1==1 || s2==1 || s3==1) break;
    }

  }
 
  if(posicion<=0)
  {
    motores(izq_f_d,der_f_d);
    while(true)
    {
          sensores();
          if(s1==1 || s2==1 || s3==1) break;
    }

  }
 
}
void test()
{
  digitalWrite(led1,!digitalRead(led1));
  botones();
  sensores();
  Serial.print(btn1);
  Serial.print(" ");
  Serial.print(btn2);
  Serial.print(" ");
  Serial.print(s1);
  Serial.print(" ");
  Serial.print(s2);
  Serial.print(" ");
  Serial.print(s3);
  Serial.println(" ");
  delay(100);
}

void motores(int motor_izq, int motor_der){                                     
  if(motor_izq >= 0)
  {
    digitalWrite(mi1,LOW);  digitalWrite(mi2,HIGH); analogWrite(pwmi,motor_izq);
  }
  else
  {
    digitalWrite(mi1,HIGH);  digitalWrite(mi2,LOW); motor_izq = motor_izq*(-1);  analogWrite(pwmi,motor_izq);
  }
  if ( motor_der >= 0 ) //motor derecho
  {
    digitalWrite(md1,LOW);  digitalWrite(md2,HIGH); analogWrite(pwmd,motor_der);
  }
  else
  {
    digitalWrite(md1,HIGH); digitalWrite(md2,LOW); motor_der= motor_der*(-1); analogWrite(pwmd,motor_der);
  }
}
void botones()
{
  btn1=digitalRead(boton1);
  btn2=digitalRead(boton2);
  btn3=digitalRead(boton3);
}

void sensores()
{
  s3=!digitalRead(sensor_i);
  s2=!digitalRead(sensor_c);
  s1=!digitalRead(sensor_d);   
}


void tracking()
{
  posicion=ponderacion();
  proporcional=(posicion) - 10;
  integral=integral+proporcional_pasado;
  derivativo=(proporcional-proporcional_pasado);
  int ITerm=integral*KI;
  if(ITerm>=250)ITerm=250;
  if(ITerm<=-250)ITerm=-250;
 
  salida_control=(proporcional*KP)+(derivativo*KD)+ITerm;
 
  if(salida_control>velocidad) salida_control=velocidad;
  if(salida_control<-velocidad) salida_control=-velocidad;

  proporcional_pasado=proporcional;
                     
  if(salida_control<0)//si se salio por la izquierda
  {
    motores(-salida_control,salida_control);
  }
  if(salida_control>0)//si se salio por la derecha
  {
     motores(-salida_control,salida_control);
  }
  if(salida_control==0) //si esta en punto de consigna
  {
  proporcional=(posicion) - 10;
    motores(100,100);
  }
 // Serial.println(salida_control);
}


void tracking2()
{
  posicion=ponderacion();
  integral=integral+proporcional_pasado;
  derivativo=(proporcional-proporcional_pasado);
  int ITerm=integral*KI;
  if(ITerm>=100)ITerm=100;
  if(ITerm<=-100)ITerm=-100;
 
  salida_control=(proporcional*KP)+(derivativo*KD)+ITerm;
 
  if(salida_control>velocidad) salida_control=velocidad;
  if(salida_control<-velocidad) salida_control=-velocidad;

  proporcional_pasado=proporcional;
                     
  if(salida_control<0)//si se salio por la izquierda
  {
    motores(-salida_control,0);
  }
  if(salida_control>0)//si se salio por la derecha
  {
     motores(0,salida_control);
  }
  Serial.println(salida_control);
}


void tracking3() // envestida
{
  posicion=ponderacion();
  proporcional=(posicion) - 10;
  integral=integral+proporcional_pasado;
  derivativo=(proporcional-proporcional_pasado);
  int ITerm=integral*KI;
  if(ITerm>=250)ITerm=250;
  if(ITerm<=-250)ITerm=-250;
 
  salida_control=(proporcional*KP)+(derivativo*KD)+ITerm;
 
  if(salida_control>velocidad) salida_control=velocidad;
  if(salida_control<-velocidad) salida_control=-velocidad;

                     
  if(salida_control<0)//si se salio por la izquierda
  {
 
    motores(velocidad,velocidad+salida_control);
  }
  if(salida_control>0)//si se salio por la derecha
  {
     motores(velocidad-salida_control , velocidad);
  }
   if(salida_control==0)//si se salio por la derecha
  {
     motores(velocidad , velocidad);
  }
 // Serial.println(salida_control);
proporcional_pasado=proporcional;
 
}

int ponderacion()
{
  int i=0;
  long avg=0;
  long sum=0;
  int on_line=0;
  sensores();
  sensors_values[0]=s1;sensors_values[1]=s2;sensors_values[1]=s2;sensors_values[2]=s3;
  // for(int i=0;i<=3;i++){Serial.print(sensors_values[i]);}
  //Serial.println("");
  for(i=0;i<_numSensors;i++)
  {
    int value=sensors_values[i];
    if(value>0)
    {
      on_line=1;
    }
    avg+=(long)(value)*(i*10);
    sum+=value;
  }
  if(!on_line)
  {
    if(last_value<1)
    { 
      return 0;
    }
   else
    {
      return(_numSensors-1)*10;
    }
  }
  last_value = avg/sum;
  return last_value;
}


Aquí pueden observar una deliciosa demostracion de este enfoque de robot sumo PID





lunes, 5 de diciembre de 2016

Driver Drv8833 y arduino (tutorial)

Driver drv8833 y arduino

 (tutorial)








#include <QTRSensors.h>
/////////////////////////////////////////////////////////////////////////////////////
//*************  Programa realizado por MARCO A. CABALLERO MORENO***************   //
// Solo para fines educativos   
// robot velocista mini FK BOT  V 2.0                                            //
// micro motores pololu MP 10:1, sensores qtr 8rc, driver drv8833, arduino nano    //
//                                     05/12/2014                  
// ACTUALIZADO 29/3/2015            
/////////////////////////////////////////////////////////////////////////////////////

#define NUM_SENSORS   8     //numero de sensores usados
#define TIMEOUT       2000  // tiempo de espera para dar resultado en uS
#define EMITTER_PIN   6     //pin led on
///////////////pines arduino a utilizar/////////////////////
#define led1          13 
#define led2          4  
#define mot_i         7
#define mot_d         8
#define sensores      6
#define boton_1       2  //pin para boton
#define pin_pwm_i     9
#define pin_pwm_d     10

QTRSensorsRC qtrrc((unsigned char[]) {19, 18, 17, 16,15,14,11,12}
,NUM_SENSORS, TIMEOUT, EMITTER_PIN);

//variables para almacenar valores de sensores y posicion
unsigned int sensorValues[NUM_SENSORS];
unsigned int position=0;

/// variables para el pid
int  derivativo=0, proporcional=0, integral=0; //parametros
int  salida_pwm=0, proporcional_pasado=0;

///////////////AQUI CAMBIEREMOS LOS PARAMETROS DE NUESTRO ROBOT!!!!!!!!!!!!!!!
int velocidad=120;              //variable para la velocidad, el maximo es 255
float Kp=0.18, Kd=4, Ki=0.001;  //constantes
//variable para escoger el tipo de linea
int linea=0;                    //  0 para lineas negra, 1 para lineas blancas

void setup()
{
 delay(800);
 pinMode(mot_i, OUTPUT);//pin de direccion motor izquierdo
 pinMode(mot_d, OUTPUT);//pin de direccion motor derecho
 pinMode(led1, OUTPUT); //led1
 pinMode(led2, OUTPUT); //led2
 pinMode(boton_1, INPUT); //boton 1 como pull up
        
 for (int i = 0; i <40; i++)  //calibracion durante 2.5 segundos,
 {                                 //para calibrar es necesario colocar los sensores sobre la superficie negra y luego 
  digitalWrite(led1, HIGH);  //la blanca
  delay(20);
  qtrrc.calibrate();    //funcion para calibrar sensores   
  digitalWrite(led1, LOW);  
  delay(20);
 }
digitalWrite(led1, LOW); //apagar sensores para indicar fin de calibracion 
delay(400); 
digitalWrite(led2,HIGH); //encender led 2 para indicar la
while(true)
{
    int x=digitalRead(boton_1); //leemos y guardamos el valor
                                      // del boton en variable x
    delay(100);
    if(x==0) //si se presiona boton 
    {
        digitalWrite(led2,LOW); //indicamos que se presiono boton
        digitalWrite(led1,HIGH); //encendiendo led 1
        delay(100);
        break; //saltamos hacia el bucle principal
    }
}
}       


void loop()
{

 //pid(0, 120, 0.18, 0.001, 4 );
  pid(linea,velocidad,Kp,Ki,Kd); //funcion para algoritmo pid 
                                 //primer parametro: 0 para lineas negras, tipo 1 para lineas blancas
                                 //segundo parametro: velocidad pwm de 0 a 255
                                 //tercer parametro: constante para accion proporcional
                                 //cuarto parametro: constante para accion integral
                                 //quinto parametro: constante para accion derivativa
  //frenos_contorno(0,700);
  frenos_contorno(linea,700); //funcion para frenado en curvas tipo 
                              //primer parametro :0 para lineas negras, tipo 1 para lineas blancas
                              //segundo parametro:flanco de comparación va desde 0 hasta 1000 , esto para ver 
}

////////funciones para el control del robot////
 void pid(int linea, int velocidad, float Kp, float Ki, float Kd)
{
  position = qtrrc.readLine(sensorValues, QTR_EMITTERS_ON, linea); //0 para linea negra, 1 para linea blanca
  proporcional = (position) - 3500; // set point es 3500, asi obtenemos el error
  integral=integral + proporcional_pasado; //obteniendo integral
  derivativo = (proporcional - proporcional_pasado); //obteniedo el derivativo
  if (integral>1000) integral=1000; //limitamos la integral para no causar problemas
  if (integral<-1000) integral=-1000;
  salida_pwm =( proporcional * Kp ) + ( derivativo * Kd )+(integral*Ki);
  
  if (  salida_pwm > velocidad )  salida_pwm = velocidad; //limitamos la salida de pwm
  if ( salida_pwm < -velocidad )  salida_pwm = -velocidad;
  
  if (salida_pwm < 0)
 {
  motores(velocidad+salida_pwm, velocidad);
 }
 if (salida_pwm >0)
 {
  motores(velocidad, velocidad-salida_pwm);
 }

 proporcional_pasado = proporcional;  
}

//funcion para control de motores
void motores(int motor_izq, int motor_der)
{
  if ( motor_izq >= 0 )  //motor izquierdo
 {
  digitalWrite(mot_i,HIGH); // con high avanza
  analogWrite(pin_pwm_i,255-motor_izq); //se controla de manera
                                        //inversa para mayor control
 }
 else
 {
  digitalWrite(mot_i,LOW); //con low retrocede
  motor_izq = motor_izq*(-1); //cambio de signo
  analogWrite(pin_pwm_i,motor_izq); 
 }

  if ( motor_der >= 0 ) //motor derecho
 {
  digitalWrite(mot_d,HIGH);
  analogWrite(pin_pwm_d,255-motor_der);
 }
 else
 {
  digitalWrite(mot_d,LOW);
  motor_der= motor_der*(-1);
  analogWrite(pin_pwm_d,motor_der);
 }

  
}

void frenos_contorno(int tipo,int flanco_comparacion)
{
  
if(tipo==0)
{
  if(position<=50) //si se salio por la parte derecha de la linea
 {
  motores(-80,90); //debido a la inercia, el motor 
                                  //tendera a seguri girando
                                  //por eso le damos para atras , para que frene
                                 // lo mas rapido posible 
  while(true)  
  {
   qtrrc.read(sensorValues); //lectura en bruto de sensor   
   if( sensorValues[0]>flanco_comparacion || sensorValues[1]>flanco_comparacion ) 
   //asegurar que esta en linea
   {
    break;
   } 
  }
 }

 if (position>=6550) //si se salio por la parte izquierda de la linea
 { 
  motores(90,-80);
  while(true)
  {
   qtrrc.read(sensorValues);
   if(sensorValues[7]>flanco_comparacion || sensorValues[6]>flanco_comparacion )
   {
    break;
   }  
  }
 }
}

if(tipo==1) //para linea blanca con fondo negro
{
 if(position<=50) //si se salio por la parte derecha de la linea
 {
  motores(-80,90); //debido a la inercia el motor 
                   //tendera a seguri girando
                   //por eso le damos para atras  
                   //para que frene lo mas rapido posible 
  while(true)  
  {
   qtrrc.read(sensorValues); //lectura en bruto de sensor
   if(sensorValues[0]<flanco_comparacion || sensorValues[1]<flanco_comparacion )   //asegurar que esta en linea
   {
    break;
   }
  }
 }

 if(position>=6550) //si se salio por la parte izquierda de la linea
 { 
  motores(90,-80);
  while(true)
  {
   qtrrc.read(sensorValues);
   if(sensorValues[7]<flanco_comparacion || sensorValues[6]<flanco_comparacion)
   {
    break;
   }  
  }
 }
}
}

miércoles, 30 de noviembre de 2016

Robot Velocista QTR8A (Parte III - Programacion del Robot)

Programación del Robot


Algoritmo PID

Este sera el encargado de regular el comportamienito del robot y corregir su marcha en el recorrido de la pista, recibe datos entrada (sensores) , las procesa, (PID) y envia la señal de correccion hacia los motores (salida de control) y nuevamente repite el proceso coparando la salida con la entrada (retroalimentacion) sin entrar en mas teoría se puede resumir de manera esquematica este controlador
  • Entrada de mando: Vendría a ser el punto de referencia en donde queremos fijar al robot "Set point", nuestro objetivo es que el robot no se salga de la linea, por lo tanto lo deseado es que siempre se mantenga centrado en el medio, como se vio anteriormente el centro de los sensores arrojaba un valor de posición relativa de 3500, este sera nuestra referencia o "set point" (donde queremos que el robot se mantenga siempre.
  • Controlador :  En este caso el controlador es el encargado de corregir y mantener en marcha al robot, su objetivo es que no se salga del punto de referencia o que almenos logre tenerlo dentro de los rangos permitidos. lo ideal es que mantenga al robot fijado en el centro, pero en la realidad ocurrirá que el mundo externo provoque muchas  perturbaciones haciendo que el robot oscile o se salga del punto de referencia por lo que tendrá que corregir continuamente la marcha. Si este controlador es el "PID"... Que para nuestro caso sera un algoritmo programado en arduino.
  • Planta: La planta esta relacionada con las condiciones físicas del robot, peso, longitud, traccion de los motores, velocidad, rozamiento, inercia, etc.  Como se ve el diagrama de bloques, el controlador modifica el comportamiento de la planta, osea el comportamiento del robot.
  • Salida o señal de control: Es la respuesta producida por el control aplicado en el robot, en este caso la salida  de control se envia al driver de motor y luego a los motores para que puedan corregir la marcha constantemente. la medición de esta salida es jutamente la señal es la posicion actual del robot medido .
  • Realimentacion: Esta compuesta de la adquisición de datos, osea la de los sensores del robot, que va leer la posición relativa actual del robot la procesa y manda nuevamente a comparararse con la referencia que es el "set point"  , esta comparación traerá un resultado llamado error que nuevamente es entregado al controlador para que pueda procesarla y enviar una señal de correccion, la realimentacion es la comparación de la salida con respecto a la entrada, 
Todo esto en gran parte sera el algoritmo de control del robot: Se que es muy abstracto todo lo que concierne con PID, pero con la practica algunos de estos conceptos estaran claros.

En este post ya tramos acerca de cada una de las acciones del PID,  de las constantes y el procedimiento para sintonizar, por lo que ya no seré tan redundante explicando nuevamente. : http://aprendiendofacilelectronica.blogspot.pe/2014/12/robot-velocista-de-competencia_4.html


Circuito del Robot Velocista


Programa Completo

/////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////

#include <QTRSensors.h>

  //entradas
#define btn1      0
#define btn2      1
  //salidas
#define led1      13

#define led_on    9   //~
#define mi1       3
#define mi2       4
#define pwmi      6   //~
#define md1       8
#define md2       7
#define pwmd      5   //~
  

#define NUM_SENSORS             8  // number of sensors used
#define NUM_SAMPLES_PER_SENSOR  1 // average 4 analog samples per sensor reading
#define EMITTER_PIN             9   // emitter is controlled by digital pin 2

QTRSensorsAnalog qtra((unsigned char[]) {7, 6, 5, 4, 3, 2,1,0},NUM_SENSORS, NUM_SAMPLES_PER_SENSOR, EMITTER_PIN);
unsigned int sensorValues[NUM_SENSORS];
int proporcional=0;
int derivativo=0;
int integral=0;
int salida_pwm=0;
int proporcional_pasado=0;
int position=0;

////////////////////Parametros PID/////////////////////////////////
int velocidad=120;
//float KP=0.15, KD=2.2, KI=0.006; //reaccion rapida
float KP=0.01, KD=0.15 , KI=0.0001; //reaccion rapida
///////////////////////////////////////////////////////

/////////////////parametros de sensado/////////////////////////////
int linea=0; //0 linea negra, 1 para linea blanca
int flanco_color=  0 ;
int en_linea=  500 ;
int ruido= 30;
/////////////////////////////////////////////////////////
int boton1=7;
int boton2=7;

void setup()
{
    pinMode(led1,OUTPUT);
    pinMode(led_on,OUTPUT);
    pinMode(mi1,OUTPUT);
    pinMode(mi2,OUTPUT);
    pinMode(pwmi,OUTPUT);
    pinMode(md1,OUTPUT);
    pinMode(md2,OUTPUT);
    pinMode(pwmd,OUTPUT);

digitalWrite(led1,HIGH);
delay(200);
digitalWrite(led1,LOW);
delay(200);

digitalWrite(led1, HIGH);    // turn on Arduino's LED to indicate we are in calibration mode
  for (int i = 0; i < 200; i++)  // make the calibration take about 10 seconds
  {
    qtra.calibrate();       // reads all sensors 10 times at 2.5 ms per six sensors (i.e. ~25 ms per call)
  }
  digitalWrite(led1, LOW);     // turn off Arduino's LED to indicate we are through with calibration
 //Serial.begin(115200);
   //Serial.println();

   while(true)
   {
      botones();
      if(boton2==0) 
      {
        delay(20);
        digitalWrite(led1,HIGH);
        delay(100);
        digitalWrite(led1,LOW);
        delay(100);
        break;
      }
   }
  
Serial.begin(115200);
//bt.println("Hello, world?");

}

void loop()
{
  pid(1,velocidad,KP,KI,KD);
  frenos_contorno(600);

 Serial.println(position);
 delay(2);
}

void pid(int linea, int velocidad, float Kp, float Ki, float Kd)
{
   
   position = qtra.readLine(sensorValues,QTR_EMITTERS_ON, linea, flanco_color, en_linea, ruido);
  //0 linea negra, 1 para linea blanca
  
      //  Serial.println(position);
  proporcional = (position) - 3500; // set point es 3500, asi obtenemos el error
  integral=integral + proporcional_pasado; //obteniendo integral
  derivativo = (proporcional - proporcional_pasado); //obteniedo el derivativo
  int ITerm=integral*KI;
  if(ITerm>=255) ITerm=255;
  if(ITerm<=-255) ITerm=-255;
  
  salida_pwm =( proporcional * KP ) + ( derivativo * KD )+(ITerm);
  
  if (  salida_pwm >velocidad )  salida_pwm = velocidad; //limitamos la salida de pwm
  if ( salida_pwm  <-velocidad )  salida_pwm = -velocidad;
  
  if (salida_pwm < 0)
 {
    int der=velocidad-salida_pwm; //(+)
    int izq=velocidad+salida_pwm;  //(-)
    if(der>=255)der=255;
    if(izq<=0)izq=0;
    motores(izq, der);
 }
 if (salida_pwm >0)
 {
  int der=velocidad-salida_pwm; //(-)
  int izq=velocidad+salida_pwm; //(+)
  
  if(izq >= 255) izq=255;
  if(der <= 0) der=0;
  motores(izq ,der );
 }

 proporcional_pasado = proporcional;  
}


void frenos_contorno(int flanco_comparacion)
{
    if (position <=10) //si se salio por la parte derecha de la linea
    {
      while(true)
      { 
        digitalWrite(led1,HIGH);
        motores(-125,60);
        qtra.read(sensorValues); //lectura en bruto de sensor
        if ( sensorValues[0]<flanco_comparacion || sensorValues[1]<flanco_comparacion || sensorValues[2]<flanco_comparacion || sensorValues[3]<flanco_comparacion || sensorValues[4]<flanco_comparacion || sensorValues[5]<flanco_comparacion || sensorValues[6]<flanco_comparacion || sensorValues[7]<flanco_comparacion)
        {
          break;
        }
        
      }
    }

    if (position>=6990) //si se salio por la parte izquierda de la linea
    {
      while(true)
      {
        digitalWrite(led1,HIGH);
        motores(60,-125); 
        qtra.read(sensorValues);
        if (sensorValues[7]<flanco_comparacion || sensorValues[6]<flanco_comparacion|| sensorValues[5]<flanco_comparacion || sensorValues[4]<flanco_comparacion || sensorValues[3]<flanco_comparacion || sensorValues[2]<flanco_comparacion || sensorValues[1]<flanco_comparacion|| sensorValues[0]<flanco_comparacion)
        {
          break;
        }
      }
  }
  digitalWrite(led1,LOW);
}


void motores(int motor_izq, int motor_der)
{
  if ( motor_izq >= 0 )  
  {
    digitalWrite(mi1,LOW);
    digitalWrite(mi2,HIGH); 
    analogWrite(pwmi,motor_izq); 
  }
  else
  {
    digitalWrite(mi1,HIGH); 
    digitalWrite(mi2,LOW);
    motor_izq = motor_izq*(-1); 
    analogWrite(pwmi,motor_izq);
  }

  if ( motor_der >= 0 ) //motor derecho
  {
    digitalWrite(md1,LOW);
    digitalWrite(md2,HIGH);
    analogWrite(pwmd,motor_der);
  }
  else
  {
    digitalWrite(md1,HIGH);
    digitalWrite(md2,LOW);
    motor_der= motor_der*(-1);
    analogWrite(pwmd,motor_der);
  }
}

void botones()
{
    boton1=digitalRead(btn2);
    boton2=digitalRead(btn1); ///boton izquierdo, derecho
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Nota: este programa esta utilizando la libreria modificada de este post Modificacion de libreria QTR, si estas usando la libreria sin modificar, que de hecho no funcionara con este codigo tendrás que descargarlo desde este link: https://mega.nz/#!CkMkiZhA!FMK4eJQVmOGZK9GZzfqSKRgEPOijTSkMmbNDUwbf5C0 en instalarlo nuevamente. 

Instalacion de Libreria QTR SENSORS:


Esquematicos de FK-BOT:

Ya que me estuvieron pidiendo esquemáticos por mucho tiempo, pues aqui las libero.
 He pasado muy buenos días diseñando este robot, que fue considerado en su momento como el más rapido, ya ha pasado los años y cumplio su mision ...

La mejor forma de agradecerme es que le des clic a los anuncios de la parte superior del blog (cosa que no te costara nada hacerlo) , asi me ayudaras mucho! Saludos amigos robotero!!!  😊😎🙌



Cifrado: !tBRwDXi3MO-D9U3xMqgBTw

Driver Sparkfun-Compatible(rojo): https://mega.nz/#F!Ok1jULzb!DFAwhpyvyMLxdrc3C_xedw
Cifrado: !DFAwhpyvyMLxdrc3C_xedw


PRUEBAS FINALES: 





Post Anterior  << Manejando sensores QTR8A y Driver

martes, 29 de noviembre de 2016

Robot Velocista QTR8A (Parte II - Manejando Sensores y Motores)

 Manejando Sensores QTR8A


1. Manejando Sensor QTR8A con la libreria

Uso de librería Qtr8a en Arduino:


  • https://www.pololu.com/product/960/resources (mayor información)
  • Descargar la librería desde aquí : https://mega.nz/#F!78FVmD7Q!auGJgTr0Muo9qkNtl9CuLA
  • Una vez descargado instalar la librería de modo convencional en arduino: Copiar y pegar en la carpeta “librerías” de la carpeta donde esta instalado arduino.
  • Generalmente en esta dirección esta instalada C:\Program Files (x86)\Arduino\libraries
Descargar, descomprimir y copiar .

Ubicar la dirección donde se instalo arduino y buscar la carpeta libraries, y pergar la libreria QTRSensors.


La conexión sera la siguiente: 



  • La librería contiene un ejemplo básico de uso de los sensores
  • “QTRAExample”, abrirla y experimentar…


Configurando pines para uso de sensores Qtr8a :

Como estamos usando la regleta que trae 8 sensores, entonces debemos configurarlo para usar los 8 sensores, ya que por defecto esta configurado para usar 6, en esta imagen se muestra como configurarlo correctamente de acuerdo a las conexiones que se tienen en arduino de la imagen previa.


El código completo :
/////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <QTRSensors.h>

#define NUM_SENSORS             8  // number of sensors used
#define NUM_SAMPLES_PER_SENSOR  4  // average 4 analog samples per sensor reading
#define EMITTER_PIN             9  // emitter is controlled by digital pin 2

// sensors 0 through 5 are connected to analog inputs 0 through 5, respectively
QTRSensorsAnalog qtra((unsigned char[]) {7, 6, 5, 4, 3, 2, 1, 0}, 
  NUM_SENSORS, NUM_SAMPLES_PER_SENSOR, EMITTER_PIN);
unsigned int sensorValues[NUM_SENSORS];


void setup()
{
  delay(500);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);    // turn on Arduino's LED to indicate we are in calibration mode
  for (int i = 0; i < 400; i++)  // make the calibration take about 10 seconds
  {
    qtra.calibrate();       // reads all sensors 10 times at 2.5 ms per six sensors (i.e. ~25 ms per call)
  }
  digitalWrite(13, LOW);     // turn off Arduino's LED to indicate we are through with calibration

  // print the calibration minimum values measured when emitters were on
  Serial.begin(9600);
  for (int i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(qtra.calibratedMinimumOn[i]);
    Serial.print(' ');
  }
  Serial.println();
  
  // print the calibration maximum values measured when emitters were on
  for (int i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(qtra.calibratedMaximumOn[i]);
    Serial.print(' ');
  }
  Serial.println();
  Serial.println();
  delay(1000);
}


void loop()
{
  unsigned int position = qtra.readLine(sensorValues);
  
  // print the sensor values as numbers from 0 to 1000, where 0 means maximum reflectance and
  // 1000 means minimum reflectance, followed by the line position
  for (unsigned char i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(sensorValues[i]);
    Serial.print('\t');
  }
  //Serial.println(); // uncomment this line if you are using raw values
  Serial.println(position); // comment this line out if you are using raw values
  
  delay(50);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



Calibración

  • Previamente, para poder utilizar los sensores es necesario hacer una rutina de calibración, esto  durante algunos segundos. esto hace que la librería procese los datos de sensado, y muestre valores correctos.
  • En el proceso de calibración es necesario pasar repetidas veces los sensores sobre la línea negra y luego sobre la superficie blanca si levantar los sensores.
  • Se recomienda hacer la calibración de manera a una distancia constante sobre la superficie.
Lo que hace este código ejemplo es hacer uso de la librería QTRSensors ,se  obtienen los datos  de los sensores, que son las 8 primeras columnas. La 9na columna son los datos de posición relativa del sensor que vas desde 0 hasta 7000, en donde el centro se encuentra en 3500 a este valor le llamaremos set point. Este valore nos sera util para utilizar el algoritmo PID que controlara al Robot. Ademas se puede notar que cuando los sensores estan posicionados en la linea negra, los valores de sensado unitario incrementan alrededor de 800 a 1000 y cuando están sobre superficie blanca los valores son 0. Para visualizar estos datos se tiene que Abrir el monitor serie de Arduino.

 funciones de la librería Qtr8a

  • qtra.calibrate();  
                   Primera función a ser llamada, antes de usar los sensores, hace calibración de sensores                       (debe usarse un tiempo adecuado)
  • qtra.read(sensorValues);
                    Hace lectura de cada sensor y los guarda en matriz “sensorValues[ ];”
                    Rango de lectura de cada sensor : 0 a 1000.
  • int position = qtra.readLine(sensorValues);
                     Esta función devolverá la posición de sensores (necesario  PID)


2. Manejando Motores 

La conexión es la siguiente:

Ya hice un post para manejar este tipo de driver con arduino pueden verlo aca:  http://aprendiendofacilelectronica.blogspot.pe/2016/11/control-de-motores-dc-con-modulo-driver.html

Simplemente lo que haremos aca es utilizar otros pines con arduino  definiendolos nuevamente y listo, el programa de control de motores para el velocista  esta aqui:

///////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define mi1        3
#define mi2        4
#define pwmi       6
#define md1        8
#define md2        7
#define pwmd       5

void setup() 
{
  pinMode(mi1,OUTPUT);
  pinMode(mi2,OUTPUT);
  pinMode(md1,OUTPUT);
  pinMode(md2,OUTPUT);
}

void loop()
{
  motores(100,100);
}

void motores(int motor_izq, int motor_der)
{
  if( motor_izq >=0)
    {
      digitalWrite (mi1,HIGH);
      digitalWrite (mi2,LOW);
      analogWrite (pwmi,motor_izq);
    }
  else
    {
      digitalWrite(mi1,LOW);
      digitalWrite(mi2,HIGH);
      motor_izq = motor_izq*(-1);
      analogWrite(pwmi,motor_izq); 
    }
  if(motor_der>=0)
    {
      digitalWrite(md1,HIGH);
      digitalWrite(md2,LOW);
      analogWrite(pwmd,motor_der);
  }
  else
     {
      digitalWrite(md1,LOW);
      digitalWrite(md2,HIGH);
      motor_der=motor_der*(-1);
      analogWrite(pwmd,motor_der);    
     }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////









Anterior post << Materiales
Siguiente post >> Programacion PID Robot

martes, 15 de noviembre de 2016

Sensor GP2Y0D340K y Arduino

Sensor GP2Y0D340K y Arduino

El sensor GP2Y0D340K o mas conocido como Sharp340k es un sensor de distancia IRED, que posee un procesador de señal integrado, lo cual facilita enormemente ya que a su salida dara un valor digital "0" o "LOW" si hay un obstáculo y "1" o "HIGH" si no encuentra obstáculo alguno. Su pequeño tamaño lo hace ideal para aplicaciones como detección de obstáculos, sensor de proximidad, y porsupuesto para aplicaciones de robotica, como los robots minisumos.
Estas son algunas de sus características a destacar:


  • Salida de tipo digital.
  • Distancia máxima de detección 40.00 cm.
  • Consumo tipico de 31 mA.
  • Velocidad de respuesta de 8 ms.
  • Tamaño  de 15 x 9.6 x 8.7 mm.
  • Voltaje de funcionamiento de 4.5 a 5.5V.
Esquema en Bloques:


Modo de Conexión:









Código Ejemplo:

Este ejemplo hace una lectura del pin donde esta el sensor y si detecta algo, imprimirá en pantalla y a la vez encenderá el led del pin 13.


#define sensor 9  // lectura en pin D9 
#define led    13 // D13

int lectura;
void setup() {
  pinMode(sensor, INPUT);
  pinMode(led,OUTPUT);
  Serial.begin(9600);
}
void loop() {
  lectura=digitalRead(sensor);
  if(lectura==0)
  {
    digitalWrite(led,HIGH);
    Serial.println("Obstaculo");
  }
  else{
    digitalWrite(led,LOW);
    Serial.println("No obstaculo");
  }




viernes, 4 de noviembre de 2016

Driver TB6612fNG y ARDUINO (Control de Motores DC + programa)

  Driver TB6612fNG y  ARDUINO

 (Pololu, Sparkfun Breakout)



El Modulo driver Tb6612fng cuenta con las siguientes características:

  • Puente H doble de tecnología LD MOS (2 canales para manejar 2 motores DC)
  • Voltaje máximo de entrada de hasta 15V.
  • Corriente de trabajo tipico de 1.2 A por canal y 3A pico por un lapso de 10 milisegundos
  • 2 entradas para PWM con una frecuencia máxima de hasta 100KHz
Estas características ademas de ser muy pequeño (2.0x2.0 cm como máximo ) y de ser altamente eficiente a comparación  al modulo L298N que esta basado en tecnologia bjt (no muy eficiente por lo que las baterías se agotan demasiado rapido), lo hacen un modulo driver muy versatil para distintos proyectos en donde se tenga hacer uso de motores DC, y en especial en robotica donde se le puede sacar bastante provecho usandolos con micromotores Pololu.

En este apartado explicare a como usarlos correctamente y conectarlos a la placa Arduino en donde describire  un codigo  que es altamente eficiente en el control de los motores (velocidad y dirección): Pero antes de ello tenemos que saber que en el mercado existen varios fabricantes de estos módulos usando el chip TB6612FNG y que sus patillajes no son necesariamente los mismos, por el contrario tienen diferente dispocicion de pines, pero el funcionamiento sigue siendo el mismo. Debemos verificar cual es el que vamos a usar, a continuación explico algunas características de estos:

TB6612FNG Pololu


Este modulo es fabricado por Pololu, cuenta con un transistor mosfet que evita que al conectar de manera inversa no se queme o que cuando reciba una corriente inversa  que puede ser muy perjudicial no lo dañe permanentemente. También cuenta con algunos condensadores filtros que atenúan el ruido producido por los motores DC. Tienen un tamaño de 1.5 x2.0 cm. 
Estos Módulos son generalmente un poco mas costosos que los que fabrica Sparkfun o compatibles. se conecta de esta Forma:


TB6612FNG Sparkfun Breakout y compatibles chinos

Estos módulos son fabricados por sparkfun y también por varios fabricantes chinos, No cuenta con un circuito proteccion de corriente inversa, por lo que se debe tener cuidado al conectar las polaridades de la batería de forma correcta (es recomendado poner un diodo en la alimentacion). Cuenta con  capacitores filtros que atenúan el ruido eléctrico producido por los motores.
Son mucho mas baratos  a comparación de los módulos de Pololu, varios fabricantes chinos lo comercializan a muy bajo costo por lo que si se te quema no te perjudicara económicamente. Tienen una medida de 2 . 0 x 2.0 cm. La forma de conectarlo correctamente es la Siguiente:


Código en Arduino Para manejar motores DC:

Este código Funciona de la siguiente manera: 
  • Podemos controlar velocidad y dirección de cada motor independiente del otro para esto creamos una función que recibe 2 parámetros numéricos el primero es para el motor izquierdo el segundo para el motor derecho : " void   motores(int izq , int der) "
  • Para controlar la velocidad solo basta variar el valor de los parámetros desde 0 a 255, que justamente es el pwm del arduino. Ejemplo motores(150,150);
  • Si queremos que gire en sentido inverso  los motores, pues simplemente colocamos un valor negativo desde -1 hasta -255,  la función se encargara de dar la dirección y velocidad. Ejemplo: motores(-150,-150);
  • Si queremos parar pues damos motores(0,0); 

//Se definen los pines a usar del arduino

#define pwm_i 9 //~
#define izq_1 4
#define izq_2 5

#define pwm_d 10 //~
#define der_1 6
#define der_2 7

void setup() {
  delay(1000);
pinMode(izq_1,OUTPUT);
pinMode(izq_2,OUTPUT);
pinMode(der_1,OUTPUT);
pinMode(der_2,OUTPUT);
}

void loop() {
  motores(150,150);
}

void motores(int izq, int der)
{
  if(izq>=0)
  {
    digitalWrite(izq_1,HIGH);
    digitalWrite(izq_2,LOW);
    analogWrite(pwm_i,izq);
  }
  if(izq<0)
  {
    digitalWrite(izq_1,LOW);
    digitalWrite(izq_2,HIGH);
    izq=izq*-1;
    analogWrite(pwm_i,izq);
  }

  if(der>=0)
  {
    digitalWrite(der_1,HIGH);
    digitalWrite(der_2,LOW);
    analogWrite(pwm_d,der);
  }
  if(der<0)
  {
    digitalWrite(der_1,LOW);
    digitalWrite(der_2,HIGH);
    der=der*-1;
    analogWrite(pwm_d,der);
  }
}