Creative Commons BY-NC-ND 2.5Questo sito e tutto il suo contenuto sono distribuiti sotto la licenza Creative Commons Attribuzione - Non Commerciale - Non opere derivate 2.5 Italia e con le condizioni d'uso definite nel disclaimer: siete pregati di leggere entrambi questi documenti prima di usufruire dei contenuti di questo sito. Per alcuni contenuti è necessaria una registrazione gratuita: non è necessario pagare e non è necessario accumulare punteggi per accedere agli articoli e scaricare i sorgenti. Basta solo essere onesti. Se volete che questo sito continui a rimanere attivo, a contribuire ogni giorno alla diffusione della cultura libera, non copiate il materiale per ripubblicarlo in altri luoghi : chi fa questo è solo un miserabile e un perdente. Se volete partecipare su settorezero e rendere le vostre idee, i vostri progetti, fruibili da tutti senza limitazioni, come dovrebbe essere in un paese civile e acculturato, potete farlo tranquillamente.

Corso programmazione PICMicro in C – Approfondimenti – Pilotare un servocomando usando un trimmer

Autore: Giovanni Bernardo | Data pubblicazione: 17 aprile 2011
Categorie: PICmicro 10/12/16

Abbiamo visto in un articolo precedente cos’è un servocomando e soprattutto come deve essere fatto il segnale per poterlo pilotare. Se non avete letto quell’articolo vi consiglio di farlo prima di continuare. Riassumo in ogni caso le caratteristiche che deve avere il segnale di pilotaggio:

  • Deve avere una frequenza di 50Hz, ovvero un periodo di 20mS
  • Il livello logico alto deve avere una durata variabile tra 500μS (servo tutto girato in un verso) e 2500μS (servo tutto girato nel verso opposto). Questi due valori estremi vanno bene per quei servocomandi che sono in grado di eseguire una rotazione di 180° (la stragrande maggioranza)
  • Il segnale deve essere inviato di continuo affinchè il servo, sotto sforzo, possa mantenere la sua posizione

Dobbiamo quindi generare un’onda quadra, tenendola a livello alto per il tempo necessario ad impostare un determinato valore di rotazione e quindi a livello basso per il tempo rimanente per ottenere un periodo di 20mS. E’ una cosa abbastanza semplice da realizzare sfruttando ritardi e cambiamenti di stato logico del pin al quale è connesso il cavo segnale del servo.

Nell’esempio allegato vi mostro come è semplice far ruotare un servocomando in base alla rotazione di un trimmer. Il programma è scritto come sempre in Hitech-C (9.81) per pic16F877A quarzato a 20MHz, montato su FreedomII. Andremo quindi a sfruttare il trimmer collegato alla porta AN1 eseguendo tutte le impostazioni del caso come già imparato.

Il valore restituito dal convertitore A/D viene memorizzato nella variabile ADval, prima di impostare il servo vengono eseguite due letture e quindi eseguita la media sfruttando un bitshift di 1 posizione verso destra, che abbiamo imparato serve a dividere per due. La durata del livello logico alto per controllare il servo è memorizzata nella variabile Pulse ed è un valore che deve variare da 500 a 2500.

Dobbiamo quindi trovare un sistema per far corrispondere la dinamica di valori fornita dal convertitore A/D (0÷1023) nel range di valori da sfruttare per il servo (500÷2500). Cominciamo col notare che il range di azione del servo è di 2500-500 = 2000μS. Basta quindi eseguire una proporzione per “trasformare” il valore letto dal modulo ADC in un valore di μS da assegnare al servo:

Il valore di Pulse in base al valore di ADval sarà quindi dato da:

(1)

A tale valore andrà quindi aggiunto 500 per ottenere un valore tra 500 e 2500:

(2)

