Aller au contenu


Contenu de bvking

Il y a 95 élément(s) pour bvking (recherche limitée depuis 03-juin 13)



#102056 Robot 2WD homologable pour la coupe de france de robotique réalisé au dernier...

Posté par bvking sur 06 février 2019 - 04:34 dans Robots roulants, chars à chenilles et autres machines sur roues

OK

Fichier(s) joint(s)




#102099 Robot 2WD homologable pour la coupe de france de robotique réalisé au dernier...

Posté par bvking sur 10 février 2019 - 07:56 dans Robots roulants, chars à chenilles et autres machines sur roues

Pourquoi utiliser le " noInterrupt " ? 

 

​Je sais pas trop en fait, je crois que c'était au cas où l'une des deux pins deconnait.

 

Dans le programme de base j'avais seulement ça

 //  abs_durationA=durationA;/

 

mais un programmeur sur le forum Arduino m'avait conseillé

 

noInterrupts();

      latestDurationCountA = durationA;
      interrupts();
      abs_durationA = abs(latestDurationCountA);
 
 
J'ai retiré noInterrupts(); et en effet, il n'y a aucune difference! 
 
Depuis, j'ai intégré dans mon programme des fonctions de controle de vitesse et sens pour chacun de mes deux moteurs, et là, je n'ai plus du tout la même synchronicité qu'avec le programme attaché dernièrement.
 
Donc, j'aurai bien aimé utilisé les deux pin de l'encodeur pour doubler la resolution.

Si tu pouvais me donner un bon coup de main avec un exemple de programme, je suis preneur. Car je suis loin d'avoir fini mon projet qui au final fera tourner 5 moteurs où j'aimerai observer justement observer des légers décalages de manières précises afin de créer une illusion de mouvement optique dans un mouvement réel.... (et faut que je réfléchisse à cette dernière partie).
 
Merci  :mr47_05:
 
 

 




#102105 Robot 2WD homologable pour la coupe de france de robotique réalisé au dernier...

Posté par bvking sur 11 février 2019 - 09:17 dans Robots roulants, chars à chenilles et autres machines sur roues

Avant en assignant les mêmes vitesses à mes deux moteurs, ils se décalaient de 45° au bout de deux minutes,

 

maintenant en compliquant mon programme (avec le calcul de la moyenne de la vitesse par moteur), j'ai un décalage de 720° donc je vais essayer de

 

"doubler le code déjà présent ".

 

Ok, mais en plus de doubler la resolution, il faudrait que je puisse garder la fonction qui  detecte la direction de la roue. 

Voila le code, je vais essayer donc de doubler

volatile byte LstateA = digitalRead(encoderApinA);

avec

volatile byte LstateB = digitalRead(encoderApinB);

....

void EncoderInitA()
{
  DirectionA = true;//default -> Forward  
  pinMode(encoderApinB,INPUT);  
  attachInterrupt(3, wheelSpeedA, CHANGE);
}
 
void wheelSpeedA()
{
volatile byte LstateA = digitalRead(encoderApinA);  
  if((encoderAPinALast == LOW) && LstateA==HIGH)
  {
 volatile byte valA = digitalRead(encoderApinB);
    if(valA == LOW && DirectionA)
    {
      DirectionA = false; //Reverse
    }
    else if(valA == HIGH && !DirectionA)
    {
      DirectionA = true;  //Forward
    }
  }
  encoderAPinALast = LstateA; 
  
 
  if(!DirectionA)  durationA++;
  else  durationA--;

}



#101942 Robot 2WD homologable pour la coupe de france de robotique réalisé au dernier...

Posté par bvking sur 29 janvier 2019 - 09:50 dans Robots roulants, chars à chenilles et autres machines sur roues

 Bonjour,

 

J'aime ce sujet car il utilise le PID et j'ai un projet artistique qui devra faire tourner au moins 5 moteurs à vitesse constante et de manière égale dans un premier temps, puis dans un second temps les faire tourner à vitesse constante mais à des vitesses proportionnellement differentes (je rentre pas ici dans les details)

 

 

En essayant le programme, si je mets 10 dans le Serial monitor, le premier moteur accélère jusqu'a un maximum, puis le second accélère tandis que le premier ralentit, puis le second ralentit et le premier ré-accelere jusqu'a un maximum. Puis si je mets -10, le phénomène s'inverse. (je sais pas trop si c'est normal)
 
Dans mon projet, j'essaye de contrôler au moins pour l'instant deux moteurs afin qu'ils aillent exactement à la meme vitesse et j'aurais voulu m'inspirer de votre  programme pour asservir des vitesses identiques puis differentes à chacun des moteurs et choisir leur sens, mais je sèche un peu.
Aussi j'ai voulu utilisé votre programme avec une Arduino Due, mais j'ai eu ce message:
 
ATTENTION : la bibliothèque TimerOne prétend être exécutable sur la (ou les) architecture(s) (avr) et peut être incompatible avec votre carte actuelle qui s'exécute sur (sam).
/Users/macbookpro/Documents/Arduino/PID_ROBOT_DEUX_ROUES/PID_ROBOT_DEUX_ROUES.ino: In function 'void setup()':
 
Pourriez vous m'aider?
 
Bien à vous
 
Benjamin :thank_you: 



#102053 Robot 2WD homologable pour la coupe de france de robotique réalisé au dernier...

Posté par bvking sur 06 février 2019 - 04:12 dans Robots roulants, chars à chenilles et autres machines sur roues

Salut,

 

Juste pour dire que j'ai mis le programme dans une vrai Arduino, la Due et là je n'ai plus aucun problème. 

 

En plus, mes deux moteurs sont synchronisés encore plus précisément.

 

Merci pour votre patience. :zsmoke:




#102106 Robot 2WD homologable pour la coupe de france de robotique réalisé au dernier...

Posté par bvking sur 11 février 2019 - 10:40 dans Robots roulants, chars à chenilles et autres machines sur roues

voilà , j'ai changé comme ceci

 

la roue A avec l'encodeur A

void EncoderInitA()

{
  DirectionA = true;//default -> Forward  
  pinMode(encoderApinB,INPUT);  
  pinMode(encoderApinA,INPUT);  
  attachInterrupt(3, wheelSpeedA, CHANGE);
   attachInterrupt(7, wheelSpeedA, CHANGE);
}


void wheelSpeedA()
{
volatile byte LstateA = digitalRead(encoderApinA);  
volatile byte LstateAB = digitalRead(encoderApinB);  

  if(encoderAPinALast == LOW && LstateA==HIGH && encoderAPinBLast == HIGH && LstateAB==LOW)
  
  
  {
 volatile byte valA = digitalRead(encoderApinB);

    if(valA == LOW && DirectionA)
    {
      DirectionA = false; //Reverse
    }
    else if(valA == HIGH && !DirectionA)
    {
      DirectionA = true;  //Forward
    }
  }
  encoderAPinALast = LstateA; 
  encoderAPinBLast = LstateAB; 
  

  if(!DirectionA)  durationA++;
  else  durationA--;

}

 

 

et pareil avec la roue B

oid EncoderInitB()
{
  DirectionB = true;//default -> Forward  
  pinMode(encoderBpinB,INPUT); 
  pinMode(encoderBpinA,INPUT); 
  attachInterrupt(2, wheelSpeedB, CHANGE);
  attachInterrupt(4, wheelSpeedB, CHANGE);
}
 
void wheelSpeedB()
{
  volatile byte LstateB = digitalRead(encoderBpinA); 
  volatile byte LstateBB = digitalRead(encoderBpinA); 

  
  if(encoderBPinALast == LOW && LstateB==HIGH && encoderBPinBLast == HIGH && LstateBB==LOW)
  {
   volatile byte valB = digitalRead(encoderBpinB);
    if(valB == LOW && DirectionB)
    {
      DirectionB = false; //Reverse
    }
    else if(valB == HIGH && !DirectionB)
    {
      DirectionB = true;  //Forward
    }
  }
  encoderBPinALast = LstateB;
  encoderBPinBLast = LstateBB;
 
  if(!DirectionB)  durationB++;
  else  durationB--;

}

en n'oubliant pas ceci dans le setup

volatile byte encoderAPinBLast;
volatile byte encoderBPinBLast;

et bizarrement j'ai la roue A qui va plus doucement que la roue B .

La vitesse détectée pour la roue A est instable alors qu'elle ne saccade pas( à l'oeil nu)

Et la roue A est détecté à une vitesse negative quand l'autre est positive.

 

