Vi piace il mio braccio?? :D

Rieccomi… Volevo farvi vedere il mio primo skatch funzionante, grazie ai vostri consigli… :smiley:

byte pwm_1 = 3; //Pin Velocità motore 1
byte pwm_2 = 11; //Pin Velocità motore 2
byte pwm_3 = 5; //Pin Velocità motore 3
byte pwm_4 = 6; //Pin Velocità motore 3
byte pwm_5 = 10; //Pin Velocità motore 4
byte dir_1 = 12; //Pin Direzione motore 1
byte dir_2 = 13; //Pin Direzione motore 2
byte dir_3 = 8; //Pin Direzione motore 3
byte dir_4 = 9; //Pin Direzione motore 4
byte dir_5a = 2; //Pin Direzione moore 5
byte dir_5b = 7; //Pin Direzione motore 5
byte stato_1 = 0; //Stato direzione morore 1
byte stato_2 = 0; //Stato direzione morore 2
byte stato_3 = 0; //Stato direzione morore 3
byte stato_4 = 0; //Stato direzione morore 4
byte stato_5 = 0; //Stato direzione morore 5
byte command = 0; //Comando per movimento
byte pwm_speed = 255; // Velocità motori
unsigned long time_pause = 0; //parametro per pausa
boolean esci = false; //uscita da ciclo while

void setup()
{
  // Inizio comunicazione seriale a 9600
  Serial.begin(9600);
  pinMode(pwm_1, OUTPUT);
  pinMode(pwm_2, OUTPUT);
  pinMode(pwm_3, OUTPUT);
  pinMode(pwm_4, OUTPUT);
  pinMode(dir_1, OUTPUT);   
  pinMode(dir_2, OUTPUT);
  pinMode(dir_3, OUTPUT);
  pinMode(dir_4, OUTPUT);
}

