PS2 controller e stepper motor problema delay

Allora sono riuscito a collegare 2 stepper ed 1 servo ad un controller PS2 wireless. Tutti funziona rispondendo correttamente ai vari tasti e joystick, però il problema sono gli step dei motori, che vengono influenzati dal delay alla fine del codice:

#include <PS2X_lib.h>
#include <AccelStepper.h>
#include <Servo.h>

PS2X ps2x;  // create PS2 Controller Class
int error = 0;  // define error variable, initialize as no error
byte type = 0;  // define controller type variable, may test removing
byte vibrate = 0;  // define vibration strength, default to none

Servo myservo;  // create servo object to control a servo
#define servoPin 2 //
int angle = 90;   // initial angle  for servo
int angleStep = 10;
const int minAngle = 90;
const int maxAngle = 170;

// $$$$$ INITIALIZE PROGRAM VARIABLES AND CONSTANTS $$$$$ //
int stickX = 128;  // initialize X-Axis joystick value to the middle of 0-255 range
int stickY = 128;  // initialize Y-Axis joystick value to the middle of 0-255 range

int startSwitchState = 0;  // initialize start switch state as not pressed
int startLastSwitchState = 0;  // initialize start last switch state as not pressed
int R1SwitchState = 0;  // initialize R1 switch state as not pressed
int R1LastSwitchState = 0;  // initialize R1 last switch state as not pressed
int R2SwitchState = 0;  // initialize R2 switch state as not pressed
int R2LastSwitchState = 0;  // initialize R2 last switch state as not pressed
int L1SwitchState = 0;  // initialize L1 switch state as not pressed
int L1LastSwitchState = 0;  // initialize L1 last switch state as not pressed
int L2SwitchState = 0;  // initialize L2 switch state as not pressed
int L2LastSwitchState = 0;  // initialize L2 last switch state as not pressed

const int stepX = 3;  //pin digitale che invia i segnali di STEP al driver delle X
const int dirX = 4; //pin digitale che invia il segnale DIREZIONE al driver delle X
long speedX, valX, mapX;  //variabili di gestione movimenti motore X
const int stepY = 5;  //pin digitale che invia i segnali di STEP al driver delle Y
const int dirY = 6; //pin digitale che invia il segnale DIREZIONE al driver delle Y
long speedY, valY, mapY;  //variabili di gestione movimenti motore Y
//variabili utilizzate dalla libreria AccelStepper
int maxSpeed = 200;  //stando alla documentazione della libreria questo valore può essere impostato fino a 4000 per un Arduino UNO
int minSpeed = 0; //velocità minima del motore
const float accelerazione = 3; //numero di step al secondo in accelerazione
const int treshold = 10;  //la lettura dei potenziometri non è mai affidabile al 100%, questo valore aiuta a determinare il punto da considerare come "Stai fermo" nei movimenti
long tresholdUp, tresholdDown;  //variabili di servizio per espletare il compito descritto sopra
boolean abilitato, muoviX, muoviY, enable;  //variabili di gestione dei movimenti
//istanzia i motori
AccelStepper motoreX(AccelStepper::DRIVER, stepX, dirX);
AccelStepper motoreY(AccelStepper::DRIVER, stepY, dirY);


void setup() {
  Serial.begin(9600);  // begin serial communication, set at 57600 Baud rate, may test changing
  error = ps2x.config_gamepad(13, 10, 11, 12, false, false); // check for errors on PS2 controller

  myservo.attach(servoPin);  // attaches the servo on pin 3 to the servo object
  myservo.write(angle);
  //configura parametri dei motori
  motoreX.setMaxSpeed(maxSpeed);
  motoreX.setSpeed(minSpeed);
  motoreX.setAcceleration(accelerazione);

  motoreY.setMaxSpeed(maxSpeed);
  motoreY.setSpeed(minSpeed);
  motoreY.setAcceleration(accelerazione);

  if (error == 0)
    Serial.print("Found Controller, Configured Successfully.");
  else if (error == 1)
    Serial.println("No Controller Found.");
  else if (error == 2)
    Serial.println("Controller Found but not Accepting Commands.");
  else if (error == 3)
    Serial.println("Controller Refusing to Enter Pressures Mode, May Not Support it.");

  type = ps2x.readType();  // find the type of the

  switch (type) {
    case 0:
      Serial.print("Unknown Controller Type Found ");
      break;
    case 1:
      Serial.print("DualShock Controller Found ");
      break;
  }
}


