Coche radio control + ARDUINO. VirtualWire y ServoTimer2

Hola a todos/as,

Cuando tiene uno un proyecto en la cabeza, se pone a hacerlo y a veces no espera determinados inconvenientes. Para mí ha sido una sorpresa que las bibliotecas VirtualWire y Servo no puedan trabajar juntas, ya que al parecer usa los mismos temporizadores internos del chip ATmega328. Para el proyecto que tengo en mente, un coche por radiocontrol, necesito ambas bibliotecas: una para manejar la parte de comunicación inalámbrica y la otra la dirección.

http://forums.adafruit.com/viewtopic.php?f=31&t=16297

Tras algunas pruebas con VirtualWire conseguí un programa que enviase varios datos. En concreto dos rangos de números de 0 a 1023 (uno potencia, y otro giro) y dos bits que dirán al motor si tiene que dar marcha atrás y si se le encienden las luces. Si le pongo intermitentes puedo detectarlo desde los números de giro del volante.

Pero el problema está en que aunque incluya la biblioteca ServoTimer2 para poder controlar el servo, y funcione, no lo hace muy bien. La transmisión debe ser a 4000 bits/sec y el servo parece dar muchos saltos. Además, cuando se activa el servo el programa "tiende a cortar" la comunicación inalámbrica. Ahora mismo estoy en un modo de diseño y prueba... Pero... ¿y cuando tenga el coche? ¿funcionará?

Y aún no le he metido el Motor Shield para controlar el motor y su potencia. Por lo menos una de las salidas puede entrar en conflicto con los temporizadores de estas bibliotecas, por lo que he leído.

Os escribo para ver si alguien puede arrojar un poco más de luz sobre este proyecto. Si tiene otro enfoque u otra solución para él. A las bravas, lo que se me ocurre es utilizar dos ARDUINOs distintos, uno para la recepción de la señal y otro que controle el servo y el motor. Pero me parece que sería una solución poco elegante. ¿Alguna otra manera de hacerlo?

¡¡MUCHAS GRACIAS!!

Os dejo los programas del transmisor (hardware: dos potenciómetros conectados a A0 y A1 y pines
conectados a 6 y 7 que detectarían si el coche va adelante/detrás y tiene luces encendidas)....

#include <VirtualWire.h>

const int pinData=12; // cambio el puerto de entrada de datos del mando.

const int pinAcelerador = A0;
const int pinVolante = A1;
const int pinMarchaAdelante = 7;
const int pinLuces = 6;

int Acelerador = 0; // valor de 0 a 1023 de cmo acelera.
int Volante = 0; // valor del sensor de giro
int MarchaAdelante = true; // valor de si anda hacia adelante o hacia atrs
int Luces = false; // si estn o no las luces conectadas.

String SSend; // Codigo a enviar
char msg[13]; // cadena de caracteres

void setup()
{
pinMode(pinMarchaAdelante,INPUT); // de entrada
pinMode(pinLuces,INPUT); // de entrada
vw_setup(4000); // Bits per sec. Lo cambio de 2000 a 4000
vw_set_tx_pin(pinData);
// Serial.begin(9600); // empiezo comunicacin serie
// Por defecto el pin de transmisin es el numero 12
}

void loop()
{
// **********************
// Valores de los sensores  
// **********************

//Valor del acelerador
Acelerador=analogRead(pinAcelerador);
//Valor del volante
Volante=analogRead(pinVolante);
//Valor de las Luces
Luces=digitalRead(pinLuces);
//Valor de si estoy en marcha adelante o atras
MarchaAdelante=digitalRead(pinMarchaAdelante);

// **********************
// Mostrar en Serial  
// **********************
/*
Serial.print("Acelerador: ");
Serial.print(Acelerador);
Serial.print(" - ");
Serial.print("Volante: ");
Serial.print(Volante);
Serial.print(" - ");
Serial.print("Luces: ");
Serial.print(Luces);
Serial.print(" - ");
Serial.print("A/D: ");
Serial.print(MarchaAdelante);
Serial.println(""); */

// ******************************************
// Convertir los datos en cadena alfanumerica
// ******************************************
SSend = String("AA"); //Codigo de la tarjeta
SSend+= formateo(Acelerador);
SSend+= formateo(Volante);
SSend+= String(MarchaAdelante);
SSend+= String(Luces);
// Serial.println(SSend);

SSend.toCharArray(msg,13);
vw_send((uint8_t *)msg, strlen(msg));

delay(10); // retraso en la recepcion del mensaje
}

// funcion que formatea los numeros
String formateo (int numero) {
  char cadena[5];
  cadena[0]='0'+(numero/1000);
    numero = numero - 1000*round(numero/1000); 
  cadena[1]='0'+(numero/100);
    numero = numero - 100*round(numero/100); 
  cadena[2]='0'+(numero/10);
    numero = numero - 10*round(numero/10); 
  cadena[3]='0'+(numero%10);
  cadena[4]='\0'; //terminar cadena
  return String(cadena);
}

