Comunicación entre arduínos

Por que conectar dous arduínos?

Imos conectar dous arduinos entre si para que funcionen de maneira sincronizada. Hai diversas ocasións nas que podemos necesitalo, pero vou resaltar dúas delas:

Programas en paralelo

procesos
[tecnoloxia.org By-SA]
Unha importante razón é que necesitemos executar instrucións en paralelo. Por exemplo, queremos que mentres a porta dun garaxe se estea abrindo ou cerrando, un LED escintile e e un zumbador envíe un son. Isto en Arduíno non se pode facer (a non ser que utilicemos novos métodos de programación, como eliminar os delays e utilizar interrupcións, que aquí non imos ver), xa que o control se realiza a través dun microcontrolador, que só é capaz de executar un único programa. Os delays ou tempos de espera que utilizamos para o acendido e apagado dos LEDs ou os do son afectan a todo o programa, tamén ao motor.

Se usásemos un microprocesador (como no caso dun LEGO ou unha Raspberry Pi) isto non tería problema, pois permite a execución de varios programas de maneira simultánea.

Unha solución é utilizar dúas placas: unha encárgase do control do motor de apertura e peche da porta e outra das luces, son, alarma, etc., e sincronizamos os dous programas mediante o envío de mensaxes desde unha placa a outra.

Necesitamos moitos pins

semaforo_peons2
[CC0 Public Domain]
As tarxetas Arduíno UNO teñen un número de entradas e saídas analóxicas e dixitais limitado, e para determinados proxectos pode ser necesario utilizar más. A maneira máis común de aumentar o número de entradas ou saídas é mediante a utilización de chips electrónicos que se encarguen da tarefa. Por exemplo, podemos utilizar un rexistro de desprazamento para o control dun display 7 segmentos, ou podemos usar un multiplexor para aumentar o número de entradas analóxicas.

Sin embargo pode ser tamén interesante traballar na clase a conexión entre arduínos. Por exemplo, nun proxecto dun cruce de semáforos, un compoñente do equipo pódese encargar do control dos LEDs dos semáforos e do son dos pasos de peóns, e outro de programar nunha matriz de LEDs o boneco que se move cando o semáforo está verde. No canto de unificar todo iso nunha única placa (non nos chegarían os pins), facer de novo as conexións e unificar os programas nun programa global podemos facer que o programa de control dos semáforos envíe unha orde a outra placa para que active a matriz de LEDs cando se precise.

Conexión serial:

serie_mestre-escravo
[tecnoloxia.org CC By-SA]
Imos utilizar de forma simplificada o que se coñece por arquitectura mestre/escravo, na que un compoñente realiza labores de control, supervisión e coordinación (denominado mestre) e os restantes realizan tarefas específicas (denominados escravos), devolvendo os resultados ao compoñente mestre.

Para poder establecer a comunicación serie entre dous arduínos requírense unha conexión serie Rx-Tx cruzada e unir as masas:

  • Para envío de datos do mestre ao escravo: Pin Tx do mestre co pin Rx do escravo.
  • Para envío de datos do escravo ao mestre: Pin Tx do escravo co pin Rx do mestre.
  • Unión das masas dos dispositivos.

A distancia máxima  que soporta o bus serie depende da velocidade de transmisión de datos pero aproximadamente a 9600 baudios podemos poñer unha distancia máxima de 15 metros.

Montaxe

Hai dúas maneiras de facer isto:

  • Mediante os pins Rx (pin 0) e Tx (pin 1) das placas. Neste caso antes de subir el código a cada Arduíno cómpre desconectar os pins Rx  e Tx, pois estes pins tamén son usados para comunicarse por USB e non poderiamos instalar o programa.
  • Habilitando outros pins dixitais da placa para que fagan a función Rx e Tx. Desta maneira non é necesario desconectar a comunicación para poder instalar os programas mediante USB.

comunicacionarduinos_01      comunicacionarduinos_78

Antes de instalar os programas fíxate ben a que porto tes conectada cada placa, pois cada unha levará un programa diferente. No caso de dúbidas deixa conectado o cable USB só da placa na que queiras instalar o programa e desconecta o da outra.

Prácticas:

Imos facer dúas prácticas, unha sinxela na que un pulsador conectado á placa 1controla un LED conectado á placa 2, e outra na que se move un servo conectado á placa 1 e uns LEDs conectados á placa 2 escintilan segundo sexa o movemento do servo.

  • Se utilizamos a conexión Rx=0 e Tx=1, nos programas, para enviar e recibir datos, utilízanse os mesmos comandos que utilizamos para comunicarnos coa consola serie:
    Serial.print('A'); Serial.available(); Serial.parseInt(); Serial.read(); etc.
  • Se habilitamos outros pins Rx e Tx (no noso caso Rx=7 e Tx=8), hai que instalar a librería SoftwareSerial.h e indicar os pins Rx e Tx que queremos habilitar mediante a instrución
    SoftwareSerial nomedaplaca(7, 8);

    Os comandos utilizamos son moi similares aos que utilizamos para comunicarnos coa consola serie, só hai que substituír “Serial” polo nome da placa.

    nomedaplaca.begin(9600);     // Inicia a comunicación serie
    nomedaplaca.print('A'); nomedaplaca.available(); nomedaplaca.read(); etc

 

Segundo sexa a conexión que vaias utilizar elixe as prácticas correspondentes.

1. Proba (pins 0-1)

1. Probamos: Imos facer unha práctica sinxela para entender como hai que facer para enviar datos dunha placa a outra: Nun Arduíno conectamos un pulsador e noutro conectamos un LED. O LED debe cambiar de estado cada vez que prememos no pulsador.

serial_probando
[tecnoloxia.org CC By-SA from Fritzing]
Programa da placa 1:

// Declaración de variables:

int pulsador=2;

// Configuración:

void setup(){
  Serial.begin(9600);     // Inicia a comunicación serie        
}

// Programa:

void loop() {
  
  if (digitalRead(pulsador)==1){  
    while(digitalRead(pulsador)==1);   // Agarda mentres o pulsador esta premido
    delay(20);                         // tempo para evitar o efecto rebote do pulsador
    Serial.print('A');                 // Envía o dato A
  }

}

Programa da placa 2:

// Declaración de variables:

int led=13;
char sinal;
int estado=0;       // variable na que almacenamos o estado do LED

// Configuración:

void setup(){
  Serial.begin(9600);      // Inicia a comunicación serie        
  pinMode (led, OUTPUT);
  digitalWrite(led, LOW);
}

// Programa:

void loop(){
  
  if (Serial.available()) {   // Se recibe un dato
    sinal = Serial.read();    // Lemos o dato
    if (sinal == 'A') {       // Se o dato é A cambiamos o estado do led

      if (estado==0) {    
        digitalWrite(led, HIGH);  
        estado=1;
      }
      else{
        digitalWrite(led, LOW); 
        estado=0;
      }
      
    }
  }

}

Lembra que se envías un número e non un carácter, para recibilo no canto de usar Serial.read() debes usar Serial.parseInt()

2. Servo e luz (pins0-1)

2. Movemento e luz (pins 0-1): Imos facer que un servo se mova lentamente de o a 180º e despois en sentido contrario de forma cíclica. Cada vez que xira nun sentido escintila un LED verde, e cando xira en sentido contrario escintila un LED vermello.

serial_servoleds
[tecnoloxia.org CC By-SA from Fritzing]
Programa da placa 1:

#include <Servo.h>

// Declaración de variables:

Servo meuservo;      // poñémoslle nome ao servo: "meuservo"

// Configuración:

void setup(){
  Serial.begin(9600);    // Inicia a comunicación serie 
  meuservo.attach(6);   // servo conectado no pin 6
        
}

// Programa:

void loop() {

  meuservo.write(0);              // Parte da posición de 0º
  Serial.print('A');              // Envía o dato A
  for(int i=0;i<=180;i++){
    meuservo.write(i);   
    delay (20);
  }
  Serial.print('B');              // Envía o dato B
  for(int i=180;i>=0;i--){
    meuservo.write(i);   
    delay (20);
  }

}

Programa da placa 2:

// Declaración de variables:

int ledverde=12;
int ledvermello=13;
int sinal;

// Configuración:

void setup(){
  Serial.begin(9600);      // Inicia a comunicación serie        
  pinMode (ledverde, OUTPUT);
  pinMode (ledvermello, OUTPUT);
}

// Programa:

void verde(){
   digitalWrite(ledverde, HIGH);  
   delay(100);
   digitalWrite(ledverde, LOW); 
   delay(100);
}
void vermello(){
   digitalWrite(ledvermello, HIGH);  
   delay(100);
   digitalWrite(ledvermello, LOW); 
   delay(100);
}

void loop(){
  
  if(Serial.available()){           // Se hai un dato
    sinal = Serial.read();          // Lemos o dato
    Serial.print(sinal); 
    if (sinal == 'A') {             // Se o dato é 'A'
      while(!Serial.available()){   // executamos verde mentres non haxa un novo dato
        verde();
      }
    }
    if (sinal == 'B'){
      while(!Serial.available()){
        vermello();
      }
    }
  }
       
}

3. Proba (pins 7-8)