C’è da notare una cosa. Dichiaro le variabili Pulse e ADval come unsigned int, per cui si tratta di valori a 16bit. Eseguendo l’operazione definita dalla [1], a meno che ADval non valga 1023, otterrò sempre zero come risultato. Ricordo difatti che in C una divisione tra interi restituisce sempre un numero intero per cui con valori di ADval minori di 1023 la frazione varrà sempre 0 virgola qualcosa e quindi verrà sempre restituito un valore pari a zero. La [1] quindi mi serve unicamente per rilevare il trimmer girato tutto verso 5V, che mi restituisce il valore 1023. Potete anche fare la prova: girando il trimmer, il servo rimarrà sempre tutto da un lato fino a che non raggiungete l’estremità e quindi il servo si sposterà completamente in direzione opposta.

Dobbiamo quindi recuperare i valori intermedi. Nulla di più facile utilizzando l’operatore resto della divisione (%). Dopo aver eseguito la [1] dobbiamo sommare la parte decimale:

(3)

L’operazione che stiamo eseguendo è in pratica la stessa eseguita nella [1] per trovare la proporzionalità tra valore letto dall’A/D e valore da assegnare il servo, l’unica differenza è che stiamo usando l’operatore % per trovare il resto della divisione e quindi moltiplichiamo per 2 anzichè per 2000 perchè il resto della divisione è in realtà la parte millesimale (le 3 cifre dopo la virgola). Dopo aver eseguito la [1] e la [3] possiamo quindi aggiungere le 500 unità con la [2].

Possiamo infine creare il segnale con una semplicissima sequenza di ritardi:

// impulso positivo al servo
SERVO=1;
// per la durata calcolata in base alla posizione del trimmer
DelayBigUs(Pulse); // DelayBigUs accetta un INT come argomento (0-65535)
// impulso negativo
SERVO=0;
// per il resto del tempo che manca per arrivare a 20mS (50Hz)
DelayBigUs(20000-Pulse);

La funzione DelayBigUs è contenuta nelle routine di delay enhanced precision del sito MicrochipC.com.

Il ritardo ottenuto con queste routine è preciso e possiamo osservare all’oscilloscopio la bontà delle funzioni che vi ho appena esposto. Con il trimmer tutto girato da un lato possiamo osservare la pulsazione da 500μS (0.5mS):

Mentre girando tutto il trimmer nella direzione opposta:

Alcune raccomandazioni:

  • Il servo deve essere alimentato preferibilmente con una tensione diversa da quella che usate per alimentare il PIC. Potete anche usare la stessa linea di alimentazione ma predisporre un regolatore separato per i servocomandi. I servocomandi funzionano da 5 a 6V. Ovviamente a 6V forniscono il massimo valore di coppia. Se dovete acquistare un regolatore consiglio un 7806CV che è in grado di fornire fino a 2A. Se usate la stessa indentica linea di alimentazione potrete notare (ma non è sempre detto) come i disturbi generati dal servo fanno impazzire il pic che a sua volta invierà dei segnali di comando sbagliati facendo impazzire il servo.
  • Se usate due alimentatori separati non dimenticate di mettere le masse in comune.
  • Se agli estremi di rotazione notate che il servo fischia o fa molto rumore, fatelo tornare indietro: non è fatto per raggiungere quella posizione e rimanerlo così ne potrebbe causare la rottura.
  • Il codice è scritto per Hitech-C versione da 9.81 a salire. Se il codice così come l’ho scritto vi crea problemi e state impazzendo vuol dire che non avete letto questo. Comunque sia dato che una piccola percentuale legge col prosciutto davanti agli occhi ho messo tra le note del sorgente le poche modifiche da fare per farlo funzionare con le vecchie versioni (mannaggia a voi che non vi aggiornate!).
  • Ovviamente se il vostro programma deve eseguire tanta altra roba nel main, questo sistema potrebbe non essere buono in quanto i ritardi tra l’invio di un segnale e il successivo aumenterebbero di molto. In questo caso vi conviene utilizzare un sistema che piloti i servo sfruttando l’interrupt. Ovviamente più avete un Fosc elevato e più risoluzione potete ottenere.

Download