Mais est-ce que dans le principe c'est bon?

 

Je mets les vitesses perçues pour les moteurs avec LD (dernière vitesse de A) et LDb (dernière vitesse de B)

LDB-50.00Db: -9.00-12.00-16.00Vb92.85
LD49.00D  : 8.0012.0016.00V85.25
LDB-50.00Db: -9.00-13.00-17.00Vb92.85
LD51.00D  : 8.0011.0016.00V73.20
LDB-50.00Db: -9.00-13.00-17.00Vb92.85
LD50.00D  : 8.0011.0014.00V80.20
LDB-51.00Db: -8.00-12.00-16.00Vb89.80
LD50.00D  : 8.0011.0013.00V78.20
LDB-49.00Db: -9.00-13.00-17.00Vb97.85
LD51.00D  : 11.0014.0018.00V75.15
LDB-51.00Db: -9.00-13.00-17.00Vb87.80
LD52.00D  : 9.0012.0014.00V74.05
LDB-50.00Db: -10.00-14.00-18.00Vb94.80
LD54.00D  : 8.0011.0014.00V69.85
LDB-51.00Db: -9.00-13.00-17.00Vb89.75




#102025 Robot 2WD homologable pour la coupe de france de robotique réalisé au dernier...

Posté par bvking sur 04 février 2019 - 04:07 dans Robots roulants, chars à chenilles et autres machines sur roues

Merci Mike pour tous les conseils. 

 

C bon, je controle mes moteurs dans les mêmes sens et à la même vitesse. 

 

J'ai simplifié comme ça la fonction de commande

 

void commandMotor (int8_t commandeMoteurDroit, int8_t commandeMoteurGauche) {

 
if (valeur >0){/
  
  SetpointB = commandeMoteurDroit;
  SetpointA = commandeMoteurGauche;
 
  }
 
  else  {
 
   SetpointB =  -commandeMoteurDroit;
   SetpointA =  -commandeMoteurGauche;
 
   } 
 
  //utilisation de la sortie du PID pour asservir les moteurs
  if (valeur >= 0) {
    advanceB();
  }
  if (valeur < 0) {
    backB();
  }
  if (valeur >= 0) {
    advanceA();
  }
  if (valeur < 0) {
    backA();
  }
 
J'ai retiré myPIDB.SetOutputLimits(-255, 255), pour lire la tension de sortie toujours positivement et que ça n'embrouille pas le programme (ou moi même).
 
Par contre petit truc, j'aurai aimé avoir la vitesse de mes moteurs hyper constante pour me rapprocher de la théorie du PID.,  
De sorte que, lorsque les moteurs sont censés être arrivés à leurs vitesses qui est stable dans le temps (celle de leur Setpoint), il y ait toujours le même décalage de phase entre eux.
 
Mes deux moteurs au bout de 2 minutes, ils se décalent de 90°. Ce qui est pas beaucoup sachant qu'ils tournent à 70BPM. Mais je sais pas s'il est peut être possible d'améliorer ce résultat en remplaçant des constantes byte par volatile byte ou unsigned char ou.....
 
 
Aussi quand, je bloque mes deux moteurs la tension augmente et quand je les lache, ils retournent à leurs vitesses asservies.
Ce qui est normal.
 
Mais quand je les bloque plus longtemps jusqu'à ce que  leur val_output atteint les 255, le moteur de gauche ne se "force plus" à revenir à son Setpoint il 'est à l'arrêt alors que celui de droite se comporte normalement, il fait des à coup.
.
C'est seulement quand je lache le moteur de droite que ça "débloque" le moteur de gauche qui retourne à son Setpoint. 
 
Là je pense que la vitesse détectée du moteur droit influence le calcule ou les attachinterrupt du moteur gauche.
 
D'où peut être l'utilité du mask comme dans votre premier programme avec un seul moteur, mais je ne sais pas comment l'intégrer au mien.
state|=B11101011;  // mask pour ne regarder que les changements sur 2 et 4 
  // Modifier le MASK  B01111011 par BXXXXXXXX mettre des 0 là où sont les pins utilisés par l'encodeur
  if( state!=laststate)
Je mets mon programme 
#include <PID_v1.h>

// PORT POUR KIT L298N 2nd (Bleu clair) supllied with 6 V
//  MOTEUR A  GAUCHE  avec myPIDA 8,9,5,3,7,

//Ports de commande du moteur A supplied with 6 volt= 90 round/min.

int motorPinA1 = 9; //13 pin to set H BRIDGE of L298N  
int motorPinA2 = 8; //12 pin to set H BRIDGE of L298N  
const int enablePinA= 5; //11 //  Commande de vitesse moteur, to Output ENA pour L298 the second

//  MOTEUR B Droit  avec myPIDB 10,11,6,2,4
  
//Ports de commande du moteur B supplied with 6 volt.

int motorPinB1 = 10; // pin to set H BRIDGE of L298N
int motorPinB2 = 11; //12 pin to set H BRIDGE of L298N
const int enablePinB= 6; //11 //  Commande de vitesse moteur, to Output ENA pour L298 the second



//MOTOR GAUCHE pin D 3,7,9,8,5
 
volatile byte encoderApinA = 3;//A pin -> the interrupt pin 3
byte encoderApinB = 7;//B pin -> the digital pin 7 /// What is better? byte or const byte ?

volatile byte encoderAPinALast;  // What is better? volatile byte encoderAPinALast or just byte encoderAPinALast  ?
double  latestDurationCountA,durationA,abs_durationA;//the number of the pulses
boolean DirectionA;//the rotation direction 
boolean resultA;

double val_outputA;//Power supplied to the motor PWM value.
double SetpointA;
double Kp=1, Ki=10, Kd=0.01; // 1 ; 10 ; 0.01
PID myPIDA(&abs_durationA, &val_outputA, &SetpointA, Kp, Ki, Kd, DIRECT); 


//**************************************************
//MOTOR DROIT myPIDB motor pinB+encoderB 2,4,11,10,6
volatile byte encoderBpinA = 2;//A pin -> the interrupt pin 1/*volatile byte
byte encoderBpinB = 4;//B pin -> the digital pin 4

volatile byte encoderBPinALast;
double  latestDurationCountB, durationB, abs_durationB; //the number of the pulses
boolean DirectionB;//the rotation direction 
boolean resultaB;

double val_outputB;//Power supplied to the motor PWM value.
double SetpointB;
//double Kp=0.6, Ki=5, Kd=0; // 0.6 ; 5 ; 0
PID myPIDB(&abs_durationB, &val_outputB, &SetpointB, Kp, Ki, Kd, DIRECT); 

unsigned long time0 = 0; // stock un temps à un instant donné
unsigned long timer = 0; // variable qui va contenir le dernier temps enregistré via millis

int8_t valeur = 20;  //lecture de la consigne via le moniteur serie pour test, initialisé à 40 pour test rapide du PID




void setup()

{  
  Serial.begin(19200);//Initialize the serial port
  
   // Configuration des ports en mode "sortie" A   moteur GAUCHE
  pinMode(motorPinA1, OUTPUT);
  pinMode(motorPinA2, OUTPUT);
  pinMode(enablePinA, OUTPUT);

   // Configuration des ports en mode "sortie" B moteur DROIT
   
   pinMode(motorPinB1, OUTPUT);   //L298N Control port settings direction of motor B (originaly L298N)
   pinMode(motorPinB2, OUTPUT);  //L298N Control port settings direction of motor B
   pinMode(enablePinB, OUTPUT);  // powerRate to control speed of motor B
   
   // REGLAGE PID MOTOR A (gauche)
   SetpointA; 
   
   myPIDA.SetMode(AUTOMATIC);//PID is set to automatic mode
   myPIDA.SetSampleTime(5);//Set PID sampling frequency is 100ms
  // myPIDA.SetOutputLimits(-255, 255);
   EncoderInitA();
  

   //REGLAGE PID MOTEUR DROIT (droit)
   
   SetpointB; 
   
   myPIDB.SetMode(AUTOMATIC);//PID is set to automatic mode
   myPIDB.SetSampleTime(5);//Set PID sampling frequency is 100ms
   //myPIDB.SetOutputLimits(-255, 255);
   EncoderInitB();
   

 
 
  
}
 
void loop()
{ if (Serial.available()) {
    time0 = timer;
    valeur = Serial.parseInt(); //récupération des caractères sur le port série
    Serial.println("-----------------valeur");Serial.println(valeur);
    
  }
  if (valeur != 0) {
    commandMotor(valeur,valeur);
  }
  else {
    SetpointA=0; SetpointB=0;
    stopMotors();
  }
  timer = millis();
  
  if ( (timer - time0) >120000) { // Timeout !
    valeur = 0 ;
    stopMotors();
    time0 = timer; 

 }  

//MOTOR GAUCHE 

      noInterrupts();
      latestDurationCountA = durationA;
      interrupts();
      abs_durationA = abs(latestDurationCountA);
        
      resultA=myPIDA.Compute();//PID conversion is complete and returns 1
      
    //   advanceA();
      if(resultA)
      {
        Serial.print("LD"); Serial.print(latestDurationCountA); 
        Serial.print("D  : ");  Serial.print(durationA); Serial.print(durationA); Serial.print(durationA);
        durationA = 0; //Count clear, wait for the next count
        //Serial.print("SetpointA"); Serial.println(SetpointA);
        Serial.print("V"); Serial.println(val_outputA);// volt to MOTOR= real speed
      }

        // *******************************************


  // SETTING  MOTEUR DROIT PIDB avec PIN B plus rapide?
   
      noInterrupts();
      latestDurationCountB = durationB;
      interrupts();
      abs_durationB = abs(latestDurationCountB);

     //  SetpointB=20; //
  
      resultaB=myPIDB.Compute();//PID conversion is complete and returns 1
      
    //  advanceB();
      
      if(resultaB){
  
        Serial.print("LDb"); Serial.print(latestDurationCountB);  
        Serial.print("Db: ");  Serial.print(durationB);Serial.print(durationB);Serial.print(durationB); 
        durationB = 0; //Count clear, wait for the next count
        //Serial.print("SetpointB"); Serial.println(SetpointB);
        Serial.print("Va"); Serial.println(val_outputB);// volt to MOTOR= real speed
      }
    
}


 
void EncoderInitA()
{
  DirectionA = true;//default -> Forward  
  pinMode(encoderApinB,INPUT);  
  attachInterrupt(1, wheelSpeedA, CHANGE);
}
 
void wheelSpeedA()
{
  byte Lstate = digitalRead(encoderApinA);
  if((encoderAPinALast == LOW) && Lstate==HIGH)
  {
    byte val = digitalRead(encoderApinB);
    if(val == LOW && DirectionA)
    {
      DirectionA = false; //Reverse
    }
    else if(val == HIGH && !DirectionA)
    {
      DirectionA = true;  //Forward
    }
  }
  encoderAPinALast = Lstate; // volatile byte encoderAPinALast ??
  
 
  if(!DirectionA)  durationA++;
  else  durationA--;

}
void advanceA()//Motor Forward
{
     digitalWrite(motorPinA1,HIGH);
     digitalWrite(motorPinA2,LOW);
     
     analogWrite(enablePinA,val_outputA);
}
void backA()//Motor reverse
{
      digitalWrite(motorPinA1,LOW);
     digitalWrite(motorPinA2,HIGH);
     
     analogWrite(enablePinA,val_outputA);
}

void StopA()//Motor stops
{
     digitalWrite(enablePinA, LOW); 
}

void EncoderInitB()
{
  DirectionB = true;//default -> Forward  
  pinMode(encoderBpinB,INPUT);  
  attachInterrupt(0, wheelSpeedB, CHANGE);
}
 
void wheelSpeedB()
{
  byte LstateB = digitalRead(encoderBpinA);
  if((encoderBPinALast == LOW) && LstateB==HIGH)
  {
    byte valB = digitalRead(encoderBpinB);
    if(valB == LOW && DirectionB)
    {
      DirectionB = false; //Reverse
    }
    else if(valB == HIGH && !DirectionB)
    {
      DirectionB = true;  //Forward
    }
  }
  encoderBPinALast = LstateB;
 
  if(!DirectionB)  durationB++;
  else  durationB--;

}
void advanceB()//Motor Forward
{
     digitalWrite(motorPinB1,HIGH);
     digitalWrite(motorPinB2,LOW);
     
     analogWrite(enablePinB,val_outputB);
}
void backB()//Motor reverse
{
      digitalWrite(motorPinB1,LOW);
     digitalWrite(motorPinB2,HIGH);
     
     analogWrite(enablePinB,val_outputB);
}

void StopB()//Motor stops
{
     digitalWrite(enablePinB, LOW); 

     
}

void stopMotors() {

  StopB();
  StopA();

 // digitalWrite(enablePinA, 0);
  //digitalWrite(enablePinB, 0);

}
void commandMotor (int8_t commandeMoteurDroit, int8_t commandeMoteurGauche) {

if (valeur >0){// || commandeMoteurDroit
  
  SetpointB = commandeMoteurDroit;
  SetpointA = commandeMoteurGauche;

  }

  else  {

   SetpointB =  -commandeMoteurDroit;
   SetpointA =  -commandeMoteurGauche;

   } 

  //int outputDroit = (int)val_outputB;   // creer nouvelle donnée de val-output egale à (int)val-outputB
  //int outputGauche = (int)val_outputA; //gauche

  //utilisation de la sortie du PID pour asservir les moteurs
  if (valeur >= 0) {
    advanceB();
  }
  if (valeur < 0) {
    backB();
  }
  if (valeur >= 0) {
    advanceA();
  }
  if (valeur < 0) {
    backA();
  }



}

Merci pour votre aide, j'espère n'être pas trop confus. :crazy:



#101964 Robot 2WD homologable pour la coupe de france de robotique réalisé au dernier...

Posté par bvking sur 30 janvier 2019 - 10:16 dans Robots roulants, chars à chenilles et autres machines sur roues

J'utilise une Uno.

 

Il se peut que pour le sens des moteurs, j'ai inversé les pin mais ce qui compte c'est que je puisse assigner à chaque moteur une vitesse, dans un sens ou dans l'autre et pouvoir visualiser les 2 vitesses (positive dans un sens , negative dans l'autre) 




