Avvertenze

Relativamente agli aspetti di sicurezza, poiché i progetti sono basati su alimentazione elettrica in bassissima tensione erogata dalla porta usb del pc o da batterie di supporto o alimentatori con al massimo 9V in uscita, non ci sono particolari rischi di natura elettrica. È comunque doveroso precisare che eventuali cortocircuiti causati in fase di esercitazione potrebbero produrre danni al pc, agli arredi ed in casi estremi anche a ustioni, per tale ragione ogni qual volta si assembla un circuito, o si fanno modifiche su di esso, occorrerà farlo in assenza di alimentazione e al termine dell’esercitazione occorrerà provvedere alla disalimentazione del circuito rimuovendo sia il cavo usb di collegamento al pc che eventuali batterie dai preposti vani o connettori di alimentazione esterna. Inoltre, sempre per ragioni di sicurezza, è fortemente consigliato eseguire i progetti su tappeti isolanti e resistenti al calore acquistabili in un qualsiasi negozio di elettronica o anche sui siti web specializzati.

Al termine delle esercitazioni è opportuno lavarsi le mani, in quanto i componenti elettronici potrebbero avere residui di lavorazione che potrebbero arrecare danno se ingeriti o se a contatto con occhi, bocca, pelle, etc. Sebbene i singoli progetti siano stati testati e sicuri, chi decide di seguire quanto riportato nel presente documento, si assume la piena responsabilità di quanto potrebbe accadere nell’esecuzione delle esercitazioni previste nello stesso. Per i ragazzi più giovani e/o alle prime esperienze nel campo dell’Elettronica, si consiglia di eseguire le esercitazioni con l’aiuto ed in presenza di un adulto.

Roberto Francavilla

Controllare un Braccio Robot via BT con HC-05 e PCA9685

Continuiamo sulla scia delle lezioni precedenti che mostrano le varie modalità di controllo del Braccio Robot e vediamo in questa lezione come combinare l’uso della scheda PCA9685 per il controllo dei servomotori e del modulo Bluetooth HC-05 per il collegamento wireless tra PC e Arduino.

Da un punto di vista hardware utilizzeremo oggetti ben noti per cui non c’è nulla da approfondire, mentre da un punto di vista software dovremo aggiornare sia lo sketch su Arduino che quello su Processing.

Non perdiamo altro tempo passiamo subito all’azione e quindi al Progetto 12.

Progetto 12: Controllo e Comando Braccio Robot via BT con PCA9685

Anche per questo progetto si utilizzerà Processing per creare una fantastica interfaccia grafica che riporta in 3D tutti i movimenti del nostro braccio robotico che comandiamo tramite Arduino.

Descrizione del Progetto 12: impartiremo dei comandi cliccando con il tasto sinistro del mouse su dei bottoni presenti nella pagina grafica riprodotta con Processing su un PC che è collegato tramite il modulo Bluetooth HC-05 ad Arduino. Per verificare i comandi provenienti dal primo PC collegheremo ad Arduino via USB un secondo PC in modo tale da far riprodurre sul monitor seriale i vari comandi ricevuti. Ad Arduino è collegata quindi, tramite I2C la scheda PCA9685 Servormotor Controller che provvederà a smistare i comandi ai singoli servomotori e ad alimentarli. Ovviamente, come ogni mio progetto, esso è da considerarsi solo come punto di partenza anche per i vostri sviluppi e miglioramenti.

Per questo progetto ci occorre:

Andiamo a realizzare quanto rappresentato dagli schemi di montaggio sotto, come ben potete osservare sono in sostanza due sistemi separati, li rappresenterò separatamente anche per migliorarne la lettura, uno schema si occupa della comunicazione Bluetooth e l’altro del comando e controllo del braccio robot attraverso la PCA9685. L’alimentazione dei 7 servo motori è fatta attraverso un alimentatore stabilizzato con tensione a 5 V che va alla PCA9685 che a sua volta provvederà a smistare l’alimentazione ai singoli servo.
Vediamo lo schema da realizzare per la parte relativa alla comunicazione Bluetooth con l’HC-05. Come è possibile osservare è sostanzialmente identico a quanto fatto per il Progetto 5

Per quanto riguarda lo schema da realizzare per il controllo dei servomotori del braccio, potete fare riferimento allo schema sotto:

Durante il montaggio dei circuiti fate attenzione ai colori dei cavi del servo (marrone = GND, rosso = Vcc e arancio = Segnale) ed inoltre poiché sicuramente necessiterete di prolunghe, fate in modo che nei punti di giunzione non vi si creino distaccamenti di cavi mettendo del nastro adesivo di carta.

