Go Down

Topic: Proyecto: añadir sensores a un robot submarino (Read 32642 times) previous topic - next topic

javikomu

Jul 11, 2014, 12:29 pm Last Edit: Jul 11, 2014, 01:35 pm by javikomu Reason: 1
Saludos a todos!

He estado trabajando por algun tiempo en añadir sensores a un robot submarino. Mi plan es conectar estos sensores a un arduino uno, que posteriormente conectare al arduino del robot via I2C como esclavo.
I had done this code to connect the data adquisition arduino to the computer by USB.
He realizado este codigo para conectar dicho arduino directamente al ordenador.

"CodigoSensoresOrdenador"

Como veis no es un codigo muy complicado, pero al ser la primera vez que trabajo con I2C (ya lo intente una vez pero al final me desespere y acabe utilizando un USB, pero no tengo esa posibilidad ahora), no se muy bien como hacerlo y me vendría bien toda ayuda o consejo que me podaís ofrecer. Investigando un poco he realizado este codigo, que seguramente este mal.

"CodigoSensoresEsclavoI2C"

Si alguién quiere ver como estan conectados puedo subir un diagrama diagrama de conexión rapidamente. De todas maneras lo explico un poco, cuatro de los sensores estan conectados al arduino por un serial port connector y el de temperatura esta conectado directamente a la placa arduino. y todo este arduino es el que iría conectado por I2C al arduino del robot, que a su vez va a una BeagleBone Black (una especie de Raspberry) que esta conectada al ordenador por un cable ethernet.

Muchas Gracias por todo!

Javier Garcia Martin.

P.D:Edito porque no habia adjuntado los códigos

javikomu

Porfa ayuda, que no hay forma de que me salga lo de conectarlo por I2C  :smiley-red: :smiley-sweat:

noter

Hola.
Tal vez deberías poner ese esquema que refieres, porque yo al menos no me termino de aclarar.
Si estos dos códigos se deben comunicar entre sí por i2c, entiendo que codeigosensoresordenador sería el master, ¿no?
Pero el caso es que ni has iniciado Wire en él (de hecho ni incluyes la librería) así que el otro ya puede esforzarse :P.
La verdad es que yo no he utilizado i2c, pero si miras en la referencia el ejemplo write y el ejemplo read, verás al menos cómo empezar con la parte de master.
Saludos.

javikomu

