• Consulenza progettazione sistemi elettronici
  • Dall'idea al sistema completo
  • Preventivo base gratuito
  • Corsi di progettazione e argomenti tecnici
  • Per maggiori info visita la pagina :Servizi consulenza
  • Per domande e maggiori informazioni: Contattami

 

Pilotare un servomotore con un potenziometro

  • Pinna
  • Autore della discussione
  • Moderatore
  • Moderatore
Di più
11 Anni 5 Mesi fa #36 da Pinna
timer0 si occupa di dare l'impulso al servo mentre timer1 scandisce il periodo di 20 ms... quindi sarà con questi due timer che si dovrà lavorare mentre ciò che si dovrà implementare sarà leggere in modo sequenziale le porte analogiche utilizzate

Marcello

Chi vola vale, chi vale vola, chi non vola è un vile

Si prega Accesso o Crea un account a partecipare alla conversazione.

  • elpablito
  • Platino Utente
  • Platino Utente
Di più
11 Anni 5 Mesi fa #37 da elpablito
Risposta da elpablito al topic Pilotare un servomotore con un potenziometro
Non so cosa state tramando e quindi dico la mia fesseria se devi generare un impulso ogni 20mS
perchè non adoperi un PWM com un tempo di 20 ms e adoperi il duty cycle per generare l'impulso che se ti serve potresti anche variarene l'ampiezza?
E' la solita idea della prima mattina, non fateci caso.
Saluti
Paolo

Si prega Accesso o Crea un account a partecipare alla conversazione.

  • Pinna
  • Autore della discussione
  • Moderatore
  • Moderatore
Di più
11 Anni 5 Mesi fa #38 da Pinna
Ciao Paolo, quello che si sta cercando di fare è un progetto aperto a TUTTI COLORO che possono o vogliono partecipare (invito valido anche per te, se lo desideri)... diciamo che è finalizzato alla progettazione di un braccio robotico, ma non solo: può essere la base per la progettazione di un robot come domotino, ma in versione più "tosta". Stiamo iniziando con i primi esperimenti per pilotare i servi con un potenziometro, che sarà sostituito da un joystick. Per il pilotaggio di un servo non ho avuto nessun problema, tant'è vero che troverai il firmware allegato qualche topic indietro. Il problema lo vedo nel pilotare più servi, anche perchè dalle prove che sto conducendo sto riscontrando alcune anomalie... purtroppo il fatto di non avere un oscilloscopio mi penalizza alquanto. Comunque, dato che non abbiamo fretta, facciamo un passo alla volta. Tutto è iniziato da questo topic:

www.laurtec.it/forum/15-progetti/7425-do...struito?limitstart=0



Marcello

Chi vola vale, chi vale vola, chi non vola è un vile

Si prega Accesso o Crea un account a partecipare alla conversazione.

  • StefA
  • Moderatore
  • Moderatore
Di più
11 Anni 5 Mesi fa #39 da StefA
con i pwm avevo fatto una prova e funzionicchiava, dovevo però verificare se si riusciva ad avere una buona "risoluzione" riguardo il variare la durata dell'impulso con la variazione del duty cycle.. in fin dei conti il pwm usa i timer.. ;)

Anche io pensavo di usare un timer per l'impulso generale da 20ms e poi un timer ogni servo, per fare tutto con soli due timer cos'hai in mente Pinna?

Cambiare canali dell'adc non è niente di difficile.