PDFComandare un servocomando con un trimmer (10.6 KB - 274 downloads)
L'articolo ti è piaciuto o ti è stato utile per risolvere un problema? SettoreZero è realizzato soltanto contenuti originali: tutti gli articoli sono curati con passione dagli autori e nulla viene copiato da altri siti. Supporta e mantieni in vita SettoreZero con una donazione: basta soltanto un caffè o una birra. Puoi supportare SettoreZero anche con uno dei progetti elencati nella sezione servizi o partecipare anche tu con un tuo articolo/progetto personale.

Se desiderate che SettoreZero continui a rimanere gratuito e fruibile da tutti, non copiate il nostro materiale e segnalateci se qualcuno lo fa.

Puoi andare alla fine dell'articolo e lasciare un commento. I trackback e i ping non sono attualmente consentiti.

  1. #1 da Cristianoscr il 20 aprile 2011

    Nel tuo primo articolo sui servocomandi, i uS dei tre punti 0-90-180 non avevi detto che erano 1000uS-1500uS (centro) – 2000uS ?? Hai apportato delle correzioni?

    • #2 da Giovanni Bernardo il 20 aprile 2011

      Non ho detto assolutamente così, ammetto comunque che posso aver creato un po’ di confusione ma tutto era per rimanere in margini di sicurezza. Mi spiego meglio: i tempi 1000-1500-2000 sono riferiti all’escursione 45° – 90 ° – 135 (o 45 a sinistra – 0 – 45° a destra : 90° in totale NO 90° per lato! Forse ti sei confuso con questo). Cioè l’impulso da 1000 a 2000 vale per i servo che hanno una escursione massima di 90° (45 a destra e 45 a sinistra dalla posizione centrale che richiede 1500uS). Però quasi tutti i servocomandi accettano da 500 a 2500 e fanno una rotazione di 180° (90 a destra e 90 a sinistra). I servocomandi buoni (Hitech per esempio) non hanno problemi a fare i 180° ma quelli economici li senti che arrivati ai margini incominciano a fare rumore, per tale motivo ho specificato la questione che 1000-2000 vale per l’escursione di 90° (ma in totale! cioè 45-0- (-)45) e con questa stai sicuro con tutti i servocomandi, ma oramai vanno tutti da 500 a 2500 anche se quelli economici sforzano ai margini e quindi, dopo aver fatto delle prove, ti rendi conto se davvero ci puoi arrivare agli estremi. Ci sono pure alcuni servo speciali che fanno rotazioni ancora più estese ma in ogni caso la posizione centrale è sempre data dall’impulso di 1500, poi ogni 500uS hai 45° di rotazione… basta ricordarsi solo di questo e quindi fare delle prove con i servocomandi che uno ha per capire fino a che punto possono arrivare.

  2. #3 da bolivazio il 26 luglio 2011

    Ciao Giovanni,
    utilizzando la libreria di ritardo che hai allegato hai avuto modo di sperimentare qualche bug a particolari valori di PW? Io ho preso spunto dal tuo articolo e avevo recuperato una liberia con DelayBigUs su internet. Sembrava funzionare tutto correttamente ma mi sono reso conto che per alcuni puntuali valori di PW avviene qualche cosa che non ho ancora determinato con esattezza che allunga il periodo (si riduce la frequenza da 49.8 Hz a 49.2 Hz) e il servo si posiziona in maniera errata (suppongo sia variato il duty cicle). Al di fuori di questo punto specifico l’algoritmo funziona correttamente e il servo si posiziona come dovrebbe (visivamente, se fai uno sweep di PW, noti un salto del servo che si riposiziona correttamente all’avanzare della spazzata di PW).
    Mi viene da pensare che ci sia un “bug” nelle routine di delay che ho usato che a particolari valori di input sballano il ritardo causando una variazione di frequenza e di duty cicle. Hai avuto modo di sperimentare un malfunzionamento analogo?

    • #4 da Giovanni Bernardo il 26 luglio 2011

      Io le prove le ho fatte con l’oscilloscopio collegato sulla linea del segnale e non ho notato nulla di strano.

      • #5 da bolivazio il 26 luglio 2011

        Giovanni ho fatto anche io una verifica con l’oscilloscopio dopo aver visto “salti” del servo facendo la spazzata.
        Farò una prova con la libreria che hai allegato tu perchè probabilmente è diversa da quella che ho scaricato altrove.
        Prima di sostituire la libreria volevo capire se era un problema già noto.

        • #6 da Giovanni Bernardo il 26 luglio 2011

          I salti sono causati da disturbi sulla linea. Hai usato un regolatore di tensione separato per il servo o stai usando lo stesso regolatore sia per il pic che per il servo?

          • #7 da bolivazio il 26 luglio 2011

            Il Pic e il servo hanno alimentazioni separate (hanno in comune solo la massa).
            Il fatto è che il salto che ti descrivo non è aleatorio: avviene sempre a specifici valori di PW (di Pulse, per intenderci) e la cosa interessante è che il segnale in quella situazione è stabile (in frequenza e Duty… non è rumore)… tant’è che anche il servo rimane stabilmente in quella posizione finchè non vario il valore di Pulse. Tanto per completezza aggiungo che pensando potesse essere il servo (disturbi elettromagnetici o problemi elettromeccanici) ho fatto una prova a vuoto (staccando fisicamente il servo) e il comportamento è identico… quindi non è il servo (che per la cronaca è un Hitec HS-55).
            La soluzione più ovvia che mi viene in mente è “ammazzare” quei due valori di pulse a cui si verifica il fattaccio… ma visto che sono testardo voglio andare fino in fondo e capire cosa crea questa anomalia.

  3. #8 da bolivazio il 26 luglio 2011

    Giovanni,
    Ho scoperto il problema.
    La libreria mi sembra identica a quella che hai usato tu.
    I valori di PW a cui c’è il malfunzionamento (almeno a me) sono 1280 e 1536.
    Se li rappresenti in binario (e poi ti dico perchè) questi sono:
    1280: 0b10100000000
    1536: 0b11000000000
    Hanno entrambi gli 8 bit meno significativi tutti a 0 (0b00000000=0).
    Se guardi la routine DelayBigUs vedi che fa un richiamo a DelayUs per un valore pari agli 8 bit meno significativi del valore di ritardo.
    void DelayBigUs(unsigned int cnt)
    {
    unsigned char i;

    i = (unsigned char)(cnt>>8);
    while(i>=1)
    {
    i–;
    DelayUs(253);
    CLRWDT();
    }
    DelayUs((unsigned char)(cnt & 0xFF));
    }

    Ora… probabilmente c’è un bug nella routine DelayUs ma ragionevolmente richiamare una funzione di ritardo per un tempo pari a zero “dovrebbe” sortire un effetto analogo a non richiamarla affatto… quindi ho corretto la routine DelayBigUs con la seguente:
    void DelayBigUs(unsigned int cnt)
    {
    unsigned char i;

    i = (unsigned char)(cnt>>8);
    while(i>=1)
    {
    i–;
    DelayUs(253);
    CLRWDT();
    }
    if ((unsigned char)(cnt & 0xFF)!=0)
    {
    DelayUs((unsigned char)(cnt & 0xFF));
    }
    }

    e il problema è sparito!!!

    • #9 da espocesco il 25 febbraio 2013

      Effettivamente la routine DelayUs non gestisce correttamente il valore 0.
      Analizzando la definizione di DelayUs, contenuta nel file delay.h

      #define DelayUs(x) { \
      delayus_variable=(unsigned char)(x/DelayDivisor); \
      WaitFor1Us; } \
      asm(“decfsz _delayus_variable,f”); \
      Jumpback;

      si vede che quando alla funzione è passato il valore 0, essa inizializza a 0 la variabile delayus_variable, che la successiva istruzione assembly decfsz (DECrement File Skip if Zero) imposta a 255.
      Di conseguenza il ciclo assembly

      asm(“decfsz _delayus_variable,f”); \
      Jumpback;

      è eseguito 255 volte.

      In definitiva DelayUs (0) produce un ritardo di 256 microSecondi, anziché di 0 microSecondi.

  4. #10 da Massimo Peino il 4 maggio 2012

    se non c’era la funzione DelayBigUs come avresti fatto?

    • #11 da Giovanni Bernardo il 5 maggio 2012

      Semplice…Me la creavo… Io non sono abituato a utilizzare funzioni già scritte. Il problema dei vari compilatori Mikro-Mikro è appunto quello che avendo funzioni già fatte, gli utenti non si abituano a ragionare per bypassare un “problema”. Per questo motivo ho sempre detto che se uno vuole approdare al C… allora Hitech-C e i vari MPLAB C compiler. Il C serve a capire l’architettura di un processore, e una volta imparato per bene puoi passare al C di un altro produttore o per un altro processore. Il MikroC invece non permette questo, perchè non rispetta gli standard ANSI e perchè ti da tutte funzioni già fatte che di certo non ti aiutano a capire quello che stai facendo. Questione diversa è se uno usa il basic.. purtroppo il Mikrobasic è l’unico a fare da padrone. Oppure in questo caso usavo un timer settato opportunamente.

    • #12 da Giovanni Bernardo il 5 maggio 2012

      Se vedi la funzione DelayBigUs, non è difficile da implementare per il MikroC. Puoi sfruttare la funzione DelayUs che hai normalmente, richiamandola piu volte con un ciclo a scalare.

  5. #13 da Massimo Peino il 5 maggio 2012

    La mia intenzione è ampliare il mio articolo . Vorrei pilotare il servo con un potenziometro via etere.
    Ci sono due possibilità :
    1- implementare il tuo progetto con la funzione DelayBigUs , e studiarmi la usart con Hitech-C .
    2-ampliare il mio progetto e crearmi una funzione per i tempi pilotata da un trimmer.
    In entrambi i casi c’è da fare esperienza .

    la seconda forse è più semplice ,tu cosa ne pensi.

    Un chiarimento:
    la funzione delay_us non può ricevere una variabile ma solo numeri interi ( può sembrare una domanda banale ma vista la mia esperienza!!!! ).
    Come faresti?

    P.S. Il MicroC è vero ti da delle funzioni già fatte ma chi inizia almeno non molla tutto subito in quanto vede dei risultati poi mangiando……….o trovando dei problemi ….

    ciao

    • #14 da Giovanni Bernardo il 6 maggio 2012

      Per fare i ritardi puoi sfruttare il timer. Ti calcoli a quale valore devi precaricarlo per avere un certo ritardo, quando ottieni l’interrupt il ritardo è finito.
      Mi pare strano che il mikro non ha una funzione per i ritardi variabili… hanno fatto funzioni per tutto e non per i ritardi?

  6. #15 da Massimo Peino il 7 maggio 2012

    Ha Vdelay_ms(); ma non c’è per i us, dovrò farmela ( o almeno provarci ).
    ciao

  7. #16 da riccai83 il 29 novembre 2012

    Ti ho inviato una mail su “i vostri progetti@…”, non ho inventato niente di nuovo, ma se dai uno sguardo
    al codice e ti sembra una cosa decente posso condividere altro materiale… ciao..

Devi essere collegato per lasciare un commento.

settorezero.com e il logo Zroid™ ©2007÷2013 Giovanni Bernardo - E' vietata la copia e la distribuzione anche parziale dei contenuti di questo sito web senza l'esplicito consenso dell'autore.
I contenuti di settorezero.com sono distribuiti sotto una licenza Creative Commons Attribuzione-Non Commerciale-Non Opere derivate 2.5 Italia a cui vanno aggiunte le condizioni d'uso definite nel disclaimer.
settorezero.com e tutti i suoi contenuti sono tutelati dalla legge sul diritto d'autore per cui i trasgressori sono perseguibili a norma di legge.
Creative Commons BY-NC-ND 2.5
Il tema di questo sito è basato sul tema Fusion per wordpress, realizzato originariamente da digitalnature e fa uso del plugin Wassup per il computo delle statistiche. Per contattare l'autore siete pregati di utilizzare la sezione contatti.
Per essere aggiornato con tutte le novità di settorezero.com seguici anche anche su Facebook Twitter Tumblr Blogspot Youtube.