Perdona, creo que me hice la picha un lio explicandome. Adjunto pongo un esquema de cual es mi idea para conectarlo al robot ("EverythingSensorPackageDiagram), la idea es conectar un arduino digamos de adquisición de datos, con el arduino que ya trae el robot, por I2C.
El arduino de adquisición de datos debe estar conectado por supuesto también a los sensores, y esta conexión se hace a traves de un serial port, para todos los sensores excepto para el de temperatura, que se hace directamente ("serial_port_connector_arduino_uno_1", "Wiringdiagram_ENV_TMP.pdf").
Para probar directamente el arduino de adquisición de datos, lo conecte via serie al ordenador y realice el código llamado CodigoSensoresOrdenador, mi problema es que al no haber usado nunca I2C, no se adaptar bien ese código para que las ordenes de tomar dato de "x" o pedir dato de "x" las mande por I2C en lugar de via serie.
Modificar el codigo del arduino del robot para que las pida, ya es otro problema posterior.
Un saludo!

noter

Bueno; entiendo que lo que quieres es sustituir la transmisión-recepción serial en codigosensoresesclavo por una i2c y en codigosensoresordenador aún no has implementado nada del master.  Ya puedes poner dispositivos esclavos perfectamente programados, que como no haya un master que les dé la palabra, no van a decir ni pío.
Creo que podíamos empezar concretando más qué información deseas enviar del master al esclavo y viceversa, y centrarnos en un pequeño programa que muestre en el monitor del master lo que se recibe del esclavo. Una de las cuestiones a tener en cuenta es que el máximo de datos que se puede enviar en una trama i2c creo que es 32 bytes (aunque se puede modificar en la librería), así que lo ideal sería enviar los datos mínimos, con lo que además optimizamos tanto el tiempo de transmisión como la posterior extracción y conversión de los datos. No tiene sentido que algo que vamos a enviar para consumo del arduino se le envíe "humanizado" en plan cadenas tipo "temperatura1=27.56,temperatura2=27.30". Lo mismo se podría aplicar a las transmisiones serie entre dispositivos (otra cosa es una transmisión destinada al usuario, como el monitor serial).
De todas formas, si de momento sólo te interesa conseguir una transmisión i2c tal vez esto te ayude para empezar.
Ya irás contando.
Saludos.

javikomu

CodigoSensoresOrdenador es un código que hice para ver si los sensores funcionaban. En dicho código no hay conexión I2C, solo vía serie al ordenador. Lo que hace es que cada vez que recibe una orden del ordenador, esta orden lleva asociada un canal (uno de los sensores) y un cmd. Así pués, en función de lo que se le dice desde el ordenador toma una medida u otra. El ordenador envia las ordenes en forma de bytes con readbytesuntil.

Ese código es el que quiero transformar para en lugar de recibir esos bytes que dan la orden desde el ordenador por puerto serie, se reciban por I2C desde otro arduino maestro. Esta claro que hasta que no programe el maestro me puedo comer los mocos, pero quiero creer que es más facil empezar adaptando este código. El arduino maestro lleva encima toda la programación del robot que no es poca, y para hacerlo master hay que hacer un analisis del código grande.


noter

Bien. En el código del esclavo i2c debes, básicamente, construir las funciones callback para onReceive y onRequest

Code: [Select]

void receiveEvent(int computer_bytes_received)
{
      for (int i=0; i<computer_bytes_received; i++){
            computerdata[i]=wire.read();
      }
      // analizar los datos recibidos en computerdata, preparar una respuesta en sensordata
}


void requestEvent(void)
{
      wire.write(sensordata); // Si es una cadena, así valdría. si es una estructura sería wire.write(estructura, numbytes)     
}



La principal diferencia es que cuando recibes datos del maestro, no puedes contestar inmediatamente, sino que irás preparando una respuesta en un buffer a la espera de que el master solicite datos. En requestEvent enviaremos esos datos previamente preparados en ese buffer.

javikomu

Vale, creo que lo voy entendiendo, puedes desarrollar un poco la idea del buffer.

Muchas gracias!

noter

Con lo del buffer, me refiero a un espacio de memoria en el que irás preparando los datos a enviar. Puede ser una cadena, en cuyo caso la "construyes" cuando el master te envía sus mensaje, y será la cadena que permanecerá a la espera de ser enviada cuando el master te diga "habla".
Digamos que antes, cuando te llegaba la pregunta ibas contestando la respuesta; ahora sólo preparas la respuesta para cuando te den permiso para hablar.
Sería interesante saber en qué "dialecto" van a ir esas preguntas y respuestas y podría decirte códigos más concretos.

javikomu

Y si no me importa demasiado perder datos, me vale con que el arduino envie al maestro el último valor del dato que tiene (el actual).
He desarrollado el siguiente código un poco con tus indicaciones, un poco con lo que he encontrado en reference. SIn embargo, no se si esta bien, compilarme no me compila porque da algún tipo de error raro en el onReceive de que no se puede hacer una conversion void a void o algo así.

noter

Claro. Te da ese error, precisamente porque la función que asignes a onReceive debe ser void y recibir un parámetro int. Prueba el receiveEvent que te puse cuatro post arriba.
Code: [Select]

void receiveEvent(int computer_bytes_received)
{
      for (int i=0; i<computer_bytes_received; i++){
            computerdata[i]=wire.read();
      }
}


Y en cuanto a la función que asignas a requestEvent, prueba por este otro camino (escribiendo los datos previamente en un buffer de memoria), ya que creo que desde el esclavo se debe escribir, si no me equivoco, en un solo comando.
Code: [Select]

void requestEvent()
{
      char buffer_envio[20];
      sprintf(buffer_envio,"%s%f", sensordata, temp);
      wire.write(buffer_envio); // El envío desde esclavo i2c se debe hacer de una vez, creo
}

javikomu

Vale lo pruebo. Pero no entiendo muy bien como funciona, y porque debe recibir un int  :smiley-sweat:

javikomu

Bueno compilar compila, pero sigo sin entender bien tus modificaciones.
Me queda probarlo cuando consiga modificar el código del robot para ver si funciona. Lo que pasa es que el código del master va a tener tela, tengo que encontrar como insertarlo aquí https://github.com/OpenROV/openrov-software-arduino/tree/master/OpenROV



noter

Una de las características de C++ que para algunos será virtud y para otros defecto, es que es muy estricto en cuanto a los tipos de variable, lo que incluye las funciones. Si miras la referencia, verás que el parámetro que se pasa a wire.onRequest es una función de tipo void y sin parámetros. Si la función que le asignas no coincide, el compilador te dará error. De la misma forma, para wire.onReceive el parámetro es una función tipo void y que va a recibir un parámetro int, así que tu función debe ser así. Si lees más, verás que a través de ese parámetro vas a recibir la cantidad de bytes que se te envían (yo lo he llamado computer_bytes_received), así que lo mejor es leer ese parámetro para saber cuántos bytes leer (como ves lo he utilizado en el for).
El código del master no debería ser muy complejo, sabiendo qué hay que enviar y recibir.
En el vínculo que te pasé en otro post tienes un ejemplo de transmisión master, recepción master, recepción esclavo y transmisión esclavo (al recibir onrequest).

javikomu

Muchas gracias, voy a mirarlo y te digo cuando vea algo.
El problema que tengo es que si ves el código del robot que te he puesto, es un .ino que corre todos los devices en el loop (los devices estan definidos en los .h y .cpp) y uno de estos es I2Cdevices, tengo que averiguar la forma de meter este arduino como un I2C device en el Robot  :smiley-roll-blue:

Go Up