void loop()
{
  if (Serial.available() > 0) { //Se sono presenti dati nel buffer
    leggi_seriale(); //li leggo con la funzione
  }
  switch (command) { //Switch sul comando
  case 'q':
    if (stato_1 == 0) 
    {  
      pausa();
      analogWrite(pwm_1, pwm_speed);
      digitalWrite(dir_1, LOW); 
      Serial.println("Chiude pinza");
      stato_1 = 1;
      command = 0;
      break; 
    }
    else if (stato_1 == 1)
    {
      pausa();
      analogWrite(pwm_1, pwm_speed);
      digitalWrite(dir_1, HIGH);
      Serial.println("Apre pinza");
      stato_1 = 0;
      command = 0;
      break;  
    }
  case 'w':    
    if (stato_2 == 0) 
    {  
      analogWrite(pwm_2, pwm_speed);
      digitalWrite(dir_2, LOW); 
      Serial.println("Scende braccio 1");
      stato_2 = 1;
      command = 0;
      pausa();
      break; 
    }
    else if (stato_2 == 1)
    {
      analogWrite(pwm_2, pwm_speed);
      digitalWrite(dir_2, HIGH);
      Serial.println("Sale braccio 1");
      stato_2 = 0;
      command = 0;
      pausa();
      break;  
    }
  case 'e':    
    if (stato_3 == 0) 
    {  
      analogWrite(pwm_3, pwm_speed);
      digitalWrite(dir_3, LOW); 
      Serial.println("Sale braccio 2");
      stato_3 = 1;
      command = 0;
      pausa();
      break; 
    }
    else if (stato_3 == 1)
    {
      analogWrite(pwm_3, pwm_speed);
      digitalWrite(dir_3, HIGH);
      Serial.println("Scende braccio 2");
      stato_3 = 0;
      command = 0;
      pausa();
      break;  
    }
  case 'r':    
    if (stato_4 == 0) 
    { 
      analogWrite(pwm_4, pwm_speed);
      digitalWrite(dir_4, LOW); 
      Serial.println("Scende braccio 3");
      stato_4 = 1;
      command = 0;
      pausa(); 
      break; 
    }
    else if (stato_4 == 1)
    {
      analogWrite(pwm_4, pwm_speed);
      digitalWrite(dir_4, HIGH);
      Serial.println("Sale braccio 3");
      stato_4 = 0;
      command = 0;
      pausa();
      break;  
    }
  case 't':    
    if (stato_5 == 0) 
    {  
      analogWrite(pwm_5, pwm_speed);
      digitalWrite(dir_5a, LOW);
      digitalWrite(dir_5b, HIGH); 
      Serial.println("Gira a destra");
      stato_5 = 1;
      command = 0;
      pausa();
      break; 
    }
    else if (stato_5 == 1)
    {
      analogWrite(pwm_5, pwm_speed);
      digitalWrite(dir_5a, HIGH);
      digitalWrite(dir_5b, LOW); 
      Serial.println("Gira a sinistra");
      stato_5 = 0;
      command = 0;
      pausa();
      break;   
    }
  case '1':
    pausa();
    analogWrite(pwm_1, 0);
    analogWrite(pwm_2, 0);
    analogWrite(pwm_3, 0);
    analogWrite(pwm_4, 0);
    analogWrite(pwm_5, 0);
    Serial.println("Stop!");
    command = 0;
    break;
  case 's':
    Serial.print ("Pwm impostato a: ");
    Serial.println (pwm_speed, DEC);
    command = 0;
    break;
  case 'a':
    delay(250);
    command =0;
    break;
  case 'p':
    String command_string = String(5);
    command_string = "";
    byte cont = 0;
    char char_in[3];
    Serial.println("Modalità di programmazione..");
    Serial.println("Inserire valore pwm");
    command = 0;
    esci = false;
    Serial.flush();
    while (esci == false) {
      if (Serial.available()>0) {
        while (Serial.available()>0) {
          char_in[cont] = Serial.read();
          cont ++;
          delay(5);
        }
        for (int i =0; i <= cont-1; i++) {
          command_string =command_string + char_in[i];
        }
        char buf[4];
        command_string.toCharArray(buf, 4);
        //if (command != 0) {
        pwm_speed = atoi(buf);
        Serial.print ("Velocità impostata a ");
        Serial.println (pwm_speed, DEC);
        command_string = "";
        cont = 0;
        esci = true;
      }
    }
  }
}

void leggi_seriale(){
  String command_string = String(10);
  command_string = "";
  byte cont = 0;
  char char_in[10];
  if (Serial.available()>0) {
    command = Serial.read();
    delay(2);
    while (Serial.available()>0) {
      char_in[cont] = Serial.read();
      if (char_in[cont]== ';'){
        break;
      }
      cont ++;
      delay(2);
    }
    for (int i =0; i <= cont; i++) {
      command_string =command_string + char_in[i];
    }
    char buf[cont+1];
    command_string.toCharArray(buf, cont+1);
    time_pause = atoi(buf);
  }
  command_string = "";
  cont = 0;
}

void pausa(){
  delay(time_pause);
  time_pause=0;
}