Comunque sia stamattina ho fatto qualche prova, ovviamente il programma di Pinna funziona perfettamente.
Quello che segue è per far vedere cosa intendevo un po' di post dietro, è una versione rozza ma funziona, avremo tempo di smussare i dettagli.
Ho provato a fare la stessa cosa con un ritardo ma non funzionava bene, indagherò meglio e vi terrò aggiornati.
Code:
//*************************************************************************************************// // Titolo: Controllo e pilotaggio di un servocomando tramite potenziometro // // Autore: Marcello Pinna 19/01/2014 // // Hardware: Freedom I // pic 18F4550 // quarzo 20 MHz // servocomando Futaba S3003 // potenziometro da 4,7 K // // Note importanti: il servo deve essere collegato a PORTD.RD0 del pic 18F4550 ed alimentato con // una tensione continua di 6 volts. Il potenziometro deve essere collegato // all'ingresso AN1 del microcontrollore //*************************************************************************************************// #include <p18F4550.h> #define SERVO_ON LATDbits.LATD0 = 1 #define SERVO_OFF LATDbits.LATD0 = 0 #define FACTOR 5 // fattore di conversione conteggi - mS #pragma config FOSC = HS //OSC = HS Impostato per lavorare ad alta frequenza #pragma config WDT = OFF //WDT = OFF Disabilito il watchdog timer #pragma config LVP = OFF //LVP = OFF Disabilito programmazione LVP #pragma config PBADEN = OFF //PBADEN = OFF Disabilito gli ingressi analogici // ============================= VARIABILI DI CONTROLLO ================================== unsigned int timer0; // vedi timers.h unsigned int timer1; // vedi timers.h unsigned int sommatoria = 0; // Variabile per salvare la sommatoria dei dati letti unsigned int valore_ADC = 0; // Variabile per salvare il valore della conversione unsigned int pulse = 0; // Variabile per convertire il valore della conversione in impulso per il servo (ms) char i; // Variabile utilizzata per il numero delle letture // ============================= PROTOTIPI DI FUNZIONE =================================== void WriteTimer0 ( unsigned int timer0); // Prototipo di funzione estrapolato dal timers.h (MCC18\h) void WriteTimer1 ( unsigned int timer1); // Prototipo di funzione estrapolato dal timers.h (MCC18\h) // ======================== IMPOSTAZIONI TIMER0 E TIMER1 ================================= void set_timer(void) { // ---> TIMER0 // Imposto la modalità a 16 bit T0CONbits.T08BIT = 0; // Imposto il clock interno T0CONbits.T0CS = 0; // Disabilito Prescaler T0CONbits.PSA = 1; // Abilito le interruzioni del Timer0 INTCONbits.TMR0IE = 1; // Abilito le interruzioni del Timer0 ad alta priorità INTCON2bits.TMR0IP = 1; // Abilito il Timer0 T0CONbits.TMR0ON = 1; //---> TIMER1 // Imposto la modalità a 16 bit T1CONbits.RD16 = 1; // Abilito il clock interno Timer1 (Fosc/4) T1CONbits.TMR1CS = 0; // Imposto il PreScaler Timer1 1:2 T1CONbits.T1CKPS0 = 1; T1CONbits.T1CKPS1 = 0; // Disabilito l'oscillatore del Timer1 T1CONbits.T1OSCEN = 0; // Abilito il Timer1 T1CONbits.TMR1ON = 1; // Calcolo del valore iniziale del Timer1 // Voglio generare un impulso della durata totale di 20 ms; con il prescaler impostato 1:4 // il tempo di inremento è di 0.0004 ms. Il numero dei conteggi è dato da (20/0.0004 = 50000) // Sottraendo a 65536 il numero dei conteggi così ottenuti si ha: (65536-50000 = 15536) timer1 = 15536; // Imposto la funzione WriteTimer1 con questo valore WriteTimer1 (timer1); // Abilito l'interrupt globale INTCONbits.GIEH = 1; } // =========================== ROUTINE INTERRUPT ALTA PRIORITA' ========================= // Prototipo di funzione void Hight_Int_Event (void); #pragma code Hight_vector=0x08 void Hight_interrupt (void) { // Imposta il salto per la gestione dell'interrupt _asm GOTO Hight_Int_Event _endasm } #pragma code #pragma interrupt Hight_Int_Event void Hight_Int_Event (void) { if (INTCONbits.TMR0IF) { // Spengo il servo SERVO_OFF; // Disabilito il Timer0 T0CONbits.TMR0ON = 0; } // Appena scatta l'interrupt if (PIR1bits.TMR1IF) { // Ricarico il Timer1 WriteTimer1(15536); // Azzero il flag di interrupt del timer1 PIR1bits.TMR1IF = 0; // Avvio il servo SERVO_ON; // Converto i ms in numero di conteggi da levare a 65536 per ottenere il valore // iniziale del Timer0 timer0 = (unsigned int)(65536 - (pulse * FACTOR)); // Imposto la funzione WriteTimer0 con questo valore WriteTimer0 (timer0); // Abilito il Timer0 T0CONbits.TMR0ON = 1; // Pulisco il flag di interrupt INTCONbits.TMR0IF = 0; } } // ==================================== ROUTINE PRINCIPALE ============================== void main (void) { // Imposto TRISA tutti ingressi LATA = 0x00; TRISA = 0xFF; // Imposto TRISB tutti ingressi LATB = 0x00; TRISB = 0xFF; // Imposto PORTC tutti ingressi, RC1 come uscita (retroilluminazione del display) LATC = 0x00; TRISC = 0xFD; // Imposto PORTD tutte uscite (pilotaggio del display) LATD = 0x00; TRISD = 0x00; // Imposto TRISE tutti ingressi LATE = 0x00; TRISE = 0xFF; // Abilito AN0-AN1 come ingressi analogici // Le VREF sono impostate a massa e VCC ADCON1 = 0b00001101; // Seleziono AN1 come ingresso ADCON0 = 0b00000100; // Imposto i tempi di conversione e giustificazione a destra // TAD : FOSC/4 // TACQ: 16 TAD ADCON2 = 0b10110100; // Abilito l' ADC ADCON0bits.ADON = 0x01; // Avvio la routine di inizializzazione set_timer(); // Ciclo infinito while(1) { sommatoria = 0; // Effettuo 8 letture per fare una media for (i = 0; i < 8; i++) { // Avvio la conversione Analogico/Digitale ADCON0bits.GO = 1; // Attendo la fine della conversione while(ADCON0bits.GO); // Prelevo il valore della conversione valore_ADC = (((int) ADRESH) << 8) | ADRESL; // Sommatoria delle letture fatte sommatoria = sommatoria + valore_ADC; } // Per ottenere la media, invece di dividere per otto, faccio tre shift verso destra // ogni shift corrisponde rispettivamente a dividere per 2, per 4 e per 8 sommatoria = sommatoria >> 3; /* // Converto la media così ottenuta in un impulso, espresso in MICROSECONDI, utilizzando un fattore // di conversione ricavato dal rapporto: 2000/1023= 1.955, dove 2000 rappresenta il range di lavoro // dell'impulso applicato (2500-500 = 2000 uS) mentre 1023 rappresenta il range di lavoro (10 bit) // del convertitore ADC. A questo dato sommo il valore minimo dell'impulso, pari a 500 us. pulse = (sommatoria * 1.955) +500; */ if ( (sommatoria >= 562) && (sommatoria < 662) ) pulse = pulse + 1; if ( (sommatoria >= 662) && (sommatoria < 762) ) pulse = pulse + 3; if ( (sommatoria >= 762) && (sommatoria < 862) ) pulse = pulse + 5; if ( (sommatoria >= 862) && (sommatoria < 962) ) pulse = pulse + 7; if (sommatoria >= 962) pulse = pulse + 100; if (sommatoria < 462) pulse = pulse - 10; if (pulse > 2400) pulse = 2400; if (pulse <= 500) pulse = 500; } }