Nota: per far si che i due circuiti abbiano lo stesso riferimento a massa, i due negativi delle basette vanno collegati. Occorre fare attenzione: se non avete un buon alimentatore, tale collegamento può provocare l’entrata in protezione del PC, per cui in questo caso occorre tenerle separate (per il PC, basta staccarlo dalla rete per 10-15 sec e riattaccarlo). 

Lo sketch da caricare su Arduino è il seguente:

Lo sketch da aprire in Processing sul PC è il seguente:

/*
BeMaker.org - CORSO SUL BRACCIO ROBOTICO
Progetto 12 – CONTROLLO BRACCIO VIA BT CON HC-05 E PCA9685
https://bemaker.org/
*/
import processing.serial.*;  //Importo la libreria perle comunicazioni seriali
Serial myPort;               //Definisco l'oggetto myPort
String Stato = "";                //Definisce la variabile Stato come stringa che darà indiazioni su Arduino
//String Pacchetto;                 //Definisce la variabile Pacchetto come stringa di caratteri che riceve da Arduino
float vel=0.5;                   //Fattore moltiplicativo angoli di rotazione
float rotazioneS1 = 0.0;  //Definisco la variabile di rotazione di S1
float rotazioneS2 = 0.0;  //Definisco la variabile di rotazione di S2
float rotazioneS3 = 0.0;  //Definisco la variabile di rotazione di S3
float rotazioneS4 = 0.0;  //Definisco la variabile di rotazione di S4
float rotazioneS5 = 0.0;  //Definisco la variabile di rotazione di S5
float rotazioneS6 = 0.0;  //Definisco la variabile di rotazione di S6
float rotazioneS7 = 0.0;  //Definisco la variabile di rotazione di S7
int grad_rot_1 = 0;     //Definisco la variabile intera che rappresenta la corrispondente rotazione in gradi
int grad_rot_2 = 0;     //Definisco la variabile intera che rappresenta la corrispondente rotazione in gradi
int grad_rot_3 = 0;     //Definisco la variabile intera che rappresenta la corrispondente rotazione in gradi
int grad_rot_4 = 0;     //Definisco la variabile intera che rappresenta la corrispondente rotazione in gradi
int grad_rot_5 = 0;     //Definisco la variabile intera che rappresenta la corrispondente rotazione in gradi
int grad_rot_6 = 0;     //Definisco la variabile intera che rappresenta la corrispondente rotazione in gradi
int grad_rot_7 = 0;     //Definisco la variabile intera che rappresenta la corrispondente rotazione in gradi
String testoA = "";      //Defnisco una variabile stringa
String testoB = "";      //Defnisco una variabile stringa
String testoC = "";      //Defnisco una variabile stringa
String testoD = "";      //Defnisco una variabile stringa
String testoE = "";      //Defnisco una variabile stringa
String testoF = "";      //Defnisco una variabile stringa
String testoG = "";      //Defnisco una variabile stringa
String Pp = "Pp";        //Defnisco una variabile stringa
void setup() {
  String portName = "COM10";  //Associo la porta COM effettivamete utilizzata per la comunicazione - vedere Lezione 4 del Corso per come fare
  myPort = new Serial(this, portName, 9600);  //Creazione e Settaggio della porta
  myPort.bufferUntil('\n');      // Definisce il carattere terminale della stringa da leggere
  myPort.write ((Pp)+'\n');      //Viene inviata la stringa 'Pp' alla porta BT per sincerarci che partiamo da una condizione nota
  delay(100);
  //Impostazione ambiente grafico 3D ed assegnazione variabili
  size( 1600, 900, P3D ); //Creao una finestra 3D x=1500, y=800 z= indefinito
  ambientLight(0,0,255);  //Aggiungo una luce ambientale bianca diffusa
  pointLight(255, 0, 0, width/2, height/2, 400);  //Aggiungo un proiettore di luce biancaa metà lunghezza della finestra per dare le ombre per la profondità
  noStroke();          //Non definisco i contorni dei solidi che andrò a disegnare
  rotazioneS1=PI/2;    //Servo S1 BASE a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180    
  rotazioneS2=PI/2;    //Servo S2 Braccio a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
  rotazioneS3=PI/2;    //Servo S3 AvanBraccio a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
  rotazioneS4=PI/2;    //Servo S4 Rotazione AvanBraccio a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
  rotazioneS5=PI/2;    //Servo S5 Rotazione Polso a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
  rotazioneS6=PI/2;    //Servo S6 Rotazione Pinza a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
  rotazioneS7=PI/2;    //Servo S7 presa pinza a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
  if (myPort.available() > 0) {           //Controlla se ci sono dati sulla porta seriale
    Stato = myPort.readStringUntil('\n'); //Legge la stringa proveniente da Arduino e la mette nella variabile stato
  }
}
void draw() {
  background(0);
  lights();
  DisegnaLegenda();
  
  //CONTROLLA QUANDO VIENE PREMUTO IL TASTO SINISTRO DEL MOUSE SU UN DETERMINATO RETTANGOLO
  //1090,70,180,50 - Xgra: rad = 180 : pi
  if(mousePressed && mouseX>1090 && mouseX<1090+180 && mouseY>70 && mouseY<70+50){
    IlluminaTasto(1090,70,180,50);
    rotazioneS1 = RotazioneGiuntoPos(rotazioneS1);
    grad_rot_1 = parseInt(rotazioneS1 * 180 / PI);
    String a1="A";
    int a2 = parseInt(grad_rot_1);
    testoA = a1+a2;    
    myPort.write((testoA)+'\n');
    print("Rotazione Servo 1 = "); print(rotazioneS1); print("    "); print(grad_rot_1); print("    "); println(testoA); //debug
    delay(10);
  }
  //1320,70,180,50
  if(mousePressed && mouseX>1320 && mouseX<1320+180 && mouseY>70 && mouseY<70+50){
    IlluminaTasto(1320,70,180,50);
    rotazioneS1 = RotazioneGiuntoNeg(rotazioneS1);
    grad_rot_1 = parseInt(rotazioneS1 * 180 / PI);
    String a1="A";
    int a2 = parseInt(grad_rot_1);
    String testoA = a1+a2;
    myPort.write((testoA)+'\n');
    print("Rotazione Servo 1 = "); print(rotazioneS1); print("    "); print(grad_rot_1); print("    "); println(testoA); //debug
    delay(10);
  }
  //1090,170,180,50
  if(mousePressed && mouseX>1090 && mouseX<1090+180 && mouseY>170 && mouseY<170+50){
    IlluminaTasto(1090,170,180,50);
    rotazioneS2 = RotazioneGiuntoPos(rotazioneS2);
    grad_rot_2 = parseInt(rotazioneS2 * 180 / PI);
    String b1="B";
    int b2 = parseInt(grad_rot_2);
    String testoB = b1+b2;
    myPort.write((testoB)+'\n');
    print("Rotazione Servo 2 = "); print(rotazioneS2); print("    "); print(grad_rot_2); print("    "); println(testoB); //debug
    delay(10);
  }
   //1320,170,180,50
  if(mousePressed && mouseX>1320 && mouseX<1320+180 && mouseY>170 && mouseY<170+50){
    IlluminaTasto(1320,170,180,50);
    rotazioneS2 = RotazioneGiuntoNeg(rotazioneS2);
    grad_rot_2 = parseInt(rotazioneS2 * 180 / PI);
    String b1="B";
    int b2 = parseInt(grad_rot_2);    stroke(255,0,0);                   //Il contorno del tasto si colora di Rosso
    String testoB = b1+b2;
    myPort.write((testoB)+'\n');
    print("Rotazione Servo 2 = "); print(rotazioneS2); print("    "); print(grad_rot_2); print("    "); println(testoB); //debug
    delay(10);
  }
  //1090,270,180,50
  if(mousePressed && mouseX>1090 && mouseX<1090+180 && mouseY>270 && mouseY<270+50){
    IlluminaTasto(1090,270,180,50);
    rotazioneS3 = RotazioneGiuntoPos(rotazioneS3);
    grad_rot_3 = parseInt(rotazioneS3 * 180 / PI);
    String c1="C";
    int c2 = parseInt(grad_rot_3);
    String testoC = c1+c2;
    myPort.write((testoC)+'\n');
    print("Rotazione Servo 3 = "); print(rotazioneS3); print("    "); print(grad_rot_3); print("    "); println(testoC); //debug
    delay(10);
  }
   //1320,270,180,50
  if(mousePressed && mouseX>1320 && mouseX<1320+180 && mouseY>270 && mouseY<270+50){
    IlluminaTasto(1320,270,180,50);
    rotazioneS3 = RotazioneGiuntoNeg(rotazioneS3);
    grad_rot_3 = parseInt(rotazioneS3 * 180 / PI);
    String c1="C";
    int c2 = parseInt(grad_rot_3);
    String testoC = c1+c2;
    myPort.write((testoC)+'\n');
    print("Rotazione Servo 3 = "); print(rotazioneS3); print("    "); print(grad_rot_3); print("    "); println(testoC); //debug
    delay(10);
  }
  //1090,370,180,50
  if(mousePressed && mouseX>1090 && mouseX<1090+180 && mouseY>370 && mouseY<370+50){
    IlluminaTasto(1090,370,180,50);
    rotazioneS4 = RotazioneGiuntoPos(rotazioneS4);
    grad_rot_4 = parseInt(rotazioneS4 * 180 / PI);
    String d1="D";
    int d2 = parseInt(grad_rot_4);
    String testoD = d1+d2;
    myPort.write((testoD)+'\n');
    print("Rotazione Servo 4 = "); print(rotazioneS4); print("    "); print(grad_rot_4); print("    "); println(testoD); //debug
    delay(10);
  }
   //1320,370,180,50
  if(mousePressed && mouseX>1320 && mouseX<1320+180 && mouseY>370 && mouseY<370+50){
    IlluminaTasto(1320,370,180,50);
    rotazioneS4 = RotazioneGiuntoNeg(rotazioneS4);
    grad_rot_4 = parseInt(rotazioneS4 * 180 / PI);
    String d1="D";
    int d2 = parseInt(grad_rot_4);
    String testoD = d1+d2;
    myPort.write((testoD)+'\n');
    print("Rotazione Servo 4 = "); print(rotazioneS4); print("    "); print(grad_rot_4); print("    "); println(testoD); //debug
    delay(10);
  }
  //1090,470,180,50
  if(mousePressed && mouseX>1090 && mouseX<1090+180 && mouseY>470 && mouseY<470+50){
    IlluminaTasto(1090,470,180,50);
    rotazioneS5 = RotazioneGiuntoPos(rotazioneS5);
    grad_rot_5 = parseInt(rotazioneS5 * 180 / PI);
    String e1="E";
    int e2 = parseInt(grad_rot_5);
    String testoE = e1+e2;
    myPort.write((testoE)+'\n');
    print("Rotazione Servo 5 = "); print(rotazioneS5); print("    "); print(grad_rot_5); print("    "); println(testoE); //debug
    delay(10);
  }
   //1320,470,180,50
  if(mousePressed && mouseX>1320 && mouseX<1320+180 && mouseY>470 && mouseY<470+50){
    IlluminaTasto(1320,470,180,50);
    rotazioneS5 = RotazioneGiuntoNeg(rotazioneS5);
    grad_rot_5 = parseInt(rotazioneS5 * 180 / PI);
    String e1="E";
    int e2 = parseInt(grad_rot_5);
    String testoE = e1+e2;
    myPort.write((testoE)+'\n');
    print("Rotazione Servo 5 = "); print(rotazioneS5); print("    "); print(grad_rot_5); print("    "); println(testoE); //debug
    delay(10);
  } 
  //1090,570,180,50
  if(mousePressed && mouseX>1090 && mouseX<1090+180 && mouseY>570 && mouseY<570+50){
    IlluminaTasto(1090,570,180,50);
    rotazioneS6 = RotazioneGiuntoPos(rotazioneS6);
    grad_rot_6 = parseInt(rotazioneS6 * 180 / PI);
    String f1="F";
    int f2 = parseInt(grad_rot_6);
    String testoF = f1+f2;
    myPort.write((testoF)+'\n');
    print("Rotazione Servo 6 = "); print(rotazioneS6); print("    "); print(grad_rot_6); print("    "); println(testoF); //debug
    delay(10);
  }
   //1320,570,180,50
  if(mousePressed && mouseX>1320 && mouseX<1320+180 && mouseY>570 && mouseY<570+50){
    IlluminaTasto(1320,570,180,50);
    rotazioneS6 = RotazioneGiuntoNeg(rotazioneS6);
    grad_rot_6 = parseInt(rotazioneS6 * 180 / PI);
    String f1="F";
    int f2 = parseInt(grad_rot_6);
    String testoF = f1+f2;
    myPort.write((testoF)+'\n');
    print("Rotazione Servo 6 = "); print(rotazioneS6); print("    "); print(grad_rot_6); print("    "); println(testoF); //debug
    delay(10);
  } 
  //1090,670,180,50
  if(mousePressed && mouseX>1090 && mouseX<1090+180 && mouseY>670 && mouseY<670+50){
    IlluminaTasto(1090,670,180,50);
    rotazioneS7 = RotazioneGiuntoPos(rotazioneS7);
    grad_rot_7 = parseInt(rotazioneS7 * 180 / PI);
    String g1="G";
    int g2 = parseInt(grad_rot_7);
    String testoG = g1+g2;
    myPort.write((testoG)+'\n');
    print("Rotazione Servo 7 = "); print(rotazioneS7); print("    "); print(grad_rot_7); print("    "); println(testoG); //debug
    delay(10);
  }
   //1320,670,180,50
  if(mousePressed && mouseX>1320 && mouseX<1320+180 && mouseY>670 && mouseY<670+50){
    IlluminaTasto(1320,670,180,50);
    rotazioneS7 = RotazioneGiuntoNeg(rotazioneS7);
    grad_rot_7 = parseInt(rotazioneS7 * 180 / PI);
    String g1="G";
    int g2 = parseInt(grad_rot_7);
    String testoG = g1+g2;
    myPort.write((testoG)+'\n');
    print("Rotazione Servo 7 = "); print(rotazioneS7); print("    "); print(grad_rot_7); print("    "); println(testoG); //debug
    delay(10);
  } 
  //1205,770,180,50 - TASTO RESET
  if(mousePressed && mouseX>1205 && mouseX<1205+180 && mouseY>770 && mouseY<770+50){
    IlluminaTasto(1205,770,180,50);
    TastoReset();
    rotazioneS1=PI/2;    //Servo S1 BASE a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180    
    rotazioneS2=PI/2;    //Servo S2 Braccio a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
    rotazioneS3=PI/2;    //Servo S3 AvanBraccio a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
    rotazioneS4=PI/2;    //Servo S4 Rotazione AvanBraccio a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
    rotazioneS5=PI/2;    //Servo S5 Rotazione Polso a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
    rotazioneS6=PI/2;    //Servo S6 Rotazione Pinza a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
    rotazioneS7=PI/2;    //Servo S7 presa pinza a riposo si trova a 90° per cui ruota da 0 a 90 e da 90 a 180
  }  
  DisegnaBraccio();
}
void TastoReset() {    
    String testoA = "A90";
    myPort.write((testoA)+'\n');
    print("Rotazione Servo 1 = "); print(PI/2); print("    "); print(90); print("    "); println(testoA); //debug
    delay(200);
    
    String testoB = "B90";
    myPort.write((testoB)+'\n');
    print("Rotazione Servo 2 = "); print(PI/2); print("    "); print(90); print("    "); println(testoB); //debug
    delay(200);
    String testoC = "C90";
    myPort.write((testoC)+'\n');
    print("Rotazione Servo 3 = "); print(PI/2); print("    "); print(90); print("    "); println(testoC); //debug
    delay(200);
    String testoD = "D90";
    myPort.write((testoD)+'\n');
    print("Rotazione Servo 4 = "); print(PI/2); print("    "); print(90); print("    "); println(testoD); //debug
    delay(200);
    String testoE = "E90";
    myPort.write((testoE)+'\n');
    print("Rotazione Servo 5 = "); print(PI/2); print("    "); print(90); print("    "); println(testoE); //debug
    delay(200);
    String testoF = "F90";
    myPort.write((testoF)+'\n');
    print("Rotazione Servo 6 = "); print(PI/2); print("    "); print(90); print("    "); println(testoF); //debug
    delay(200);
    String testoG = "G90";
    myPort.write((testoG)+'\n');
    print("Rotazione Servo 7 = "); print(PI/2); print("    "); print(90); print("    "); println(testoG); //debug
    delay(200);
}
  
