Freez du moniteur série et de moteur

Bonjour, je bosse sur un robot de self-balancing suivant ce tutoriel instructable

Pour un potentiel usage WIFI avec un Arduino nano 33 IoT, j'ai changé le microcontroleur de arduino mini à arduino nano. J'ai aussi changé le controleur moteur (simple erreur de commande), le DRV8833 devient un SparkFun TB6612.

Le problème que j'ai est que quand l'upload le sketch complet du robot ci-dessous, j'arrive à apercevoir une fluctuation de la vitesse en fonction de l'inclinaison cependant au-bout d'un certaint temps, le moniteur série n'affiche plus les nouvelles vitesse et les moteurs sont bloqué à la dernière vitesse affiché

#include "Wire.h"

#include "I2Cdev.h"
#include "MPU6050.h"
#include "math.h"

#include <SparkFun_TB6612.h>
#include <SoftwareSerial.h>

int count = 0;

// ===== MOTOR CONFIGURATION =====
// Configuration des sens de rotation des moteurs (1 ou -1)
const int offsetA = 1;
const int offsetB = -1;
// Ports numériques associés aux entrées de contrôle (les entrées PWM doivent être connectées à des ports PWM de l'Arduino)

#define AIN1 4
#define PWMA 5
#define BIN2 6
#define BIN1 7
#define STBY 8
#define AIN2 10
#define PWMB 11

volatile int motorPower = 200;

// Initialisation des moteurs
Motor motorA = Motor(AIN1, AIN2, PWMA, offsetA, STBY);
Motor motorB = Motor(BIN1, BIN2, PWMB, offsetB, STBY);


// ===== US sensor CONFIGURATION =====
// Constate for US sensor

#define TRIGGER_PIN 3
#define ECHO_PIN 2
#define MAX_DISTANCE 75


SoftwareSerial mySerial(TRIGGER_PIN, ECHO_PIN);

unsigned int HighByte = 0;
unsigned int LowByte  = 0;
unsigned int distancemm;
int distanceCm;

// ===== MPU6050 CONFIGURATION =====
// Constate for acelerometer and gyroscope
#define Kp  50
#define Kd  0
#define Ki  0

#define sampleTime  0.005

float targetAngle = 3;

MPU6050 mpu;


int16_t accX, accZ, gyroY;
volatile int gyroRate;
volatile float accAngle, gyroAngle, currentAngle, prevAngle=0, error, prevError=0, errorSum=0;

// ===== LED CONFIGURATION =====
// Led pin
#define Greenled 12
#define Redled  13


// Flashing of leds at initialization
void ledFlashing(int led[], int length){
  Serial.println("[LEDFLASHING] led flashing ...");

  for(int i = 0; i < length; i++){
    digitalWrite(led[i], HIGH);
  }
  delay(500);
  for(int i = 0; i < length; i++){
    digitalWrite(led[i], LOW);
  }
  delay(500);
  for(int i = 0; i < length; i++){
    digitalWrite(led[i], HIGH);
  }
  delay(500);
  for(int i = 0; i < length; i++){
    digitalWrite(led[i], LOW);
  }
}

// set motors speed
void setMotors(int leftMotorSpeed, int rightMotorSpeed) {
  // Serial.print("speed left and right : \t");
  // Serial.print(leftMotorSpeed);
  // Serial.print("\t");
  // Serial.println(rightMotorSpeed);
  motorA.drive(leftMotorSpeed);
  motorB.drive(rightMotorSpeed);
}

void init_PID() {
  // initialize Timer1
  cli();          // disable global interrupts
  TCCR1A = 0;     // set entire TCCR1A register to 0
  TCCR1B = 0;     // same for TCCR1B
  // set compare match register to set sample time 5ms
  OCR1A = 9999;
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS11 bit for prescaling by 8
  TCCR1B |= (1 << CS11);
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  sei();          // enable global interrupts
}

void setup() {
  mySerial.begin(9600);

  Serial.begin(9600);
  Serial.println(" === CASPER v2 ===");
  Serial.println("[SETUP] begin ...");


  // set the status LED to output mode
  pinMode(Greenled, OUTPUT); // Blue flashing
  pinMode(Redled, OUTPUT);  // Red obstacle detector
  // flashing of led
  int led_pin[2] = {Greenled, Redled};
  ledFlashing(led_pin, 2);

  // initialize the MPU6050 and set offset values
  mpu.initialize();

  Serial.println(F("[SETUP] Testing device connections..."));
  Serial.println(mpu.testConnection() ? F("[SETUP] MPU6050 connection successful") : F("[SETUP] MPU6050 connection failed"));

  Serial.println("[SETUP] Yaccel");
  mpu.setYAccelOffset(1593);
  Serial.println("[SETUP] Zaccel");
  mpu.setZAccelOffset(963);
  Serial.println("[SETUP] XGyro");
  mpu.setXGyroOffset(40);

  // initialize PID sampling loop
  Serial.println("[SETUP] init pid");
  init_PID();
  Serial.println("[SETUP] done ...");
}