Y el programa del receptor (hardware: simplemente el servo conectado al pin 3)

#include <ServoTimer2.h>
#include <VirtualWire_Config.h>
#include <VirtualWire.h>

#define pinVolante 3 //donde cojo el Volante

const int valorVolanteMIN = 750; // Inicialmente para una amplitud de unos 120º 750 - 2250 de rango.
const int valorVolanteMAX = 2250; // Cada grado, aumento en PLL de 12,5us
const int valorAmplitudEnGrados = 25; // grados a izquierda y derecha.

ServoTimer2 miVolante;

char Acelerador[5]; // una posicion ms de la necesaria
char Volante[5]; // una posicion ms de la necesaria

int valorAceleracion = 0;
int valorVolanteNuevo = 0; 
int valorVolanteAntiguo = 512; //valor intermedio de comienzo
int valorVolanteMedio = 1475; // valor intermedio
int valorVolanteIZQ = 0;
int valorVolanteDRCH = 0; // 
int marchaAD = true;
int Luces = false;

long recibidos = 0; // cuenta los recibidos
int i; //variable global de recepcion

void setup()
{
miVolante.attach(pinVolante); // cojo el servo en el pin 3.
valorVolanteMedio = (valorVolanteMIN+valorVolanteMAX) / 2;
valorVolanteIZQ=round(valorVolanteMedio-valorAmplitudEnGrados*12.5);
valorVolanteDRCH=round(valorVolanteMedio+valorAmplitudEnGrados*12.5);
Serial.begin(9600);
Serial.println("setup");
vw_setup(4000); // Bits per sec. A 2000 bits/sec
vw_rx_start();
// Start the receiver PLL running
// Por defecto, es el pin 11 el que recibe los datos por VirtualWire
}

void loop()
{
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
  if (vw_get_message(buf, &buflen)) { // Non-blocking  
  
  if (recibidos<1000) {recibidos++; } else {recibidos=0;} //contador

  // Message with a good checksum received, dump HEX
  Serial.print("Got ");
  Serial.println(recibidos);
  
  // Comprueba codigo del mando...
  
  // *******************
  // Obtiene aceleracion
  // *******************
  // Recibiendo primer dato. De la posicin 2 a la 5 inclusive
  for (i = 2; i <=5; i++) {Acelerador[i-2] = char(buf[i]); }
  Acelerador[4]='\0'; // termina la cadena
  valorAceleracion = String(Acelerador).toInt();
  
  // *******************
  // Obtiene Volante
  // *******************
  Serial.print(" Volante: ");
  // Recibiendo primer dato. De la posicin 2 a la 5 inclusive
  for (i = 6; i <=9; i++) {Volante[i-6] = char(buf[i]); }
  Volante[4]='\0'; // termina la cadena
  valorVolanteNuevo = String(Volante).toInt(); // valorRecibido
 
  // Valor de volante a la salida
  valorVolanteNuevo=map(valorVolanteNuevo,0,1023,valorVolanteIZQ,valorVolanteDRCH); //valores en microsegundos experimentales
    // que acepta mi servo. Amplitud aproximada de 120º. A los 1475us estamos en la mitad.
  if ((valorVolanteNuevo > 1.01*valorVolanteAntiguo) || (valorVolanteNuevo < 0.99*valorVolanteAntiguo)) { // Si em muevo en una horquilla de 5%
      // miVolante.attach(pinVolante);
      miVolante.write(valorVolanteNuevo); //activa el servo a la nueva variable
      valorVolanteAntiguo=valorVolanteNuevo; //refresca la variable valorVolanteAntiguo
  } else {
     // desconecto Servo
     // miVolante.detach();
  }// y si no, no hace nada, deja el servo en esa posicion.
 
  // Obtiene si va marcha atrs o delante
  if (char(buf[10])=='1') {marchaAD=true;} else {marchaAD=false;}
 
  // Obtiene si tiene luces encendidas
  if (char(buf[11])=='1') {Luces=true;} else {Luces=false;}
  
  // Serial print
  Serial.print("A: ");
  Serial.print(valorAceleracion);
  Serial.print(" - V: ");
  Serial.print(valorVolanteNuevo);
  Serial.print(" - Vant: ");
  Serial.print(valorVolanteAntiguo);
  Serial.print(" - MAD: ");
  Serial.print(marchaAD);
  Serial.print(" - Luces: ");
  Serial.println(Luces);
  
  delay(5); // retraso en la recepcion del mensaje
  
  } // fin del if de recibir el mensaje
}

Hola te contesto desde mi inexperiencia para intentar daarte una idea, que tal si usas un oscilador externo tipo NE555 a este le puedes ajustar una salida figa de oscilacion con pulsos digitales la cual puedes ajustar por medio de un resistencia y un condensador, este te emitiria una serie de pulsos con intervalos de tiempo ajustable y su coste es menor de 1 euro es otra alternativa para evitar dos placas arduino

PD.mi experiencia con arduino es baja lo conozco y trabajo con el desde hace poco.