void DisegnaLegenda() {
  //Posiziono il testo per sito
  fill(255);    //Seleziono il colore Bianco     
  textSize(20);                        //Dimensione testo
  text("WWW.BEMAKER.ORG", 50, 880);   //Posiziona testo "WWW.BEMAKER.ORG"
    if (Stato != null) {  //debug
      text(Stato, 400, 880);              //Posiziona testo Stato
    } else {                                
      text("Non ho ricevuto l'OK da Arduino... controlla!", 400, 880);              //Posiziona testo Stato
     }
  //Posiziono il testo per la legenda dei click di mouse di comando
  textSize(30); //Dimensione testo
  fill(255);    //Seleziono il colore Bianco     
  text("CLICK MOUSE", 1200, 50);   //Posiziona testo "LEGENDA"
  //prima riga
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1090,70,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("a = S1 <-", 1100, 100);   //Posiziona testo "S1 <-"
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1320,70,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("s = S1 ->", 1330, 100);   //Posiziona testo "S1 <-"
  //seconda riga
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1090,170,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("e = S2 v", 1100, 200);   //Posiziona testo "e = S2 ^"
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1320,170,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("d = S2 ^", 1330, 200);   //Posiziona testo "d = S2 v"
  //terza riga
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1090,270,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("r = S3 ^", 1100, 300);   //Posiziona testo "e = S3 ^"
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1320,270,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("f = S3 v", 1330, 300);   //Posiziona testo "d = S3 v"
  //quarta riga
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1090,370,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("t = S4 <-", 1100, 400);   //Posiziona testo "e = S4 ^"
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1320,370,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("g = S4 ->", 1330, 400);   //Posiziona testo "d = S4 v"
  //quinta riga
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1090,470,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("y = S5 <-", 1100, 500);   //Posiziona testo "e = S5 ^"
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1320,470,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("h = S5 ->", 1330, 500);   //Posiziona testo "d = S5 v"
  //sesta riga
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1090,570,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("u = S6 <-", 1100, 600);   //Posiziona testo "e = S6 <-"
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1320,570,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("j = S6 ->", 1330, 600);   //Posiziona testo "d = S6 ->"
  //settima riga
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1090,670,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("k = S7 <->", 1100, 700);   //Posiziona testo "d = S7 <->"
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1320,670,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("l = S7 >-<", 1330, 700);   //Posiziona testo "d = S7 >-<"
  //ottava riga
  fill(0,123,184);    //Seleziono il colore Bianco     
  rect(1205,770,180,50);
  fill(255);    //Seleziono il colore Bianco     
  text("RESET", 1250, 800);   //Posiziona testo "d = S7 <->"
  fill(255);    //Seleziono il colore Bianco     
}
void DisegnaBraccio() {
  // Disegno il Braccio Robot in 3D
  //Disegno la base
  noStroke();
  translate(300,700,0);  //Sposto il riferimento del disegno verso destra (x) di 200, verso il basso (y) di 600 e z=0
  rotateY(rotazioneS1);  //Ruoto lungo l'asse y
  fill(0,127,255);       //Seleziono il colore blu
  box(60);               //Disegno alle nuove coordinate un cubo di lato 60
  //Disegno il giunto di rotazione del braccio
  translate( 0,-60,0 );   //Sposto il riferimento solo verso l'alto lungo la y
  fill(255,0,0);          //Seleziono il colore Rosso
  rotateX( PI-rotazioneS2 ); //Ruoto lungo l'asse X
  sphere(30);             //Disegno una sfera
  //Disegno il braccio
  translate( 0,0,140 );  //Sposto il riferimento solo verso l'alto lungo la z
  fill(255,255,0);       //Seleziono il colore Giallo
  box( 60, 60, 220 );    //Disegno un parallelepipedo 60x60x220
  //Disegno il giunto di rotazione dell'avanbraccio
  translate( 0,0,140 );  //Sposto il riferimento solo verso l'alto lungo la z
  fill(255,0,0);          //Seleziono il colore Rosso
  rotateX( rotazioneS3 ); //Ruoto lungo l'asse X
  rotateZ( rotazioneS4 ); //Ruoto lungo l'asse z
  sphere(30);             //Disegno una sfera
  //Disegno l'avanbraccio
  translate( 0,0,-110 );  //Sposto il riferimento solo verso l'alto lungo la z
  fill(255,255,0);       //Seleziono il colore Giallo
  box( 60, 60, 150 );    //Disegno un parallelepipedo 60x60x220
  //Disegno il giunto di rotazione del polso
  translate( 0,0,-110 );  //Sposto il riferimento solo verso l'alto lungo la z
  fill(255,0,0);          //Seleziono il colore Rosso
  rotateX( rotazioneS5 ); //Ruoto lungo l'asse y
  rotateY( rotazioneS6 ); //Ruoto lungo l'asse z
  sphere(30);             //Disegno una sfera
  //Disegno la pinza inferiore
  translate( 0,-70,0 );  //Sposto il riferimento solo verso l'alto lungo la z
  fill(70,70,70);          //Seleziono il colore Rosso
  box( 20, 130, 20 );    //Disegno un parallelepipedo
  //Disegno il giunto di rotazione della pinza superiore
  translate( 0,35,0 );  //Sposto il riferimento solo verso l'alto lungo la z
  fill(255,0,0);          //Seleziono il colore Rosso
  rotateX( PI-rotazioneS7 ); //Ruoto lungo l'asse x
  sphere(10);             //Disegno una sfera
  //Disegno la pinza superiore
  translate( 0,50,0 );  //Sposto il riferimento solo verso l'alto lungo la z
  fill(70,70,70);          //Seleziono il colore Rosso
  rotateX( -PI/2 );       //Ruoto lungo l'asse X
  box( 20, 20, 80 );    //Disegno un parallelepipedo
  translate( 0,-40,40 );  //Sposto il riferimento solo verso l'alto lungo la z
  fill(70,70,70);          //Seleziono il colore Rosso
  rotateX( PI/2 );       //Ruoto lungo l'asse X
  box( 20, 20, 80 );    //Disegno un parallelepipedo  
}
void IlluminaTasto(int xa, int xb, int xc, int xd) {
    stroke(255,0,0);                   //Il contorno del tasto si colora di Rosso
    strokeWeight(10);                  //lo spessore del contorno diventa da 10
    noFill();                          //Nessun riempimento (trasparente)
    rect(xa,xb,xc,xd);        //rettangolo del tasto ON
}
float RotazioneGiuntoPos(float rg1) {
  rg1 = rg1+(vel*PI/180);           //calcolo la rotazione giunto in radianti, facendola incrementare di un grad per volta
  int rg2 = parseInt(rg1 * 180/PI);                 //converto i valori da rad in grad
  if (rg2<0){                        //limitare le rotazioni per valori <0
    rg2 = 0;                         //inserisco un valore zero anche quando con il mouse si vuole dare una rotazione negativa
    rg1 = 0.0;          
    } else if (rg2>180){             //limitare le rotazioni per valori >180°
      rg2 = 180;                     //inserisco 180 gradi anche quando con il muose si vuole dare una rotazione maggiore
      rg1 = PI;
    }
    return rg1;
}
float RotazioneGiuntoNeg(float rg1) {
  rg1 = rg1-(vel*PI/180);           //calcolo la rotazione giunto in radianti, facendola incrementare di un grad per volta
  int rg2 = parseInt(rg1 * 180/PI);                 //converto i valori da rad in grad
  if (rg2<0){                        //limitare le rotazioni per valori <0
    rg2 = 0;                         //inserisco un valore zero anche quando con il mouse si vuole dare una rotazione negativa
    rg1 = 0.0;          
    } else if (rg2>180){             //limitare le rotazioni per valori >180°
      rg2 = 180;                     //inserisco 180 gradi anche quando con il muose si vuole dare una rotazione maggiore
      rg1 = PI;
    }
    return rg1;
}