3. Probamos (pins 7-8): Imos facer unha práctica sinxela para entender como hai que facer para enviar datos dunha placa a outra: Nun Arduíno conectamos un pulsador e noutro conectamos un LED. O LED debe cambiar de estado cada vez que prememos no pulsador.

serial_probando-78
[tecnoloxia.org CC By-SA from Fritzing]
Programa da placa 1

#include <SoftwareSerial.h>
SoftwareSerial placa1(7, 8); // RX, TX

// Declaración de variables:
 
int pulsador=2;
 
// Configuración:
 
void setup(){
  placa1.begin(9600);     // Inicia a comunicación serie        
}
 
// Programa:
 
void loop() {
  
  if (digitalRead(pulsador)==1){  
    while(digitalRead(pulsador)==1);   // Agarda mentres o pulsador esta premido
    delay(20);                         // tempo para evitar o efecto rebote do pulsador
    placa1.print('A');                 // Envía o dato A
  }
 
}

Programa da placa 2

#include <SoftwareSerial.h>
SoftwareSerial placa2(7, 8); // RX, TX

// Declaración de variables:
 
int led=13;
int sinal;
int estado=0;       // variable na que almacenamos o estado do LED
 
// Configuración:
 
void setup(){
  placa2.begin(9600);      // Inicia a comunicación serie        
  pinMode (led, OUTPUT);
  digitalWrite(led, LOW);
}
 
// Programa:
 
void loop(){
  
  if (placa2.available()) {   // Se recibe un dato
    sinal = placa2.read();    // Lemos o dato
    if (sinal == 'A') {       // Se o dato é A cambiamos o estado do led
 
      if (estado==0) {    
        digitalWrite(led, HIGH);  
        estado=1;
      }
      else{
        digitalWrite(led, LOW); 
        estado=0;
      }
      
    }
  }
 
}

4. Servo e luz (pins 7-8)

4. Movemento e luz (pins 7-8): Imos facer que un servo se mova lentamente de o a 180º e despois en sentido contrario de forma cíclica. Cada vez que xira nun sentido escintila un LED verde, e cando xira en sentido contrario escintila un LED vermello.

serial_servoleds_78
[tecnoloxia.org CC By-SA from Fritzing]
Programa da placa 1

#include <Servo.h>
#include <SoftwareSerial.h>
SoftwareSerial placa1(7, 8); // RX, TX

// Declaración de variables:

Servo meuservo;      // poñémoslle nome ao servo: "meuservo"

// Configuración:

void setup(){
  placa1.begin(9600);    // Inicia a comunicación serie
  meuservo.attach(6);   // servo conectado no pin 6
        
}

// Programa:

void loop() {

  meuservo.write(0);              // Parte da posición de 0º
  placa1.print('A');              // Envía o dato A
  for(int i=0;i<=180;i++){
    meuservo.write(i);   
    delay (20);
  }
  placa1.print('B');              // Envía o dato B
  for(int i=180;i>=0;i--){
    meuservo.write(i);   
    delay (20);
  }

}

Programa da placa 2

#include <SoftwareSerial.h>
SoftwareSerial placa2(7, 8); // RX, TX

// Declaración de variables:

int ledverde=12;
int ledvermello=13;
int sinal;

// Configuración:

void setup(){
  placa2.begin(9600);      // Inicia a comunicación serie        
  pinMode (ledverde, OUTPUT);
  pinMode (ledvermello, OUTPUT);
}

// Programa:

void verde(){
   digitalWrite(ledverde, HIGH);  
   delay(100);
   digitalWrite(ledverde, LOW); 
   delay(100);
}
void vermello(){
   digitalWrite(ledvermello, HIGH);  
   delay(100);
   digitalWrite(ledvermello, LOW); 
   delay(100);
}

void loop(){
  
  if(placa2.available()){           // Se hai un dato
    sinal = placa2.read();          // Lemos o dato
    placa2.print(sinal); 
    if (sinal == 'A') {             // Se o dato é 'A'
      while(!placa2.available()){   // executamos verde mentres non haxa un novo dato
        verde();
      }
    }
    if (sinal == 'B'){
      while(!placa2.available()){
        vermello();
      }
    }
  }
       
}

Prácticas:

  1. Outras accións: Engade á práctica “Probamos” outro botón, de xeito que cando o premamos envíe outro dato diferente, e que a placa escrava execute outra acción diferente (que o LED escintile, que soe unha melodía, etc.)
  2. Datos de volta: Nas anteriores prácticas o mestre funcionou como transmisor (Tx) e o escravo coma receptor (Rx). Fai agora que a segunda placa devolva un dato á primeira despois de executar un proceso, e que ao recibilo realice algunha acción.

 


Deixa un comentario