@Pinna: se commenti qualche if e ne lasci magari solo un paio rende meglio l'idea. Fai qualche prova e fammi sapere.

Ste

..avevano magari fatto lo sgambetto al ka, ma il sangue restava sempre più denso dell'acqua.. [cit.]

Si prega Accesso o Crea un account a partecipare alla conversazione.

  • Pinna
  • Autore della discussione
  • Moderatore
  • Moderatore
Di più
11 Anni 5 Mesi fa #40 da Pinna
attualmente sto lavorando nuovamente con il display, leggendo i segnali provenienti da due ingressi adc (AN0 e AN1) collegati a due potenziometri... anche se li leggo bene ed in modo indipendente l'uno dall'altro, utilizzando lo shift per la lettura di ogni canale, c'è qualcosa che ancora non mi quadra. Per dirla secca, se faccio due letture e poi calcolo la media ottengo il valore giusto, ma se incremento il numero delle letture e poi calcolo nuovamente la media il valore scende in modo repentino. Ho mandato una mail a Mauro per sapere cosa ne pensa. Se prendo il firmware con il pilotaggio di un UNICO servo questo non avviene....

Marcello

Chi vola vale, chi vale vola, chi non vola è un vile

Si prega Accesso o Crea un account a partecipare alla conversazione.

Registrati al sito

Accedi a tutte le risorse e articoli non visibili pubblicamente, puoi registrarti con pochi passi.

Registrati al sito LaurTec.

Forum - Ultimi messaggi