Analisi degli sketch del Progetto 12 - Controllo e Comando Braccio Robot via BT

Gli sketch non presentano particolari difficoltà meritevoli di note, oltretutto non sono altro che riadattamenti considerando quanto già svolto nei progetti precedenti. Questo è ovviamente un aspetto positivo da considerare, perché è facilmente intuibile come i progetti che sono proposti in queste lezioni del Corso sono come tanti mattoni con cui poi si passa a progetti più evoluti che incrementano significativamente le varie funzionalità.

PS2 Controller e Arduino UNO

Un metodo alternativo per il controllo dei servo motori del Braccio Robot che vedremo nei prossimi progetti della Lezione 6, è quello che utilizza il Gamepad della Playstation, in particolare il PS2 Controller. In realtà il PS2 Controller può essere utilizzato per diversi progetti, ma lascio alla vostra fantasia eventuali ulteriori suoi impieghi con Arduino.

Non avendo la Playstation, per l’esecuzione dei progetti e per studiarne il funzionamento, ne ho dovuto comprare uno nuovo, anzi, facendo una ricerca su internet ho visto che il PS2 Controller viene venduto anche già compreso di modulo adattatore per Arduino.

Personalmente ho acquistato un PS2 Controller della DOIT, di tipo wireless, con frequenza radio di funzionamento a 2.4 GHz. Vi riporto alcune foto dell’acquisto:

Come potete osservare dalle foto, il modulo adattatore per Arduino non è altro che un connettore femmina per il modulo wireless del PS2 Controller a cui è stata saldata una breakout board rendendo disponibili i PIN che saranno utilizzati per interfacciarsi con Arduino.

Se non avete questo modulo di interfaccia non disperate, potete tranquillamente realizzarne una voi, ma vi occorrerà fare delle saldature, in basso vi metto la foto con i vari PIN:

I PIN colorati di azzurro sono quelli che andranno resi disponibili per Arduino. Attenzione all’alimentazione del modulo wireless è a 3,3V.

Per interfacciare il Gamepad della PS2 ad Arduino occorre una libreria specifica che si chiama: Arduino-PS2X.

I pulsanti disponibili sul Gamepad con i nomi assegnati nella libreria sono:

Il Controller PS2 utilizza un protocollo di comunicazione di tipo SPI, ovvero Serial Peripheral Interface normalmente su radiofrequenza a 2.4 GHz.

Sul sito della DOIT https://www.vvdoit.com/ suggeriscono il seguente collegamento:

Inoltre, sempre dal sito della DOIT ci vengono fornite alcune informazioni sulle precauzioni da adottare per il collegamento, nonché alcune informazioni generali che di seguito vi riporto tradotte dall’inglese e soprattutto dagli esperimenti che ho fatto:

  • L’alimentazione del Gamepad è indicata dal led rosso posto sul controller, nel caso fosse spento verificare che l’interruttore posto nella parte frontale sia nella posizione di ON:
  • Il modulo di interfaccia è anch’esso dotato di led rosso che se acceso indica la corretta alimentazione;
  • Quando i led non sono pienamente accesi, allora significa che ci sono probabili problemi di alimentazione (verificare innanzi tutto che il gamepad abbia le batterie cariche, le batterie utilizzate sono del tipo AAA).
  • Se il LED rosso sul Gamepad lampeggia significa che non c’è connessione tra il gamepad e la stazione ricevente.
  • Una volta eseguita la connessione tra Gamepad e modulo ricevente, il LED smette di lampeggiare e rimane fisso rosso;
  • Se la connessione tra gamepad e modulo ricevente non avviene al momento dell’alimentazione, provate a premere il pulsante di “START” sul Gamepad o qualsiasi altro tasto per innescare la comunicazione;
  • Fare molta attenzione nell’alimentazione del modulo ricevente, sia per la tensione di alimentazione (3,3V) che per il segno.