In sostanza comanda un braccio robotizzato (http://www.thinkgeek.com/geektoys/science/b696/) in base ai comandi ricevuti tramite seriale. La sintassi prevista è:
qyyy;wyyy;eyyy; ecc…
Dove x, s e g sono i comandi per indicare quale motore attivare; mentre yyy è la variabile per la pausa. Non è obbligatoria inserirla ma può andare da 1 al valore massimo assegnabile alla funzione delay!
Lista comandi;
q = Apre/Chiude pinza
w = Alza/Abbassa braccio 1
e = Alza/Abbassa braccio 2
r = Alza/Abbassa braccio 3
t = Gira a destra/sinistra il braccio
1 = Arresta tutto
s = Restituisce il valore impostato ai PWM
a = Pausa predefinita di 250ms
p = Imposta velocità pwm
; = Separa un comando dall’altro
Purtroppo il braccio è azionato da motori a spazzole tipo mini 4wd (Avviso di reindirizzamento) ed è quindi impossibile essere a conoscenza della posizione! All’inizio, alla fine e durante gli spostamenti. Per questo ho usati i tempi per avere una gestione almeno approssimativa della cosa! Cosa che tra l’altro fà anche la scheda usb originale del robot… (http://www.futuraelettronica.net/pdf_ita/8220-KSR10$USB.pdf http://www.youtube.com/watch?v=HpQH-ePQ4D4)
Spero non manchi niente, appena riesco metto qualche foto/video! Ciao…

Pur troppo non riesco a vedere le immagini x colpa di questa internet del c**** il codice complesso sembra ben fatto bel lavoro:)

fantastico!!! sarebbe bello anche comandarlo tramite il nunchuck della wii?? cmq davvero complimenti!!!

Grazie a tutti.. Si, è quello che mi piacerebbe fare! Mi manca solo il nunchuck, ma per pochi € dovrei trovarlo non originale! Manca solo l'accensione del led, ma non mi interessa più di tanto. Visto che è la mia prima esperienza di C/C++ e Arduino, c'è qualche cosa da migliorare? Forma, formule..

qualcosa da migliorare? tieniti stretto :D

1: ogni motore ha 3 valori: velocità, direzione e stato direzione. Raccoglili in una struttura (struct) 2: a questo punto puoi fare un array di strutture, ogni elemento nell'array rappresenta un motore 3: a questo punto gran parte del codice (come il contenuto di setup() ) diventa riscrivibile con un for anzichè scrivere l'istruzione per ogni motore! 4: nel loop(), il contenuto di quasi tutti i casi delle select può essere scitto in funzione, che accetta come parametro l'indice nell'array del motore da modificare e il nuovo valore(se necessario) 5: in generale evita di riscrivere 1000 volte lo stesso comando (per esempio command=0), piuttosto scrivilo fuori dal select, che lo scrivi una volta e vale per tutti. 6: in generale cerca di evitare l'uso di variabili globali, mi sembra che qu' hai agito bene. Variabili che sai non verranno modificate in runtime (come pwm_speed) dichiarale con una DEFINE, risparmi clock e ram. Stessa cosa vale per cose come char_in[10]: non hardcodere il 10, metti una variabile che poi definisci con una DEFINE come sopra.

Questi sono i suggerimenti per rendere più facile la manutenzione, leggibilità e "peso" in byte del codice: se trovi un errore nelle funzioni dello switch non devi ripetere la correzione per ogni case, evitando di dimenticarse uno per strada dando origine ad un bug ancora più bastardo. In oltre, se cambi la struttura dei motori lo fai una volta per tutti e vale anche il discorso di cui sopra.

dopo edito il messaggio e ti posto alcuni errori che ho trovato nella funzione "leggi_seriale()"

allora parte 2: è buona cosa evitare come la peste i break, tranne negli switch(), spesso il codice diventa più leggibile... infatti nella funzione dove leggi la seriale c'è un bug:

while (Serial.available()>0) {
      char_in[cont] = Serial.read();
      if (char_in[cont]== ';'){
        break;
      }
      cont ++;
      delay(2);
    }

sembra ok a prima vista, leggi un carattere alla volta fino al raggiungimento di ;.... invece no! cosa succedese arrivno i primi caratteri del comando ma i successivi impiegano >2ms? che esci ddal ciclo con un comando incompleto! (cosa che il codice successivo NON gestisce) risolvi così:

boolean fineInput=false;
while ( !fineInput ) {

      if (Serial.avaiable()>0){
          char_in[cont] = Serial.read();
          if (char_in[cont]!=';'){
              cont ++;
          }else{
              char_in[cont] = '\0'; //carattere di fine stringa, da mettere sempre! se no le funzioni per le stringhe tipo atoi() impazziscono!
              fineInput=true;
          }
      }
      delay(2);
    }

altro bug: tu butti il comando ricevuto in atoi() senza prima controllare che i caratteri siano tutti numeri... il controllo lo puoi fare nel primo if.

Altra imprecisazione: l'eggi il comando in un array di char, poi lo butti in una stringa, poi copi la stringa in un array di char... INUTILE! basta che ti ricordi di mettere a fine del primo array lo '\0' e puoi buttare in atoi l'array, senza passare per l'oggetto stringa e il secondo array

Terzo bug: Non controlli che l'input non mandi in overflow l'array di char (ovvero che ricevi più di 9 caratteri, il 10° carattere serve per lo '\0')

altro particolare: se non arriva il ';' rimani bloccato nel while, cosa che vogliamo evitare... puoi rendere l'array di char globale, fare una atoi solo quando ricevi il ';', l'array viene svuotato quando fai la atoi o quando ricevi un'eccezione (carattere non valido o overflow array)

Lesto :wink:
Io organizzerei il codice in modo ancora più radicale :wink:

#define MotorCount 5
#define CommandCount 5

struct tagMotorConfiguration
{
   byte pwm;
   byte direction;
   byte status;
   byte delta;
};
typedef tagMotorConfiguration MotorConfiguration;
typedef MotorConfiguration *PMotorConfiguration;
typedef MotorConfiguration &RMotorConfiguration;

MotorConfiguration Motor[MotorCount];

typedef int (*CommandHandler)(RMotorConfiguration);

CommandHandler commandHandler[CommandCount];

byte command = 0; //Comando per movimento
byte pwm_speed = 255; // Velocità motori
unsigned long time_pause = 0; //parametro per pausa
boolean esci = false; //uscita da ciclo while

int comandiPinza(MotorConfiguration & motor)
{
  pausa();
  analogWrite(motor.pwm, pwm_speed);
  if (motor.status == 0) 
  {  
    digitalWrite(motor.direction, LOW); 
    Serial.println("Chiude pinza");
    motor.status = 1;
  }
  else if (motor.status ==1)
  {
    digitalWrite(motor.direction, HIGH);
    Serial.println("Apre pinza");
    motor.status = 0;
  }
  return 0;
}

void setup()
{
  // Inizio comunicazione seriale a 9600
  Serial.begin(9600);
  memset(Motor,sizeof(Motor)*MotorCount,NULL);
  Motor[0].pwm = 3;  //Pin Velocità motore 1
  Motor[1].pwm = 11; //Pin Velocità motore 2
  Motor[2].pwm = 5;  //Pin Velocità motore 3
  Motor[3].pwm = 6;  //Pin Velocità motore 3
  Motor[4].pwm = 10; //Pin Velocità motore 4
  
  Motor[0].direction = 12;  //Pin Direzione motore 1
  Motor[1].direction = 11;  //Pin Direzione motore 2
  Motor[2].direction = 8;   //Pin Direzione motore 3
  Motor[3].direction = 9;   //Pin Direzione motore 3
  Motor[4].direction = 2;   //Pin Direzione motore 4
  Motor[4].delta = 5;   //Pin Direzione motore 4

  for (int motor = 0; motor<MotorCount; motor++)
  {
     pinMode(Motor[motor].pwm, OUTPUT); 
     pinMode(Motor[motor].direction, OUTPUT); 
  }
  for (int handler = 0; handler < CommandCount; handler++)
   commandHandler[handler] = NULL;
   
  commandHandler[0] = comandiPinza;
}

void loop()
{
  if (Serial.available() > 0)  //Se sono presenti dati nel buffer
  { 
    leggi_seriale(); //li leggo con la funzione
  }
  switch (command) 
  { //Switch sul comando
  case 'q':  commandHandler[0](Motor[0]); break;

:grin:
Se poi si spostano i pezzi in vari file è più comodo gestirli.

Complimenti !
il braccio l’ho visto alcuni giorni fa e avevo subito pensato all’abbinamento con Arduino ! … effettivamente il punto deble sono i motori

se vi interesa il mio collega l’ha acquistato alla città del sole a 48,00 €

Rispondo uno alla volta…

zaio73:
Complimenti !
il braccio l’ho visto alcuni giorni fa e avevo subito pensato all’abbinamento con Arduino ! … effettivamente il punto deble sono i motori

se vi interesa il mio collega l’ha acquistato alla città del sole a 48,00 €

Eh, averlo saputo! L’ho preso alla fiera dell’elettronica da Futuraelettronica per circa 62€, che è anche il prezzo del sito! Prezzo più alto del mondo porca p…a!!!

Stilgar:
Lesto :wink:
Io organizzerei il codice in modo ancora più radicale :wink:

#define MotorCount 5

#define CommandCount 5

struct tagMotorConfiguration
{
  byte pwm;
  byte direction;
  byte status;
  byte delta;
};
typedef tagMotorConfiguration MotorConfiguration;
typedef MotorConfiguration *PMotorConfiguration;
typedef MotorConfiguration &RMotorConfiguration;

MotorConfiguration Motor[MotorCount];

typedef int (*CommandHandler)(RMotorConfiguration);

CommandHandler commandHandler[CommandCount];

byte command = 0; //Comando per movimento
byte pwm_speed = 255; // Velocità motori
unsigned long time_pause = 0; //parametro per pausa
boolean esci = false; //uscita da ciclo while

int comandiPinza(MotorConfiguration & motor)
{
  pausa();
  analogWrite(motor.pwm, pwm_speed);
  if (motor.status == 0)
  { 
    digitalWrite(motor.direction, LOW);
    Serial.println(“Chiude pinza”);
    motor.status = 1;
  }
  else if (motor.status ==1)
  {
    digitalWrite(motor.direction, HIGH);
    Serial.println(“Apre pinza”);
    motor.status = 0;
  }
  return 0;
}

void setup()
{
  // Inizio comunicazione seriale a 9600
  Serial.begin(9600);
  memset(Motor,sizeof(Motor)*MotorCount,NULL);
  Motor[0].pwm = 3;  //Pin Velocità motore 1
  Motor[1].pwm = 11; //Pin Velocità motore 2
  Motor[2].pwm = 5;  //Pin Velocità motore 3
  Motor[3].pwm = 6;  //Pin Velocità motore 3
  Motor[4].pwm = 10; //Pin Velocità motore 4
 
  Motor[0].direction = 12;  //Pin Direzione motore 1
  Motor[1].direction = 11;  //Pin Direzione motore 2
  Motor[2].direction = 8;  //Pin Direzione motore 3
  Motor[3].direction = 9;  //Pin Direzione motore 3
  Motor[4].direction = 2;  //Pin Direzione motore 4
  Motor[4].delta = 5;  //Pin Direzione motore 4

for (int motor = 0; motor<MotorCount; motor++)
  {
    pinMode(Motor[motor].pwm, OUTPUT);
    pinMode(Motor[motor].direction, OUTPUT);
  }
  for (int handler = 0; handler < CommandCount; handler++)
  commandHandler[handler] = NULL;
 
  commandHandler[0] = comandiPinza;
}

void loop()
{
  if (Serial.available() > 0)  //Se sono presenti dati nel buffer
  {
    leggi_seriale(); //li leggo con la funzione
  }
  switch (command)
  { //Switch sul comando
  case ‘q’:  commandHandler0; break;



:grin:
Se poi si spostano i pezzi in vari file è più comodo gestirli.

Cavolo… Alla faccia del ridimensionamento!! Lo leggo con calma e vedo di capire come funziona! Grazie…

@lesto:
Grazie dei consigli. Ora non ho molto tempo, ma appena riesco metto in pratica tutto, o almeno il più possibile! Anche perchè questo è il progetto ““entry-level”” per imparare i comandi e la comunicazione seriale per poi applicare il tutto al mio cingolato per ora morto!! Cosa Vuol dire “hardcodere”? Mi sfugge…

Grazie a tutti!

Ciao rubino25, se al posto dei caratteri fai uscire dei numeri, puoi evitare lo switch case. LeggiSeriale potrebbe emettere i codici da usare come indice per chiamare le singole funzioni di elaborazione. In questo modo riesci a ridurre il codice, ulteriormente, e con le funzioni delegate puoi fare un pochino quello che ti pare alla fine ;)

Se hai bisogno di aiuto per il codice, chiedi ;)

stilgar intendi un array di funzioni?

Si,
con l’array di funzioni si potrebbe pure fare una stima dei tempi di elaborazione.
Per ogni funzione c’è solo il costo del jump che il processore dovrebbe fare.
Ora con lo switch case, l’ultimo step è quello che ci mette di più a partire.
Ma qui siamo nel campo delle “pippe mentali” :wink:

Mhh… interessante anche questo. Un array di funzioni sarebbe? Gli array so cosa sono, le funzioni anche… Messe insieme formano?? Scusate ma è da una settimana che mi cimento in nel C… Quindi mi mancano MOOOOLTE conoscenze!! =)

Dal punto di vista (moooolto) low level. L'array di funzioni è un array di interi. (Puntatori) Solo che vengono utilizzati per effettuare chiamate. Come tutto quello che è in memoria, dipende come lo interpreti.

Per farti intuire cosa succede, se vedessimo il codice in finto assembly

CALL funzione1

Con gli array di funzioni hai una cosa del tipo

CALL [2347289423]

;) Vantaggi e svantaggi della soluzione con gli array di funzione. Svantaggi: Tra 4 mesi, hai sicuramente meno leggibilità del codice, e devi leggerti tutto prima di capire bene cosa stai facendo.

Vantaggi: Sicuramente il codice è più modulare. Espandi il numero di funzioni chiamabili espandendo l'array. La "complessità" di chiamata per il processore rimane pressochè costante al crescere del numero di comandi eseguibili. Non hai la selva di IF/THEN/ELSE SWITCH/CASE dell'approccio ... "impulsivo" (??).

Diciamo, in estrema sintesi, che ti stai rifacendo un pezzettino di Tabella dei metodi delle classi C++ ;)