#101944 Robot 2WD homologable pour la coupe de france de robotique réalisé au dernier...

Posté par bvking sur 29 janvier 2019 - 12:25 dans Robots roulants, chars à chenilles et autres machines sur roues

D'accord voilà le programme

// Manipulation des ports
// PIND :  RX TX 2 3 4 5 6 7
// https://www.arduino.cc/en/Reference/PortManipulation


#include <PID_v1.h>   // Pour le PID
#include <TimerOne.h> // Pour le timer

// commande du moteur droit
#define ENCODEURDROITA 2
#define ENCODEURDROITB 4
#define MOTEURDROITA 6       // contrôle vitesse moteur 1; PWM
#define MOTEURDROITB 10       // controle direction moteur 1
#define MOTEURDROITC 11

// commande du moteur 2
#define ENCODEURGAUCHEA 3
#define ENCODEURGAUCHEB 7
#define MOTEURGAUCHEA 5       // contrôle vitesse moteur 2; PWM
#define MOTEURGAUCHEB 8     // controle direction moteur 2
#define MOTEURGAUCHEC 9      // controle direction moteur 2


double SetpointDroit, InputDroit, OutputDroit;
double SetpointGauche, InputGauche, OutputGauche;

double Kp = 0.8, Ki = 5, Kd = 0;

PID PIDDROIT(&InputDroit, &OutputDroit, &SetpointDroit, Kp, Ki, Kd, DIRECT);
PID PIDGAUCHE(&InputGauche, &OutputGauche, &SetpointGauche, Kp, Ki, Kd, DIRECT);

// volatile => pour toute variable qui seront utilisées dans les interruptions
volatile int8_t countDroit = 0; /* comptage de tick d'encoder qui sera incrémenté sur interruption " On change " sur l'interruption 0  max 127 attention à l'overflow*/
volatile int8_t countGauche = 0; /* comptage de tick d'encoder qui sera incrémenté sur interruption " On change " sur l'interruption 1 max 127 attention à l'overflow */
volatile double speedDroit = 0; // vitesse du moteur
volatile double speedGauche = 0; // vitesse du moteur

unsigned long time0 = 0; // stock un temps à un instant donné
unsigned long timer = 0; // variable qui va contenir le dernier temps enregistré via millis

int8_t valeur = 0;  //lecture de la consigne via le moniteur serie pour test, initialisé à 40 pour test rapide du PID