void loop() {
  // read acceleration and gyroscope values
  accX = mpu.getAccelerationX();
  accZ = mpu.getAccelerationZ();
  gyroY = mpu.getRotationY();

  // set motor power after constraining it
  motorPower = constrain(motorPower, -255, 255);
  Serial.println(motorPower);
  setMotors(motorPower, motorPower);

  // measure distance every 100 milliseconds
  if((count%20) == 0){
      mySerial.flush();
      mySerial.write(0X55);                           // trig US-100 begin to measure the distance
      if (mySerial.available() >= 2)                  // check receive 2 bytes correctly
      {
        HighByte = mySerial.read();
        LowByte  = mySerial.read();
        distancemm  = HighByte * 256 + LowByte;          // Calculate the distance

        if ((distancemm > 1) && (distancemm < 10000)) {
          distanceCm = distancemm/10;
        }
      }
  }

  // if((distanceCm < 20) && (distanceCm != 0)) {
  //   digitalWrite(Redled, HIGH);
  //   targetAngle = 42.5;
  // }
  // else {
  //   digitalWrite(Redled, LOW);
  //   targetAngle = 40.75;
  // }

}

// The ISR will be called every 5 milliseconds
ISR(TIMER1_COMPA_vect)
{
  // calculate the angle of inclination
  accAngle = atan2(accX, accZ)*RAD_TO_DEG;
  gyroRate = map(gyroY, -32768, 32767, -250, 250);
  gyroAngle = (float)gyroRate*sampleTime;
  currentAngle = 0.9934*(prevAngle + gyroAngle) + 0.0066*(accAngle);
  error = currentAngle - targetAngle;
  errorSum = errorSum + error;
  errorSum = constrain(errorSum, -300, 300);
  //calculate output from P, I and D values
  motorPower = Kp*(error) + Ki*(errorSum)*sampleTime - Kd*(currentAngle-prevAngle)/sampleTime;
  prevAngle = currentAngle;

  // toggle the led on pin13 every second
  count++;
  if(count == 200)  {
    count = 0;
    digitalWrite(Greenled, !digitalRead(Greenled));
  }
}

Je vous joint aussi le schéma de montage

J'avoue être franchement à court de pistes
Merci D'avance
Breizh

Il faudrait peut-être interdire les IT pendant la mise à jour de accX, accZ, gyroY.
Parce que là tu peux te retrouver à calculer sur des valeurs en cours de modification

Je ne suis pas sur que ça pose problème. J'ai déjà fait un robot similaire avec plus ou moins le même code (en tout cas le même fonctionnement entre les interruption et les modification des variables de mon MPU6050) mais pourquoi pas, simplement comment fait ont pour interdire les interruption à ses moment la ? il existe une sorte de mutex pour ça ?

Tu as quantifié le temps passé dans l'ISR?

OK, du coup en ajoutant nointerrupts() puis interrupts() autour des get du gyroscope, j'ai le même problème de coupure du moniteur série mais au setup cette fois ^^"

Le temps passé dans l'ISR doit être suffisamment infime, dans je fait chronomètre avec millis() (temps pris au début et à la fin de la fonction puis différence entre les deux) obtient zero

Avec des calculs en flottant, j'en serais surpris.

Les IT sont masquées dans l'ISR. Donc millis() ne fonctionne pas.
Par contre, il me semble que micros() continue à fonctionner.

J'avais pas fait attention à ça auparavant.
Le buffer de Serial doit être saturé.
Il faut passer à un débit bien plus élevé.
Par exemple:
Serial.begin(115200);

Il y a pas mal d'affichage pendant le setup(). Faire un Serial.flush pour s'assurer que le buffer de transmission est vide avant d'attaquer loop().

OK, alors pour le temps de ISR avec micros() on tourne aux alentours de 370 micros seconde

Pour le temps du sérial j'ai essayé avec 115200 du coup. Alors sans allumer les moteurs, ça le plante plus, par contre dès que j'allume les moteurs (j'allume l'interrupteur), le moniteur série freez de la même manière, même avec le Serial.flush()

Après, le problème du moniteur série est embêtant par rapport au débogage mais mon plus gros problème reste le blocage des moteur à la vitesse constante

Sur une nano (je ne connais pas la nano 33Iot) es 10 bits les moins significatifs continuent de tourner, mais pas les suivants. Si la mesure dure moins de 1ms, un résultat positif est bon, et il faut rajouter 1024 si le résultat est négatif. Avec 370µs, cela fonctionne.
Si la mesure est entre 1ms et 2ms milli et micros fonctionnent encore car la lecture se fait hors interruption. Si il y a une inter qui intervient pendant l'ISR, elle est traitée à la sortie de l'ISR.

(Sur le schéma, il n'y a qu'un interrupteur, si il est éteint rien ne doit marcher.)
(La batterie est dessinée à l'envers, mais cela ne gêne que les vieux du schéma).
Si sans les moteurs, cela fonctionne et cela plante juste en mettant les moteurs, c'est peut être qu'ils parasitent l'alim de la Nano.

Dans la datasheet, il mettent un condo de 10µF en parallèle avec un 100nF sur les deux alims (5V et Vmoteur).

oui, sauf si j’alimente l'arduino avec un câble USB ce qui est le cas pendant le débogage

je vais changer ça, merci ^^

je vais essayer ça, je reviens vers vous après, merci !

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.