IMHO se non sai cos'è un array o una funzione, scordati gli array di funzioni :grin: rima segui qualche guida sul C, anche le più basiche parlano di funzioni e array. Poi passi ai puntatori (concetto mooolto importante, finchè non li "domini" inutile andare avanti), allocazione dinamica della memoria, etc etc... POI puoi passare agli array di funzione

:grin: :grin: :grin: Cattivo

Grazie per il chiarimento.. No, no.. Array e funzioni sò cosa sono. Solo volevo essere sicuro di come le intendesse insieme!! =) Prima del finesettimana non riesco a provare niente di nuovo, quindi non ve la prendete..! =D

Stò partendo dalle cose più semplici… Per ora sistemo la funzione per la lettura dei dati…

void leggi_seriale(){
  byte cont = 0;
  char char_in[10];
  esci == false;
  if (Serial.available()>0) {
    command = Serial.read();
    delay(2);
  }
  while (esci == false) {
    if (Serial.available()>0) {
      Serial.println("Lettura variabile");
      char_in[cont] = Serial.read();
      if (char_in[cont] != ';') {
        Serial.println("Incremento contatore");
        cont ++;
      }
      else {
        Serial.println("Fine stringa");
        char_in[cont] == '/0';
        //esci == true;
        break;
      }
      delay(2);
    }
  }
  Serial.println("Uscito dal ciclo while");
  time_pause = atoi(char_in);
  Serial.println(time_pause, DEC);
  cont = 0;
}

Problema: perchè se metto “break;” il ciclo while termina correttamente mentre se setto esci == true no? Se imposto esci il ciclo si ferma ma non viene impostato nessun comando!

//esci == true;????

prova con

esci = true

Per le specifiche c/c++ il comando echi == true è un confronto, ma non è un errore di sintassi. Non ha senso logico impostare in test in una sequenza di comandi, ma il compilatore è di bocca buona :D Di solito l'errore è il contrario (hihi) durante il test si esegue un'assegnazione ;)

Che idiota!! =( E si che nell'altro while l'avevo fatto giusto!! Grazie..