void setup()
{
  //initialisation moniteur serie
  Serial.begin(9600);       // facultatif uniquement pour feedback
  Serial.println("cool");
  // on initialise les entrées et sorties
  pinMode(ENCODEURDROITA, INPUT_PULLUP);
  pinMode(ENCODEURDROITB, INPUT_PULLUP);
  pinMode(ENCODEURGAUCHEA, INPUT_PULLUP);
  pinMode(ENCODEURGAUCHEB, INPUT_PULLUP);
  
  

  pinMode(MOTEURDROITA, OUTPUT);
  pinMode(MOTEURDROITB, OUTPUT);
  pinMode(MOTEURDROITC, OUTPUT);
  pinMode(MOTEURGAUCHEA, OUTPUT);
  pinMode(MOTEURGAUCHEB, OUTPUT);
  pinMode(MOTEURGAUCHEC, OUTPUT);

  // moteurs à l'arret
  stopMotors();

  // Encoder quadrature counter
  attachInterrupt(0, counterDroit, CHANGE); // lorsqu'il y une modification sur le pin 2, on interrompte le programme pour enclencher le comptage
  attachInterrupt(1, counterGauche, CHANGE); // lorsqu'il y une modification sur le pin 3, on interrompte le programme pour enclencher le comptage

  Timer1.initialize(100);//80000            // set a timer of length  0.08 sec => permet d'avoir speed le plus proche de 127 sans dépasser 127 en vitesse max ! 
  Timer1.attachInterrupt( timerIsr );

  // PID
  InputDroit = 0;
  SetpointDroit = 0;
  InputGauche = 0;
  SetpointGauche = 0;
  //active le PID
  PIDDROIT.SetMode(AUTOMATIC);
  PIDDROIT.SetOutputLimits(-255, 255);
  PIDGAUCHE.SetMode(AUTOMATIC);
  PIDGAUCHE.SetOutputLimits(-255, 255);
}

void loop() {
  //while(1){test();}
  if (Serial.available()) {
    time0 = timer;
    valeur = Serial.parseInt(); //récupération des caractères sur le port série
    Serial.println("---------------------------valeur");Serial.println(valeur);
    
  }
  if (valeur != 0) {
    runMotorSpeed(valeur,valeur);
  }
  else {
    stopMotors();
  }
  timer = millis();
  if ( (timer - time0) > 90000) { //Timeout !
    valeur = 0 ;
    stopMotors();
    time0 = timer;
    
  }

  Serial.println("**************************speed1");
  Serial.println(speedDroit*100);                 // ne voit pas la speed evolué
  Serial.println("**************************speed2");
  Serial.println(speedGauche*100);                 // just 100 ou -100
  Serial.println("'''''''''''''''''");    // à commenter, utilisé pour débug

}



void counterDroit()
{
  byte state = PIND;
  (((state >> ENCODEURDROITA) & 1) ^ ((state >> ENCODEURDROITB) & 1)) ? countDroit-- : countDroit++; // régler ++ et -- pour que faire avancer => +
}

// Encoder counter 2

void counterGauche()
{
  byte state = PIND;
  (((state >> ENCODEURGAUCHEA) & 1 ) ^ ((state >> ENCODEURGAUCHEB) & 1)) ? countGauche++ : countGauche--; // régler ++ et -- pour que faire avancer => +
}


// Timer pour calculer la vitesse grace aux encodeurs

void timerIsr()
{
  speedDroit = countDroit;
  countDroit = 0;
  speedGauche = countGauche;
  countGauche = 0;
}

void stopMotors() {
  digitalWrite(MOTEURDROITA, HIGH);
  digitalWrite(MOTEURDROITB, HIGH);
  digitalWrite(MOTEURGAUCHEA, HIGH);
  digitalWrite(MOTEURGAUCHEB, HIGH);
}


void test() {

  digitalWrite(MOTEURDROITA, LOW);
  digitalWrite(MOTEURDROITB, LOW); // low fait avancer
  digitalWrite(MOTEURGAUCHEA, HIGH);
  digitalWrite(MOTEURGAUCHEB, LOW); // Low fait reculer

  Serial.println("speed1");
  Serial.println(speedDroit*100);                 // à commenter, utilisé pour débug
  Serial.println("speed2");
  Serial.println(speedGauche*100);                 // à commenter, utilisé pour débug
  Serial.println("'''''''''''''''''");    // à commenter, utilisé pour débug
}

void avancerMoteurDroit(uint8_t a) // En avant
{
  analogWrite (MOTEURDROITA, a); // Contrôle de vitesse en PWM, moteur 1
  digitalWrite(MOTEURDROITB, LOW); // sens de marche avec HIGH
   digitalWrite(MOTEURDROITC, HIGH); // sens de marche avec HIGH
}
void avancerMoteurGauche(uint8_t a) // En avant
{
  analogWrite (MOTEURGAUCHEA, 255 - a); // Contrôle de vitesse en PWM, moteur 2
  digitalWrite(MOTEURGAUCHEB, HIGH);
  digitalWrite(MOTEURGAUCHEC, LOW);
}

void reculerMoteurDroit (uint8_t a) // En arrière
{
  analogWrite (MOTEURDROITA, 255 - a);
  digitalWrite(MOTEURDROITB, HIGH);
  digitalWrite(MOTEURDROITC, LOW);
}
void reculerMoteurGauche (uint8_t a) // En arrière
{
  analogWrite (MOTEURGAUCHEA, a);
  digitalWrite(MOTEURGAUCHEB, LOW);
  digitalWrite(MOTEURGAUCHEC, HIGH);
}


void runMotorSpeed( int8_t commandeMoteurDroit, int8_t commandeMoteurGauche) {

  SetpointDroit = commandeMoteurDroit;
  SetpointGauche = commandeMoteurGauche;

  InputDroit = speedDroit;
  InputGauche = speedGauche;

  PIDDROIT.Compute();
  PIDGAUCHE.Compute();

  int outputDroit = (int)OutputDroit;
  int outputGauche = (int)OutputGauche;

  //utilisation de la sortie du PID pour asservir les moteurs
  if (outputDroit >= 0) {
    avancerMoteurDroit(outputDroit);
  }
  if (outputDroit < 0) {
    reculerMoteurDroit(-outputDroit);
  }
  if (outputGauche >= 0) {
    avancerMoteurGauche(outputGauche);
  }
  if (outputGauche < 0) {
    reculerMoteurGauche(-outputGauche);
  }
  // à commenter, utilisé pour débug
  Serial.println("output1");
  Serial.println(outputDroit);                
  Serial.println("output2");
  Serial.println(outputGauche);                
  Serial.println("'''''''''''''''''"); 
  Serial.println("-------------------speed1");
  Serial.println(InputDroit);                 // à commenter, utilisé pour débug
  Serial.println("-------------------speed2");
  Serial.println(speedGauche);                 // à commenter, utilisé pour débug
  Serial.println("'''''''''''''''''");       
}

Je n'arrive pas à voir la speed1 ou speed2 évolue, je vois seulement 100 ou -100 sur l'un ou l'autre des moteurs quand je tape -10 ou 10.

 

Merci de cette réponse rapide.

 

 




#101970 Robot 2WD homologable pour la coupe de france de robotique réalisé au dernier...

Posté par bvking sur 30 janvier 2019 - 05:14 dans Robots roulants, chars à chenilles et autres machines sur roues

J'ai inversé les ++ et -- et réciproquement. 

 

Au lieu de 80000, je mets 800 pour l'échantillonnage, sinon les moteurs saccadent.

 

Ce qui m'importe c'est que les deux moteurs tournent en même temps et à la même vitesse. 

 

J'ai filmé les reactions du moteurs.

 

Merci

 

Vous avez la video en pj?

 

Fichier joint  essaie pid 2.m4v.zip   9,3 Mo   188 téléchargement(s)




#101983 Robot 2WD homologable pour la coupe de france de robotique réalisé au dernier...

Posté par bvking sur 01 février 2019 - 03:19 dans Robots roulants, chars à chenilles et autres machines sur roues

Bonjour,

 

J'ai un programme que j'avais deja pour contrôler deux moteurs, et ils tournent parfaitement à la même vitesse et reste synchrones. Mes deux moteurs sont drivés avec un L289N et je relis sa masse à celle de l'Arduino.

 

J'ai inclus  void runMotorSpeed( int8_t commandeMoteurDroit, int8_t commandeMoteurGauche

 

Maintenant, j'arrive bien à detecter les vitesses des deux moteurs, alors que je n'y arrivai pas avec votre programme.

 

Mais par contre les deux moteurs ne vont pas à la même vitesse. J'ai l'impression que l'encodage de la vitesse de l'un entre en confusion avec l'autre.

 