Vediamo ora come connettere la scheda PCA9685 ad Arduino. La connessione è molto semplice, vediamo il PIN out di Arduino (figura in basso)

Progetto 13: Uso del PS2 Controller con Arduino

Questo primo progetto con l’uso del Gamepad lo dedichiamo a conoscere il PS2 Controller connesso ad Arduino ed a fare un po’ di pratica con la parte coding.

Per utilizzare il PS2 Controller con Arduino abbiamo necessità della libreria Arduino-PS2X che potete scaricate cliccando sul seguente link Arduino-PS2X .

Cliccando sul link proposto accederete ad un’area su Github, come mostrato sotto:

Cliccando su Code e nel menu a tendina che compare, cliccate su Download ZIP

Una volta scaricato il file .zip, scompattatelo e copiate l’intera directory PS2X_lib che si trova all’interno di Arduino-PS2X-master, nella directory delle librerie di Arduino che per default si trova in Documenti/Arduino/.

A questo punto potete aprire l’IDE e vi risulterà istallata la nuova libreria.

Passiamo al progetto. Per questo progetto ci occorre:

Fate attenzione alla tensione di alimentazione del modulo ricevitore che è di 3,3V . Lo schema da realizzare è il seguente:

Versione descrittiva collegamenti:

Lo sketch da caricare su Arduino è il seguente:

Analisi dello sketch del Progetto 13 – Uso del PS2 Controller con Arduino

Ogni riga dello sketch è commentata, per cui non troverete difficoltà nel comprendere cosa fanno le singole istruzioni. Come potete osservare lo sketch del progetto è stato ricavato alleggerendo quello di esempio ed adattandolo alle nostre esigenze.

Progetto 14: Braccio Robot pilotato con PS2 Controller & Arduino

Per lo sviluppo di questo progetto uniremo le conoscenze acquisite per la scheda PCA0685 e quanto imparato sul Gamepad PS2 Controller. Piloteremo direttamente un Braccio Robot tramite Gamepad. Il metodo di controllo che utilizzeremo è quello che con alcuni tasti del Gamepad selezioniamo il servo che si desidera pilotare e poi con i tasti di giù, su, destra e sinistra, invece piloteremo la rotazione del servo selezionato.

La fgura sotto mostra l’associazione tra tasti Gamepad e Servo con  i relativi movimenti:

Per questo progetto ci occorre:

Lo schema da realizzare è il seguente:

Per una migliore comprensione dei collegamenti, riportiamoli anche in modo descrittivo  e tabellare:

Per quanto riguarda i PIN dei servo presenti sulla Scheda PCA9685, ad essi andranno collegati i singoli servomotori del braccio robot come mostrato in figura, facendo attenzione ai colori che ricordo: cavetto di colore arancione – segnale, cavetto di colore rosso – Vcc e cavetto di colore marrone – GND.

Per lo sketch da caricare su Arduino:

Il Video Progetto che segue mostra tutti i passaggi in dettaglio.

Analisi dello sketch del Progetto 14 – Braccio Robot pilotato con PS2 Controller

A prima vista sembra complicato, ma in realtà lo sketch è composto solo da cicli di controllo con degli “if” e il gioco è fatto!. Infatti volendo schematizzare in modo banale quello che fa il nostro sketch, lo possiamo rappresentare così:

Ogni riga dello sketch è commentata, per cui non troverete difficoltà nel comprendere cosa fanno le singole istruzioni.

Con questo progetto termina la Lezione 6, ovviamente, come dico sempre, le mie proposte di progetto servono solo a solleticare la vostra curiosità e devono essere visti non come punti di arrivo, ma come punti di partenza, per cui se avete suggerimenti o se vi va di migliorare ciò che ho proposto, sentitevi liberi di farlo e se avete bisogno di aiuto contattatemi all’indirizzo info@bemaker.org .

Se hai trovato la lezione interessante fai una donazione mi aiuterai a realizzarne tante altre.