Sono nuovo del forum, per un progetto universitario sto utilizzando un Arduino Mega per controllare il movimento di alcuni servo motori bipolari, controllato ognuno da un chip uln2003 e con l'ausilio della libreria AccelStepper. Dovrei muoverli singolarmente ed allo stesso tempo settando diverse accelerazioni, velocità e step per ognuno. Sono riuscito a farli muovere singolarmente e tutti assieme, ma quando cerco di mettere le due cose in sequenza nel "void loop()" non si muovono come dovrebbero. Ci sarebbe un modo per settare diverse "sequenze" di movimento da far eseguire una dopo l'altra per un determinato tempo o per determinati step? Grazie in anticipo a chi leggerà il post. Riccardo
// MultiStepper.pde
// -*- mode: C++ -*-
//
// Shows how to multiple simultaneous steppers
// Runs one stepper forwards and backwards, accelerating and decelerating
// at the limits. Runs other steppers at the same time
//
// Copyright (C) 2009 Mike McCauley
// $Id: MultiStepper.pde,v 1.1 2011/01/05 01:51:01 mikem Exp mikem $
#include <AccelStepper.h>
// Define some steppers and the pins the will use
AccelStepper stepper1(AccelStepper::FULL4WIRE, 0, 1, 2, 3); // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
AccelStepper stepper2(AccelStepper::FULL4WIRE, 4, 5, 6, 7);
int x=1;
void setup()
{
stepper1.setMaxSpeed(2000.0);
stepper1.setAcceleration(150.0);
stepper1.moveTo(1500);
delay(0);
stepper2.setMaxSpeed(2000.0);
stepper2.setAcceleration(145.0);
stepper2.moveTo(1500);
delay(0);
stepper3.setMaxSpeed(1000.0);
stepper3.setAcceleration(140.0);
stepper3.moveTo(1500);
delay(0);
stepper4.setMaxSpeed(1000.0);
stepper4.setAcceleration(135.0);
stepper4.moveTo(1500);
}
void loop()
{
if (x <=4)
{
stepper1.runToNewPosition(100);
x++;
}
else if (x<=5)
{
stepper2.runToNewPosition(100);
x++;
}
else if (x<=6)
{
stepper1.runToNewPosition(1000);
x++;
}
else if(x<=7) {
stepper2.runToNewPosition(1000);
x++;
}
else if(x<=8) {
stepper1.moveTo(100);
stepper2.moveTo(100);
stepper1.run();
stepper2.run();
x++;
}
else if(x<=9) {
if (stepper1.distanceToGo() == 0)
stepper1.moveTo(-stepper1.currentPosition());
delay(0);
if (stepper2.distanceToGo() == 0)
stepper2.moveTo(-stepper2.currentPosition());
delay(0);
if (stepper3.distanceToGo() == 0)
stepper3.moveTo(-stepper3.currentPosition());
delay(0);
if (stepper4.distanceToGo() == 0)
stepper4.moveTo(-stepper4.currentPosition());
stepper1.run();
stepper2.run();
stepper3.run();
stepper4.run();
}
}
Ho sbagliato a scrivere, si esatto sono degli stepper, i delay(0) erano rimasti da una prova per separare le varie istruzioni, e il progetto è proprio una macchina a stati finiti. Allego come codice la libreria AccelStepper, (altrimenti visionabile al link del produttore AccelStepper: AccelStepper.h Source File ) Grazie.
Come versione di ide sto utilizzando la 1.0.4, la classe usa ancora pde poichè non credo sia mai stata aggiornata ad una versione più recente... ed effettivamente i delay sono stati un problema, ma aggiungendo delay() fra fra i vari stati fa si che i delay stessi vengano ripetuti fra ognuna delle quattro fasi degli stepper, azzerando praticamente la velocità di ogni step, non sapendo come risolvere il problema li avevo settati a zero.
Forse è proprio questa differenza il mio problema, vorrei ottenere dei movimenti ben definiti ( accelerazione, velocità e step ) di un numero n di motori allo stesso tempo, racchiusi in vari "blocchi" da susseguirsi , ovvero che si muovano tutti insieme per un certo periodo, delay(), che compiano altri movimenti ( come in un secondo blocco), ecc... Per fare questo ho provato a creare dei cicli che eseguissero un certo numero di volte le operazioni, ma senza successo, poichè all'interno del void loop questi cicli andavano in conflitto.
quindi devi creare degli stati. ogni stato è un preciso stato di TUTTI i motori. Quali sono gli stati che vuoi ottenere?
per esempio la runToNewPosition() blocca il codice finchè quel motore non è in posizione. Quindi nel frattempo anche gli motori sono fermi.
Devi creare gli stati e usare funzioni NON bloccanti come la moveTo etc.. (nel sito del tizio in ogni funzione c'è la spiegazione e se è bloccante), e poi alla fine ogni blocco avrà un qualcosa che lo renderà bloccante finchè il blocco non è completo (che dipende da cosa quel blocco deve fare)
In oltre per semplicità ogni blocco lo metti in una funzione a parte, così ordini un poco anche il codice.
Per cominciare grazie di aver sottolineato la differenza fra fra funzioni bloccanti e non bloccanti, la cui differenza mi sfuggiva, conto entro breve di riscrivere il codice separando le funzioni per renderlo, come hai osservato, più ordinato. Solo ora evidentemente non mi è chiaro cosa sia uno stato, o forse lo conosco con un nome diverso, cosa intendi esattamente?
uno stato è una serie di azioni da eseguire sempre in contemporanea.
Ed esempio più esserci lo stato "resetta" che posta tutti i motori alla posizione iniziale
lo stato "avanza tutti" che muove tutti i motori avanti di un tot di step ad un tot di velocità
lo stato "aggancia" (immaginiamo un braccio robotico) che attiva il motore 3 (apre il gancio), muove i motori 1 e 2 (immaginali come X e Y, quindi posiziona il braccio), poi quando in posizione attiva al contrario il motore 3 (chiude il gancio)
Il che è esattamente il risultato che dovrei ottenere, allora come prima cosa devo apprendere la sintassi per programmare a stati finiti, di cui dovrei aver già trovato delle guide esaurienti nel forum, in questo caso la durata dello stato (quanto tempo lo stato viene eseguito) è direttamente collegata al tempo espresso in millisecondi giusto? (time=millis()
no, tutto dipende da quello che vuoi fare. Gli stati sono un entità astratta utile solo a concepire l'idea del software, poi come sono implementati nel codice è una tua scelta.
puoi usare una funzione per stato, una classe, o semplicemente usare uno switch in cui ogni case è uno stato.
quindi potrei includere una serie di movimenti, facendo attenzione se sto utilizzando una chiamata bloccante o non bloccante, in una funzione, per poi implementare uno switch in cui utilizzo la funzione appositamente chiamata per ogni stato dello switch e alla fine di ogni stato incrementare la variabile per poter passare dal primo caso dello switch al secondo e via... facendo in modo che si eseguano le operazioni all'interno della funzione prima di passare al caso successivo, per poterli eseguire così in sequenza ma ben separati fra loro da un certo tempo da definire ( potrei implementare un istruzione switch all'interno di un ciclo for in modo che ad ogni ciclo mi incrementi la variabile e passi al caso successivo ad esempio)
bravissimo, soluzione molto pulita, io stesso non avrei pensato ad incapsulare il tutto in un for!
io renderi ogni TUO stato bloccante: la funzione che crei chiama delle funzioni NON bloccati, per esempio setta il movimento di motore 1, 2 e 3, poi si mette in attesa che i motori compiano le proprie azioni.
per attendere che il motore 1, 2, e 3 abbiano finito, mentre il motore 4 continua a girare in modo non bloccante, per esempio, fai:
Perfetto, quindi all'interno di ogni case dovrei specificare
stepper.setMaxSpeed(...);
stepper.setAcceleration(...);
stepper.moveTo(...);
per ogni motore in modo che arrivato alla funzione stepper.run(); (una run(); per motore) i motori si muovano assieme con un determinato target, accelerazione e velocità massima, ed una volta terminato il case tornare al ciclo for, incrementare la variabile e passare al case successivo con la medesima sintassi di istruzioni ma con movimenti, accelerazioni e velocità diverse...questo dovrebbe funzionare
attento la run() non è bloccante, ma controlla se c'è da inviare (in quell'itsante) qualche info al chip del motore.
infatti io ho messo la run() all'interno di un while: finchè i motori non sono in posizione chiama la run() su tutti e 4.
dato che tutti i motori si muoveranno sempre in simultanea, e se giunti in posizione ci restano, puoi fare una funzione che aggiorna tutti i mori e la chiami updateEngine, che chiama una volta il run di tutti i motori, così eviti di scrivere ogni volta il run() per ogni singolo motore, e se aggiungi/togli un motore in un colpo solo sistemi tutti i rum().
Farei anche una lockingUpdate(), che oltre che chiamare il run() su tutti i motori, lo fa in un while come il mio con TUTTI i motori; se metti una chiamata a questa funzione all'inizio di ogni ciclo di for, sei sicuro che ogni motore è alla sua posizione prefissata prima di proceder al prossimo stato.
Perfetto, allora appena implemento il codice, probabilmente questo weekand, lo aggiungerò a questo post come commento che magari qualcun'altro sta avendo i miei stessi problemi e potrebbe prendere spunto. Grazie della pazienza e dell'aiuto che mi hai dato, adesso so esattamente come procedere nella stesura del codice, non resta che darsi da fare. Ancora grazie, Riccardo.