Peut être faut'il mettre un mask comme dans votre tout premier programme?

 

Je vous mets mon programme, si vous pouvez m'éclairer là c'est trop compliqué pour moi.

 

Merci

Fichier(s) joint(s)




#118063 Interpolation à partir d'un pseudo cercle.

Posté par bvking sur 18 mars 2023 - 04:21 dans Projets logiciels, web, ou simulations

Yep!

 

Voilà le code qui reçoit les positions des 6 encodeurs.

J'ajouterai la fonction qui contrôle les 6 moteurs si tu veux.

Merci encore. 

import processing.serial.*;
Serial encoderReceiveUSBport101; // serial port receiving datas of positions of 6 motors
Serial teensyport; // serial port sending positions to 6 motors

int actualSec,lastSec,measure,measureToStartRecording;;
boolean bRecording = false;
boolean mouseRecorded =  true;

class Sample {
  int t, x, y;
  Sample( int t, int x, int y ) {
    this.t = t;  this.x = x;  this.y = y;
  }
}

class Sampler {
  
  ArrayList<Sample> samples;
  int startTime;
  int playbackFrame;
  
  Sampler() {
    samples = new ArrayList<Sample>();
    startTime = 0;
  }
  void beginRecording() {   
    samples = new ArrayList<Sample>();
    playbackFrame = 0;
  }
  void addSample( int x, int y ) {  // add sample when bRecording
    int now = millis();
    if( samples.size() == 0 ) startTime = now;
    samples.add( new Sample( now - startTime, x, y ) );
  }
  int fullTime() {
    return ( samples.size() > 1 ) ? 
    samples.get( samples.size()-1 ).t : 0;
  }
  void beginPlaying() {
    startTime = millis();
    playbackFrame = 0;
    println( samples.size(), "samples over", fullTime(), "milliseconds" );
  }
  
 
  void draw() {
    stroke( 255 );
    
    //**RECORD
    beginShape(LINES);
    for( int i=1; i<samples.size(); i++) {
      vertex( samples.get(i-1).x, samples.get(i-1).y ); // replace vertex with Pvector
      vertex( samples.get(i).x, samples.get(i).y );
    }
    endShape();
    //**ENDRECORD
    
    //**REPEAT
    int now = (millis() - startTime) % fullTime();
    if( now < samples.get( playbackFrame ).t ) playbackFrame = 0;
    while( samples.get( playbackFrame+1).t < now )
      playbackFrame = (playbackFrame+1) % (samples.size()-1);
    Sample s0 = samples.get( playbackFrame );
    Sample s1 = samples.get( playbackFrame+1 );
    float t0 = s0.t;
    float t1 = s1.t;
    float dt = (now - t0) / (t1 - t0);
    float x = lerp( s0.x, s1.x, dt );
    float y = lerp( s0.y, s1.y, dt );
    circle( x, y, 10 );
  }
  
}

Sampler sampler;

void setup() {  
  size( 800, 800, P3D );
  frameRate(30); // when size is set as P3D (3 dimension) we have 27 or 28 frame (loop) per seconde
  sampler = new Sampler();
  
  //********Sending and Receiving data with two different serialport
  String[] ports = Serial.list();
  printArray(Serial.list()); // display port in terminal
  //*************** TEENSY connected
   teensyport = new Serial(this, ports[0], 115200);// choose port matching to send data
  //*************** ENCODERD connected // comment below if port not connected
  //  encoderReceiveUSBport101 = new Serial(this, Serial.list()[1], 1000000);choose port matching to receive data
  //  Read bytes into a buffer until you get a linefeed (ASCII 10):
  //  encoderReceiveUSBport101.bufferUntil('\n');
}

void draw() {
  background( 0 );
  activeSampling();
  stopSampling();
  
  if  (actualSec!=lastSec){
       lastSec=actualSec;
       measure++;
       textSize (100);
       text (measure, 100, 100 );
     }
       actualSec =(int) (millis()*0.001);  // 
 
  if( bRecording) { // draw circle
    circle( mouseX, mouseY, 10 );
    sampler.addSample( mouseX, mouseY );
  }
  
  else {    
  if( sampler.fullTime() > 0 )
        sampler.draw();
  }
}

void mousePressed() {
  bRecording = true;   // draw circle
  mouseRecorded = true;
  measure=0;
}
  
void activeSampling() { 
   if (measure<=1 && measure>=1 &&actualSec!=lastSec && mouseRecorded == true) {
  sampler.beginRecording();
  }
}

void stopSampling() { 
   if (measure<=3 && measure>=3  && actualSec!=lastSec) {  
  mouseRecorded = false;
     //**REPEAT
  bRecording = false;
  sampler.beginPlaying();
  }
}

void serialEvent(Serial encoderReceiveUSBport101) { // receive 6 datas from serialport splited with , and a last is send with println

  // read the serial buffer:
  String myString = encoderReceiveUSBport101.readStringUntil('\n');

  // if you got any bytes other than the linefeed:
  myString = trim(myString);

  // split the string at the commas
  // and convert the sections into integers:
  int values[] = int(split(myString, ','));

  if (values.length > 0) {// v0 is value of the encodeur from 0 to 4000
  int v0; int v1; int v2; int v3; int v4; int v5;

    v0 = (int) map (values[0], 0, 4000, 0, 400);
    v1 = (int) map (values[0], 0, 4000, 0, 400);
    v2 = (int) map (values[0], 0, 4000, 0, 400);
    v3 = (int) map (values[0], 0, 4000, 0, 400);
    v4 = (int) map (values[0], 0, 4000, 0, 400);
    v5 = (int) map (values[0], 0, 4000, 0, 400);
           
    println (" v0 " + v0 ); println (" v1 " + v1 ); println (" v2 " + v2 ); println (" v3 " + v3 );
    println (" v4 " + v4 ); println (" v5 " + v5 );
}
}



#118073 Interpolation à partir d'un pseudo cercle.

Posté par bvking sur 18 mars 2023 - 08:48 dans Projets logiciels, web, ou simulations

Yep!

 

La v2 a l'air carrément mieux. Je dis à l'air, car il faut que je regarde dans la pratique. 

Je te dis çà demain.

Tres bonne soirée, et grrRRAAAAANNNNNNDDDDDDD merci!




#118134 Interpolation à partir d'un pseudo cercle.

Posté par bvking sur 22 mars 2023 - 01:39 dans Projets logiciels, web, ou simulations

Hello!

 

J'ai amélioré la methode pour enregistrer un mouvement circulaire

 

Mais le mouvement reproduit me fait ce genre de forme

 

 

class Sample {
int t;
float x, y;
Sample( int t, float x, float y ) {
this.t = t; this.x = x; this.y = y;
}
}

class Sampler {
 
ArrayList<Sample> samples;
ArrayList<Sample> samplesModified;
int startTime;
int playbackFrame;
 
Sampler() {
samples = new ArrayList<Sample>();
samplesModified = new ArrayList<Sample>();
startTime = 0;
}
void beginRecording() {
samples = new ArrayList<Sample>();
samplesModified = new ArrayList<Sample>();
playbackFrame = 0;
}
void addSample( float x, float y ) { // add sample when bRecording
int now = millis();
if( samples.size() == 0 ) startTime = now;
samples.add( new Sample( now - startTime, x, y ) );
}
int fullTime() {
return ( samples.size() > 1 ) ?
samples.get( samples.size()-1 ).t : 0;
}
void beginPlaying() {
startTime = millis();
playbackFrame = 0;
println( samples.size(), "samples over", fullTime(), "milliseconds" );
if(samples.size() > 0){
float deltax = samples.get(0).x - samples.get(samples.size()-1).x;
float deltay = samples.get(0).y - samples.get(samples.size()-1).y;
float sumdist = 0;
 
for(int i = 0; i < samples.size() - 1; i++) {
sumdist += sqrt((samples.get(i).x - samples.get(i +1 ).x)*(samples.get(i).x - samples.get(i +1 ).x) + (samples.get(i).y - samples.get(i +1 ).y)*(samples.get(i).y - samples.get(i +1 ).y));
}
 
samplesModified.add( new Sample(samples.get(0).t, samples.get(0).x , samples.get(0).y ) );
float dist = 0;
for(int i = 0; i < samples.size() - 1; i++) {
dist += sqrt((samples.get(i).x - samples.get(i +1 ).x)*(samples.get(i).x - samples.get(i +1 ).x) + (samples.get(i).y - samples.get(i +1 ).y)*(samples.get(i).y - samples.get(i +1 ).y));
samplesModified.add( new Sample(samples.get(i+1).t, (int) (samples.get(i +1).x + (dist * deltax) / sumdist), (int) (samples.get(i+1).y +( dist * deltay )/ sumdist)) );
print(samples.get(i).x);
print(",");
print(samples.get(i).y);
print(",");
print( " good data x " + samplesModified.get(i).x);
print(",");
print( " good data y " + samplesModified.get(i).y);
println("");
}
}
}
 
 
void draw() {
stroke( 255 );
 
//**RECORD
beginShape(LINES);
for( int i=1; i<samples.size(); i++) {
vertex( samplesModified.get(i-1).x, samplesModified.get(i-1).y ); // replace vertex with Pvector
vertex( samplesModified.get(i).x, samplesModified.get(i).y );
}
endShape();
//**ENDRECORD
 
//**REPEAT
int now = (millis() - startTime) % fullTime();
if( now < samplesModified.get( playbackFrame ).t ) playbackFrame = 0;
while( samplesModified.get( playbackFrame+1).t < now )
playbackFrame = (playbackFrame+1) % (samples.size()-1);
Sample s0 = samplesModified.get( playbackFrame );
Sample s1 = samplesModified.get( playbackFrame+1 );
float t0 = s0.t;
float t1 = s1.t;
float dt = (now - t0) / (t1 - t0);

float x =constrain (lerp( s0.x, s1.x, dt ),-300, 300);
float y =constrain (lerp( s0.y, s1.y, dt ),-300, 300);


circle( x, y, 20 );
 
textSize (50);
 
movementInterpolated = y ;
text (" x " + x + " y " + y + " mov " + movementInterpolated , 100, 300);

}
}