void loop() {
  if (error == 1) { // skip loop if no controller is found, may test adding config_gamepad(pins)
    ps2x.config_gamepad(13, 10, 11, 12, false, false); // reconfigure PS2 controller to attempt fixing error
    return;
  }
  ps2x.read_gamepad(false, vibrate); //read controller, don't record arrow pressures, and set large motor to spin at 'vibrate' speed

  R2SwitchState = ps2x.ButtonPressed(PSB_R2);  // read R2 switch state

  if (R2SwitchState != R2LastSwitchState) { // see if button state changed
    if (R2SwitchState == HIGH) { // if the button was pressed, not released
      myservo.write(maxAngle); // move the servo to desired angle
      Serial.println("R2 PRESSED");
    }
  }
  R2LastSwitchState = R2SwitchState;  // save switch state for comparison


  if (ps2x.ButtonPressed(PSB_RED)) {
    Serial.println("Circle just pressed");
  }
  if (ps2x.ButtonReleased(PSB_PINK)) {
    Serial.println("Square just pressed");
  }
  if (ps2x.NewButtonState(PSB_BLUE)) {
    Serial.println("X just changed");
  }

  L2SwitchState = ps2x.ButtonPressed(PSB_L2);  // read L2 switch state
  if (L2SwitchState != L2LastSwitchState) { // see if button state changed
    if (L2SwitchState == HIGH) {
      Serial.println("L2 PRESSED");
      myservo.write(minAngle); // move the servo to desired angle
    }
  }
  L2LastSwitchState = L2SwitchState;  // save switch state for comparison

  R1SwitchState = ps2x.ButtonPressed(PSB_R1);  // read R1 switch state
  if (R1SwitchState != R1LastSwitchState) { // see if button state changed
    if (R1SwitchState == HIGH) {
      Serial.println("R1 PRESSED");
    }
  }
  R1LastSwitchState = R1SwitchState;  // save switch state for comparison

  L1SwitchState = ps2x.ButtonPressed(PSB_L1);  // read L1 switch state
  if (L1SwitchState != L1LastSwitchState) { // see if button state changed
    if (L1SwitchState == HIGH) {
      Serial.println("L1 PRESSED");
    }
  }
  L1LastSwitchState = L1SwitchState;  // save switch state for comparison

  startSwitchState = ps2x.ButtonPressed(PSB_START);  // read Start switch state*/
  if (startSwitchState != startLastSwitchState) { // see if button state changed
    if (startSwitchState == HIGH) {
      Serial.println("START PRESSED");
    }
  }
  startLastSwitchState = startSwitchState;  // save switch state for comparison

  stickX = ps2x.Analog(PSS_LX);  // set the analog value of the right stick X-Axis equal (0-255)
  if (stickX != 128) {
    //Serial.print("X-AXIS:");
    //Serial.println(stickX, DEC);
  }

  stickY = ps2x.Analog(PSS_LY);  // set the analog value of the left stick Y-Axis equal (0-255)
  if (stickY != 127) {
    //Serial.print("Y-AXIS:");
    //Serial.println(stickY, DEC);
  }

  // $$$$$ MAP AND MOVE X-AXIS STEPPER MOTOR $$$$$ //
  int mapX = stickX;  // set the desired stepper position equal to the X-Axis value (0-255)
  minSpeed = 0; // reset speed

  if (mapX > 130) { // if the X-Axis stick position is positive
    speedX = map(mapX,  maxSpeed, 130,  maxSpeed, minSpeed);
    muoviX = true;
    //Serial.println("muovo X a destra");
    //Serial.println(speedX);
    //Serial.println(mapX);
  } else if (mapX < 126) { // if the X-Axis stick position is negative
    speedX = -map(mapX, 128, minSpeed,   minSpeed, maxSpeed);
    muoviX = true;
    //Serial.println("muovo X a sinistra");
    //Serial.println(speedX);
    //Serial.println(mapX);
  } else {
    //x sta fermo
    speedX = 0;
    muoviX = false;
  }


  if (muoviX) {
    motoreX.setSpeed(speedX);
    motoreX.run();
  } else {
    motoreX.stop();
  }

  // MUOVO Y-AXIS STEPPER MOTOR //
  mapY = stickY;  // set the desired stepper position equal to the Y-Axis value (0-255)
  minSpeed = 0; // reset speed

  if (mapY > 127) { // if the Y-Axis stick position is positive
    speedY = map(mapY,  maxSpeed, 127,  maxSpeed, minSpeed);
    muoviY = true;
    //Serial.println("muovo Y su");
    //Serial.println(speedY);
    //Serial.println(mapY);
  } else if (mapY < 127) { // if the Y-Axis stick position is negative
    speedY = -map(mapY, 127, minSpeed,   minSpeed, maxSpeed);
    muoviY = true;
    //Serial.println("muovo Y giu");
    //Serial.println(speedY);
    //Serial.println(mapY);
  } else {
    //y sta fermo
    speedY = 0;
    muoviY = false;
  }

  if (muoviY) {
    motoreY.setSpeed(speedY);
    motoreY.run();
  } else {
    motoreY.stop();
  }
 delay(10);
}