Sampler sampler;


 

Image(s) jointe(s)

  • Capture d’écran 2023-03-22 à 16.11.30.png



#118058 Interpolation à partir d'un pseudo cercle.

Posté par bvking sur 17 mars 2023 - 02:48 dans Projets logiciels, web, ou simulations

Yep,

Dans l'ideal la deniere interpolation est la plus lisse et donc m'intéresse le plus.

Mais comme je suis pressé d'avoir un resultat, la solution la plus simple m'ira.

 

Le but est quand je répète le cercle, celui ci passe par un point intermédiaire pour ne pas à avoir faire une saccade trop brutale pour revenir au point d'origine.

Surtout dans un cercle de 6400 points, il faut arriver à programmer:

Que si le point part de 0 et fini à 6234 point, alors il passe par le point intermédiaire, disons 6350, et continue à aller dans le meme sens,

c'est à dire à 0, sans revenir en arrière. Alors il faudrait que le point 0 devienne 6401.

Voiloù, c'est tout pour le moment ;)

Apres faudra penser à une solution quand le cercle tracé dépasse un tour, au quel cas il faudra considerer le point le plus proche et précédent le premier point, comme dernier point. 

Puis de meme, faire en sorte que le programme continue à faire tourner le cercle toujours dans le meme sens.

Merci Mike  :yahoo:




#118050 Interpolation à partir d'un pseudo cercle.

Posté par bvking sur 14 mars 2023 - 08:33 dans Projets logiciels, web, ou simulations

Bonjour à toutes et tous!

 

Pour un projet artistique, j'echantillonne (sampling) pendant deux secondes un pseudo cercle (pas entièrement fini) tracé à la souris.

Puis cette forme se répète toute seule.

 

J'aimerai ajouter entre le dernier et le premier point tracés, un point d'interpolation qui soit à la moyenne

de la droite affine crée par le premier et le dernier.

 

Il faut essayer de tracer un cercle sur deux secondes. L'enregistrement se fait à chaque changement de seconde.

(mais on est pas censé le savoir).

 

Merci pour votre aide ;) et ce n'est que le début!

int actualSec,lastSec,measure,measureToStartRecording;;
boolean bRecording = false;
boolean mouseRecorded =  true;

class Sample {
  int t, x, y;
  Sample( int t, int x, int y ) {
    this.t = t;  this.x = x;  this.y = y;
  }
}

class Sampler {
  
  ArrayList<Sample> samples;
  int startTime;
  int playbackFrame;
  
  Sampler() {
    samples = new ArrayList<Sample>();
    startTime = 0;
  }
  void beginRecording() {   
    samples = new ArrayList<Sample>();
    playbackFrame = 0;
  }
  void addSample( int x, int y ) {  // add sample when bRecording
    int now = millis();
    if( samples.size() == 0 ) startTime = now;
    samples.add( new Sample( now - startTime, x, y ) );
  }
  int fullTime() {
    return ( samples.size() > 1 ) ? 
    samples.get( samples.size()-1 ).t : 0;
  }
  void beginPlaying() {
    startTime = millis();
    playbackFrame = 0;
    println( samples.size(), "samples over", fullTime(), "milliseconds" );
  }
  
 
  void draw() {
    stroke( 255 );
    
    //**RECORD
    beginShape(LINES);
    for( int i=1; i<samples.size(); i++) {
      vertex( samples.get(i-1).x, samples.get(i-1).y ); // replace vertex with Pvector
      vertex( samples.get(i).x, samples.get(i).y );
    }
    endShape();
    //**ENDRECORD
    
    //**REPEAT
    int now = (millis() - startTime) % fullTime();
    if( now < samples.get( playbackFrame ).t ) playbackFrame = 0;
    while( samples.get( playbackFrame+1).t < now )
      playbackFrame = (playbackFrame+1) % (samples.size()-1);
    Sample s0 = samples.get( playbackFrame );
    Sample s1 = samples.get( playbackFrame+1 );
    float t0 = s0.t;
    float t1 = s1.t;
    float dt = (now - t0) / (t1 - t0);
    float x = lerp( s0.x, s1.x, dt );
    float y = lerp( s0.y, s1.y, dt );
    circle( x, y, 10 );
  }
  
}

Sampler sampler;

void setup() {  
  size( 800, 800, P3D );
  frameRate( 30 );  
  sampler = new Sampler();
}

void draw() {
  background( 0 );
  activeSampling();
  stopSampling();
  
  if  (actualSec!=lastSec){
       lastSec=actualSec;
       measure++;
       textSize (100);
       text (measure, 100, 100 );
     }
       actualSec =(int) (millis()*0.001);  // 
 
  if( bRecording) { // draw circle
    circle( mouseX, mouseY, 10 );
    sampler.addSample( mouseX, mouseY );
  }
  
  else {    
  if( sampler.fullTime() > 0 )
        sampler.draw();
  }
}

void mousePressed() {
  bRecording = true;   // draw circle
  mouseRecorded = true;
  measure=0;
}
  
void activeSampling() { 
   if (measure<=1 && measure>=1 &&actualSec!=lastSec && mouseRecorded == true) {
  sampler.beginRecording();
  }
}

void stopSampling() { 
   if (measure<=3 && measure>=3  && actualSec!=lastSec) {  
  mouseRecorded = false;
     //**REPEAT
  bRecording = false;
  sampler.beginPlaying();
  }
}

Image(s) jointe(s)

  • Capture d’écran 2023-03-14 à 20.28.39.png



#118147 Interpolation à partir d'un pseudo cercle.

Posté par bvking sur 24 mars 2023 - 01:02 dans Projets logiciels, web, ou simulations

Hello! resultat parfait bientôt! 

Cool on peut faire un pseudo cercle, s'arrêter avant ou aller un peu plus loin que le point de départ et le mouvement se répète parfaitement!
Mais ceci est vrai si on commence le mouvement sur la partie gauche du cercle trigo! Pas depuis la partie droite.
J'ai mis des lignes pour repérer le point de départ de l'enregistrement, qui d'ailleurs commence des qu'on clique sur la sourie et s'arrête au bout de deux secondes.

 

Capture d’écran 2023-05-14 à 20.10.28.png
 
Si tu commences à faire le mouvement depuis la premiere ligne jusqu’a la deuxième et un peu plus, ton programme fonctionne , le mouvement tourne en boucle.
Mais si je pars  de la deuxième ligne, comme sur le screen shot  et que je m’arrête à la troisième et un peu plus ça ne fonctionne pas .
Peux tu corriger ce problème , stp ? :thank_you: 
 

int actualSec,lastSec,measure,measureToStartRecording;
boolean bRecording = false;
boolean mouseRecorded =  true;
float movementInterpolated, angleToInterpolate;
int numberOfSample;

//--------------------        method of interpolation to return the position of (rotation) by adding modulo
float mlerp(float x0, float x1, float t, float M ){
   float dx = (x1 - x0 + 1.5*M) % M - 0.5*M;
   return (x0 + t * dx + M) % M;
}

class Sample {
int t;
float x, y;
Sample( int t, float x, float y ) {
this.t = t; this.x = x; this.y = y;
}
}

class Sampler {

ArrayList<Sample> samples;
ArrayList<Sample> samplesModified;
int startTime;
int playbackFrame;

Sampler() {
samples = new ArrayList<Sample>();
samplesModified = new ArrayList<Sample>();
startTime = 0;
}
void beginRecording() {
samples = new ArrayList<Sample>();
samplesModified = new ArrayList<Sample>();
playbackFrame = 0;
}
void addSample( float x, float y ) { // add sample when bRecording
int now = millis();
if( samples.size() == 0 ) startTime = now;
samples.add( new Sample( now - startTime, x, y ) );
}
int fullTime() {
return ( samples.size() > 1 ) ?
samples.get( samples.size()-1 ).t : 0;

}
void beginPlaying() {
startTime = millis();
playbackFrame = 0;
println( samples.size(), "samples over", fullTime(), "milliseconds" );
if(samples.size() > 0){
  numberOfSample=samples.size();
  
float deltax = samples.get(0).x - samples.get(samples.size()-1).x;
float deltay = samples.get(0).y - samples.get(samples.size()-1).y;
float sumdist = 0;

for(int i = 0; i < samples.size() - 1; i++) {
sumdist += sqrt((samples.get(i).x - samples.get(i +1 ).x)*(samples.get(i).x - samples.get(i +1 ).x) + (samples.get(i).y - samples.get(i +1 ).y)*(samples.get(i).y - samples.get(i +1 ).y));
}
samplesModified.add( new Sample(samples.get(0).t, samples.get(0).x , samples.get(0).y ) );
float dist = 0;
for(int i = 0; i < samples.size() - 1; i++) {
dist += sqrt((samples.get(i).x - samples.get(i +1 ).x)*(samples.get(i).x - samples.get(i +1 ).x) + (samples.get(i).y - samples.get(i +1 ).y)*(samples.get(i).y - samples.get(i +1 ).y));
samplesModified.add( new Sample(samples.get(i+1).t, (float) (samples.get(i +1).x + (dist * deltax) / sumdist), (float) (samples.get(i+1).y +( dist * deltay )/ sumdist)) );
print(samples.get(i).x);
print(",");
print(samples.get(i).y);
print(",");
print( " good data x " + samplesModified.get(i).x);
print(",");
print( " good data y " + samplesModified.get(i).y);
println("");
}
}
}

 void draw() {
stroke( 255 );
//**RECORD
beginShape(LINES);
for( int i=1; i<samples.size(); i++) {
vertex( samplesModified.get(i-1).x, samplesModified.get(i-1).y ); // replace vertex with Pvector
vertex( samplesModified.get(i).x, samplesModified.get(i).y );
}
endShape();
//**ENDRECORD

//**REPEAT
int now = (millis() - startTime) % fullTime();
if( now < samplesModified.get( playbackFrame ).t ) playbackFrame = 0;
while( samplesModified.get( playbackFrame+1).t < now )
playbackFrame = (playbackFrame+1) % (samples.size()-1);
Sample s0 = samplesModified.get( playbackFrame );
Sample s1 = samplesModified.get( playbackFrame+1 );
float t0 = s0.t;
float t1 = s1.t;
float dt = (now - t0) / (t1 - t0);

//float x =lerp( s0.x, s1.x, dt );  // interpolation without modulo
//float y =lerp( s0.y, s1.y, dt ); // 

float x =mlerp( s0.x, s1.x, dt, TWO_PI ); // interpolation with modulo, it's better
float y =mlerp( s0.x, s1.x, dt, TWO_PI );

movementInterpolated = y ;
text (" mov " +  (movementInterpolated) , 100, 500);
fill (255,255,255);
circle ( 100* cos (movementInterpolated)+200, 100*sin (movementInterpolated)+200, 20);
stroke(255);
 }
}

Sampler sampler;

void setup() {  
  size( 800, 800, P3D );
  frameRate(30); // when size is set as P3D (3 dimension) we have 27 or 28 frame (loop) per seconde
  sampler = new Sampler(); 
  mouseY= height/2;
}

void draw() {
  background(50);
   for (int i=0; i<=8; i++ ){ 
    stroke(2);
  line (0, height/8*i, width, height/8*i); // horizon
  line (width/8*i, 0, width/8*i, height); // vertical

  }
  textSize (20);
   //----------------------------------------
  angleToInterpolate = (float) map (mouseY, 0, 200, 0, TWO_PI)%TWO_PI; 
  fill( 100, 0, 0);
  circle ( 100* cos (angleToInterpolate)+200, 100*sin (angleToInterpolate)+200, 20); 
  //----------------------------------------
  pushMatrix();
  translate(width/2, height/2);
  rotate(angleToInterpolate);
  translate(28, 0);
  rect(-30, -5, 60, 10);
  popMatrix();
  //----------------------------------------
  ellipse(width/2, height/2, 5, 5);
  text( " repeted  " +nf (movementInterpolated, 0, 2)  + " original " +nf (angleToInterpolate,0,2 ),width/2, height/4);
//  text( " repeted  " +nf (movementInterpolated, 0, 2) , 10, 0);
  textSize (20);
    /*
      for(int i = 0; i < samples.size() - 1; i++) {
       text (" angleModif " +    sampledModifiedChecking[i], 0, 100+ 20*i);
       text (" angleModif " + samplesModified.get(i).x, 100+ 20*i);
      }
    */

 if  (actualSec!=lastSec){
       lastSec=actualSec;
       measure++;
   }
   
  text (measure, 100, 100 );
  actualSec =(int) (millis()*0.001);  // 

  activeSampling();
  stopSampling();
  
  if( bRecording) { // draw circle
 //   circle( mouseX, mouseY, 10 );
 //   sampler.addSample( mouseX, mouseY );
     textSize(100);
     fill (0, 255, 0);
     text (measure, 200, 100 );
  sampler.addSample( angleToInterpolate, angleToInterpolate );
  }
  
  else {    
  if( sampler.fullTime() > 0 )
        sampler.draw();
  }

  if(numberOfSample > 0){
  
  println (frameCount%numberOfSample+1 + " " + movementInterpolated);
  }
}

void mousePressed() {
  bRecording = true;   // draw circle
  mouseRecorded = true;
  measure=0;
}
  
void activeSampling() { 
  if (measure==0 && actualSec!=lastSec && mouseRecorded == true) {
     textSize(100);
    
     fill (0, 255, 0);
     text (measure, 200, 100 );
  sampler.beginRecording();
  }
}

void stopSampling() { 
  if (measure==2 && actualSec!=lastSec) {  
     textSize(100);
   
     fill (255, 0, 0); 
       text (measure, 200, 100 );
  mouseRecorded = false;
     //**REPEAT
  bRecording = false;
  sampler.beginPlaying();
  }
}



#118940 Tige creuse Vs barre carré creuse ? carbone et télescopique ?

Posté par bvking sur 04 juillet 2023 - 01:54 dans Mécanique

Merci Oracid,

sur cette video on voit les moteurs auxquelles sont accrochés des barres plates en aluminuim

Tout fonctionne car elle ne mesure que 50 cm. Et le systeme de LED pese 15 grammes ici.

 

J'ai peur que des tubes PVC soient trop flexibles avec une masse de 35 grammes au bout de la barre de 70cm.

Aussi je ne dois pas dépasser une largeur de barre de plus 10 mm pour des raisons esthétiques.

 




#118936 Tige creuse Vs barre carré creuse ? carbone et télescopique ?

Posté par bvking sur 04 juillet 2023 - 12:32 dans Mécanique

Bonjour,

 

Je fais tourner des barres en L en alu de 100 g et 100 mm.  La barre n'est pas fixée au moteur en son centre mais à 70/30 cm.

Au bout des 70 cm est fixée une masse de 15 g. Cette masse est un sytème de LED.

Les moteurs pas à pas peuvent soutenir un couple de 1.2 N.m soit 122 g/m , si je ne m'abuse. 

 

Sans faire de calcul, la masse de ma barre est trop lourde. Je l'ai choisie en L pour qu'elle soit rigide.