in pratica anche se cambio maxSpeed ed accelerazione poco cambia, mentre se cambio il delay cambia molto, se invece lo tolgo va proprio a scatti..... come dovrei impostarlo?

Se ti da tanta noia, toglilo :slight_smile: anche perchè in questo modo, la sequenza di impulsi dati allo stepper è influenzata dal delay (e non dalla libreria).
Dovresti inserire il comando di run all'interno di un ciclo, ad esempio "muoviti finchè non hai raggiunto questa posizione"

se tolgo il delay non so perchè ogni tanto si muove indipendentemente dal controller non so se dipende da interferenze

Questo modulo funziona calcolando un tempo di passo in microsecondi. Il tempo del passo viene ricalcolato dopo ogni passo e dopo che i parametri di velocità e accelerazione vengono modificati dal chiamante. Il tempo di ogni passaggio viene registrato in microsecondi. La funzione run() fa avanzare il motore una volta se è necessario un nuovo passo. La funzione run() deve essere chiamata frequentemente finché il motore non si trova nella posizione desiderata, dopodiché run() non farà nulla.

Questo è quello che dice la documentazione di accelstepper. Quindi la chiamata a run() non si riferisce al motore ma alla libreria. Allora prova ad inserire la chiamata a run() fuori da ogni if e togli il delay. Anzi al posto del delay ci metti:

motoreX.run();
motoreY.run();

Ciao,

C'è già l'istruzione run!:

if (muoviX) {
    motoreX.setSpeed(speedX);
    motoreX.run();
  } else {
    motoreX.stop();
  }

Prova a dare un po' più di tolleranza ai segnali dal pad, probabilmente è solo un segnale analogico ballerino.
Rimane comunque valido quello che ti ha indicato @Maurotec , magari metti i comandi run in un ciclo while che si interrompe con il rilascio del pad

Un ciclo while dentro un loop infinito può solo peggiorare la situazione, tra l'altro il metodo run se non ha step da eseguire restituisce il controllo al chiamante immediatamente restituendo false.

Qui il codice del metodo run:

// Run the motor to implement speed and acceleration in order to proceed to the target position
// You must call this at least once per step, preferably in your main loop
// If the motor is in the desired position, the cost is very small
// returns true if the motor is still running to the target position.
boolean AccelStepper::run()
{
    if (runSpeed())
	computeNewSpeed();
    return _speed != 0.0 || distanceToGo() != 0;
}

Si lo so ma si trova dentro una condizione if che non sempre è vera.
Ciao.

Perché dici che la peggiori? Dall'estratto della documentazione che hai postato è indicato

Quindi se avessi una distanza definita da percorrere scriverei

while( posAttuale != posObiettivo)
  motoreX.run();