Existent-ils des tiges ou barres creuses que je puisse assembler avec des bagues? ou encore mieux télescopiques? ou plus simplement de un mètre ? (que je découperai ensuite)

 

Je veux garder la dysymetrie 70/ 30 ou 80/20 ou 90/10 (selon que le moteur puisse supporter) pour fixer un bloc de pile du coté des 20 cm pour alimenter à l'autre bout de la tige le système de LED.

 

Grand merci pour vos suggestions.

Benj ;)

 

 

 

 

 




#118944 Tige creuse Vs barre carré creuse ? carbone et télescopique ?

Posté par bvking sur 04 juillet 2023 - 09:18 dans Mécanique

Yep,

Les profiles que j'ai vus sont des carrés de 10mm et ont une diamètre interne de 8.5 mm. On note 10*10*8.5

J'ai calculé la taille d'un carré que l'on peut mettre dans un cercle de 8.5 mm.

On peut mettre un carré de 6.01 mm exactement.
Donc normalement, je pourrais mettre un petit profile 6*6*5 dans un gros de 10*10*8.5.
Il faudra peut etre forcer un peu puis mettre une vis une rondelle et un boulon.
Sinon le vendeur me propose des tube de 3 mm d'épaisseur mais je suis pas sûr qu'ils ne vont pas osciller si je passe de 0 à 360° en une seconde et que je m'arrête.
Bref j'hésite, ou alors je fabrique une antenne télescopique moi meme?
Qu'en pensez vous?
 
voici le lien des profiles carrés
et le lien des tubes de 3 mm d'épaisseur qui peuvent peut etre tout simplement faire le travail



#118942 Tige creuse Vs barre carré creuse ? carbone et télescopique ?

Posté par bvking sur 04 juillet 2023 - 06:34 dans Mécanique

Les tubes PVC en 30mm ou 40mm sont assez rigides.

Ils peuvent être assemblés assez facilement, c'est leur avantage.

 

Une petite photo aiderait beaucoup à la compréhension du problème.

en fait je viens d'acheter des tubes carrés en carbones pultrudés pour avoir une bonne rigidité.

Ils vont peser 64 g au lieu de 100 g.

 

J'espere trouver un système télescopique de tubes carrés ou hexagonaux à l'avenir. Si vous avez une suggestion?




#118946 Tige creuse Vs barre carré creuse ? carbone et télescopique ?

Posté par bvking sur 05 juillet 2023 - 08:59 dans Mécanique

Helio.  :yahoo:

Je voudrais faire télescopique pour des raisons mécaniques et de modularités.

Moins les profils sont grands, moins je dois avoir de couple à exercer sur mon système de LED. 

Avec un format plus petit de profilés je pourrais mettre des systèmes de LED plus lourd à l'avenir.

Aussi j'aimerais que ce soit pratique à transporter car je compte installer ma machine dans divers festivals.

 

Alors j'ai pensé à un système télescopique en encastrant un petit  profilé de 6*6 mm dans un grand profilé au diamètre interne de 8.5 mm

Ce dernier ayant un rayon de 4.25 mm avec Pythagore l' hypotenuse mesure 6.01 mm.

Donc j'aurai un jeu de 0.01 mm. 

Une fois que j'aurais rentré le petit profilé dans l'autre j'aurai du mal à le ressortir mais c'est vraiment pas grave.

Je serai certain de la raideur de la perche créée et de sa legerté. 

Cela vous semble une bonne idée ou y'a t'il plus simple?

 

Par exemple fixer à l'axe moteur un tube carré creux ou circulaire en aluminium de 55 cm de longueur. Puis encastrer un profilé en carbone de 50 cm de longueur dans le tube carré ou circulaire ?

 

Sachant que une longueur de 1 mètre me suffit et que je ne veux pas dépasser une masse de 180 g.

( en fait je vais acheter des moteurs qui vont soutenir jusqu'a 2.2 N .m soit 224 g.m )

 

J'ai vu une perche télescopique pour un micro (donc supportant une masse lourde) sur Amazon qui va jusqu'à 3 metres et pese 260 g. Mais elle est donc trop lourd et un peu cher 30 euros

https://www.amazon.fr/Dextension-Microphone-Réglables-Interface-Transport/dp/B0B2VZ53R4/ref=sr_1_118?keywords=perche+micro&qid=1688540220&sr=8-118




#114838 Couplage moteur pas à pas NEMA 17. Quel bon réducteur choisir ?

Posté par bvking sur 07 décembre 2021 - 05:46 dans Mécanique

- pour le lien thingiverse, ça m'éttonnerait qu'il le vende (thingiverse, c'est plutôt du partage). Par contre, tu as les modèles 3D à télécharger. Tu peux donc le fabriquer toi même. Si tu n'as pas d'imprimante 3D, tu peux soit te rapprocher du Fablab le plus proche, soit utiliser un service d'impression 3D (Mike en propose un par exemple)

 

Merci Sandro. Je pense que je vais revendre mes NEMA 17 sur ce site, et acheter les "memes" avec un ratio de 5 ou 3.71. Je vais mettre deux fois moins de step par tour sur le driver.  Comme ca, j'aurai un ratio de 1/2*5 ou ou 1/2*3.71. Comme ça j'aurai pas besoin de super overlocker la teensy. Et j'imagine que d'imprimer un réducteur coute au dela de  15€




#114805 Couplage moteur pas à pas NEMA 17. Quel bon réducteur choisir ?

Posté par bvking sur 03 décembre 2021 - 12:48 dans Mécanique

Bonjour,

 
J'ai fixé un poids de 15 g sur une barre en aluminium de 40 cm. Cette barre est fixée perpendiculairement à l'axe de mon moteur pas à pas Nema 17 et mon poids tourne très bien, avec de belles accelerations et à grande vitesse.
 
Le mien est le septième en partant du haut.
 
Couple de maintien (N.cm Min)

40

Couple de détente (N.cm Max)

2.2

J'aimerais rajouter un réducteur pour faire tourner une masse de 80 g ou, 120 g si possible, grâce à un réducteur, sans que mon NEMA17 décroche et en gardant son accélération (2.5 tours-2) et sa vitesse (2.5 tours.) Les deux derniers les paramètres étant gérés par un Teensy (Arduino avec une horloge beaucoup plus rapide), il ne devrait pas y avoir de problème pour multiplier par 5, si j'ai une réduction de 5:1.

Mon nema 17 fait 200 pas/tour, je gère mon moteur en 6400 pas/tour (soit 32*200 pour avoir moins de vibrations et plus de couplage). Mais peu importe.

Pensez-vous que ces réducteurs (voir en bas) sont facilement montables et feront l'affaire ? Quelle réduction choisir, pour passer d'une masse de 15g à 80 ou 120 grammes  ?

L'axe moteur de mon nema 17 est de 5 mm, j'aimerais pouvoir coupler un réducteur qui a aussi son axe moteur de 5 mm. Ou alors il faut que je trouve un moyen de réduire l'axe moteur du réducteur si besoin, mais je sais pas ce qui existe.

Merci pour votre attention et vos réponses !

 

https://fr.aliexpress.com/item/1005001652781953.html?src=google&src=google&memo1=freelisting&albch=apprmkt&albagn=182499396&albcp=1735154771&albag=73623194291&albad=338294380753&aff_short_key=irey5Th&isdl=y&aff_platform=true&albslr=%7B%7D&gclid=Cj0KCQiA-qGNBhD3ARIsAO_o7yn_kb7rFM47y_VJf1u-7r71EBpTwIctdKPNa6MzDJEeAkfFy8atkZAaAl4FEALw_wcB

 

https://fr.aliexpres...cB&gclsrc=aw.ds

 

J'ai vu sur ce site quelqu'un qui a fabriqué un réducteur avec une imprimante 3D. Vend il son systeme?

 

https://www.thingive...m/thing:1743732




#114841 Couplage moteur pas à pas NEMA 17. Quel bon réducteur choisir ?

Posté par bvking sur 07 décembre 2021 - 08:22 dans Mécanique

si tu mets deux fois moins de step/tour sur le driver, ça ne change rien au couple, tu augmente juste la vitesse (si le moteur arrive à suivre)

 

oui, en mettant deux fois moins de step/tour sur le drive, je vais deux fois plus vite, et je vais calibrer ma rotation sur 2*moins de pas.

​Mais si je mets un ratio de 5, j'aurais bien ma vitesse qui va être de 2/5 plus lente et avoir un couple de 5/2 fois plus fort que à l'origine si je touchais pas au driver?