Ma nel suo caso il movimento deve essere interrotto solo dal rilascio del pad

while (mapX != posRiposo)
{
   motoreX.run();
   mapX = stickX;
}

Allora forse il vero problema non è di software ma di hardawere e di segnale di corrente, in quanto a riposo (quindi senza toccare il joypad (lo stesso avviene collegando un joystick arduino) la lettura dei valori analogici degli stick non è costante!
Se infatti faccio un serial.print di stickX e stickY mi restituisce sempre valori diversi!
La mia domanda quindi è, come stabilizzo i valori degli stick?

Io definirei delle variabili bool tipo padAvanti, padIndietro, padRiposo. Queste sono gestite da dei range di valore ed esempii 0-60 padAvanti, 60-190 padRiposo, 190-255 padIndietro.

Come alimenti Arduino durante le prove?
Potresti provare anche a fate una media di N valori prima di muovere il motore.

I motori sono alimentati da atx esterno (+12v) mentre arduino da usb.

Quindi in pratica dovrei partire da qui:

  stickX = ps2x.Analog(PSS_LX); 
  if (stickX != 132) {
    motoreY.Stop();
  }
if (stickX > 132){
    muovo_destra();
}
if (stickX < 132){
    muovo_sinistra();
}

void muovo_destra(){
    motoreY.setSpeed(speedY);
    motoreY.run();
}

void muovo_sinistra(){
    motoreY.setSpeed(-speedY);
    motoreY.run();
}

Ma non esiste un modo (siccome si tratta di un braccio robot che ha anche dei limitswith) di dare solo l'impulso di movimento di un tot di step ad una determinata velocità a prescindere dal valore analogico del joypad (cambio solo se fermo, destra, sinistra)

Con quella libreria mo sembra che ti basti impostare il distanceToGo()

Prova ad alimentare Arduino con un altro alimentatore.

Il suggerimento di @Z4KK4 al post #10 mi pare vada in questa direzione, no?

Hai messo in comune i GND ?

Alla fine vi posto la mia soluzione funzionante:

void loop() {
  if (error == 1) { // skip loop if no controller is found, may test adding config_gamepad(pins)
    ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, false, false);
    return;
  }
  ps2x.read_gamepad(false, vibrate); //read controller, don't record arrow pressures, and set large motor to spin at 'vibrate' speed
  stickX = ps2x.Analog(PSS_LY);  // set the analog value of the right stick X-Axis equal (0-255)
  stickY = ps2x.Analog(PSS_LX);  // set the analog value of the right stick X-Axis equal (0-255)
  // MUOVO X-AXIS //
  int mapX = stickX;  // set the desired stepper position equal to the X-Axis value (0-255)
  if (mapX > 123) { // if the X-Axis stick position is positive
    motoreX.setSpeed(200);
    motoreX.setAcceleration(1);
    motoreX.run();
  } else if (mapX < 123) { // if the X-Axis stick position is negative
    motoreX.setSpeed(-200);
    motoreX.setAcceleration(1);
    motoreX.run();
  } else {
    motoreX.stop();
  }

  // MUOVO Y-AXIS //
  int mapY = stickY;  // set the desired stepper position equal to the Y-Axis value (0-255)
  if (mapY > 123) { // if the Y-Axis stick position is positive
    motoreY.setSpeed(200);
    motoreY.setAcceleration(1);
    motoreY.run();
  } else if (mapY < 123) { // if the Y-Axis stick position is negative
    motoreY.setSpeed(-200);
    motoreY.setAcceleration(1);
    motoreY.run();
  } else {
    motoreY.stop();
  }
}

No vabbeh sto diventando pazzo....allora il codice ora va, ma non so perchè se collego due motori uno dei due inizia a muoversi e poi è come se perdesse corrente....devo rilasciare il joypad, aspettare un po e poi se lo rimuovo riparte.... i motori ovviamente sono alimentati da atx +12. L'altra cosa è che se stacco arduino da usb e lo alimento da jack si accende ma non funziona proprio! :sleepy: :sleepy:

E' un po' generica come descrizione.....

Serve uno schema?