• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Odtwarzanie trasy przejazdu robota - poprawność programu
#5
Dziękuję bardzo za miłe słowa Smile

Wprowadziłem znów kilka zmian według wskazówek.
Częstotliwość występowania przerwań zewnętrznych zależy od wartości PWM podawanej na sterownik silników, a więc od prędkości obrotowej. Próbowałem na większych i mniejszych wartościach. Zauważyłem, że przy wartościach większych, występował jedynie błąd wynikający z pędu pojazdu. Silniki są hamowane natychmiastowo, jednak pęd zawsze pchnie trochę pojazd w stronę poruszania się. Przy mniejszych wartościach nic się nie zmieniało.
Miałem już wcześniej problem z przerwaniami zewnętrznymi (przerwania pojawiały się bez zmiany stanu na pinie 2), ale pomogło wykorzystanie innego pinu do przerwań zewnętrznych (zmiana D2 z D7). 
Aktualnie problem błędnego odtwarzania trasy udało mi się wyeliminować zmianą pinów przerwań zewnętrznych miejscami między enkoderami. 
Enkoder A był wpięty na pin 3, natomiast enkoder B na pin 7. Teraz wpięte są odwrotnie.
Pozostaje mi dojść do tego, z jakiego powodu podczas jazdy na wprost pojazd najpierw zaczyna kręcić prawym kołem, a po chwili (milisekundy) dopiero dołącza drugie koło. Podczas jazdy do tyłu problem ten nie występuje. 
Próbowałem z nastawami regulatora PD, ale jeśli to byłoby przyczyną, to problem występował by także podczas jazdy do tyłu. 
W funkcji stop() celowo zastosowałem delay(200), ponieważ wtedy silniki prawidłowo zatrzymują się natychmiastowo, a podczas wykonywania tej funkcji program nie musi wykonywać w tym czasie absolutnie nic innego. Stosuję uśpienie sterownika w celu oszczędzania energii, ale głównie z powodu późniejszego wystawienia odpowiednich stanów wyjść, w celu ustawienia jazdy w konkretnym kierunku i o odpowiedniej prędkości, po czym dopiero wybudzam sterownik. Dzięki temu silniki powinny startować dokładnie w tej samej chwili czasowej. Jednak podczas jazdy na wprost dzieje się inaczej i nie wiem co jest tego przyczyną.
Zastosowałem Watchdog'a, jednak proszę ocenić, czy zrobiłem to prawidłowo. Przyznaję się, że stosuję tę funkcję po raz pierwszy Smile Podczas odtwarzania trasy (pętla, której wcześniej program nie chciał opuszczać) za każdym razem kasuję licznik WDG, ponieważ może to być długa trasa w danym kierunku, co może trwać nawet ponad 10 sekund.
Poniżej zamieszczam aktualny kod programu:
Kod:
#include <avr/wdt.h>
#define A_ENC 7 //enkoder silnika A
#define B_ENC 3 //enkoder silnika B
#define STDBY 4 //uśpienie sterownika silników
#define ALR 5 //sygnał alarmu
#define A_IN1 2 //zmiana kierunku obrotów silnika prawego
#define A_IN2 6 //
#define A_PWM 9 //wyjście PWM na silnik prawy
#define B_IN1 8 //zmiana kierunku obrotów silnika prawego
#define B_IN2 11 //
#define B_PWM 10 //wyjście PWM na silnik lewy
volatile unsigned int A_enc = 0; // impulsy enkodera silnika A
volatile unsigned int B_enc = 0; // impulsy enkodera silnika B
byte line = 0; //numer wiersza macierzy (krok wykonania ruchu powrotnego)
unsigned int macierz [126][4] = {}; //tablica danych trasy przejazdu
byte Speed1 = 120; //prędkość obrotów silników w trybie normalnym
byte Speed2 = 60; //prędkość obrotów silników w trybie nauki
byte Speed3 = 60; //prędkość obrotów silników w trybie powrotu
const int w_zad = 0; //wartość zadana
const int k_p = 4; //współczynnik wzmocnienia członu P regulatora
const int k_d = 1; //stała różniczkowania regulatora
volatile int p; //wartość wyjściowa członu typu P
volatile int d; //wartość wyjściowa członu typu D
volatile int u; //aktualny uchyb regulacji
volatile int u_p = 0; //poprzedni uchyb regulacji
volatile int out; // sygnał wyjściowy regulatora
volatile int diff = 0; //różnica wskazań enkoderów
volatile int x; // regulowana wartość PWM A
volatile int y; // regulowana wartość PWM B
boolean Forward = 0; //znacznik jazdy do przodu
boolean Backward = 0; //znacznik jazdy do tyłu
boolean Left = 0; //znacznik jazdy w lewo
boolean Right = 0; //znacznik jazdy w prawo
char state = 0; //odczyt z bluetooth(SerialPort1)
int meas_sum = 0; // suma wartości odczytanych z ADC
byte meas_count = 0; //licznik próbek pomiaru napięcia 
int meas_av = 0; // uśredniona wartość napięcia
float volt; // obliczona wartość napięcia

void setup() {
  
  wdt_enable(WDTO_1S);
  pinMode(A_ENC, INPUT_PULLUP); //kofiguracja wejść i wyjść
  pinMode(B_ENC, INPUT_PULLUP);
  pinMode(ALR, OUTPUT);
  pinMode(STDBY, OUTPUT);
  pinMode(A_IN1, OUTPUT);
  pinMode(A_IN2, OUTPUT);
  pinMode(A_PWM, OUTPUT);
  pinMode(B_IN1, OUTPUT);
  pinMode(B_IN2, OUTPUT);
  pinMode(B_PWM, OUTPUT);
  Serial1.begin(9600); //włączenie transmisji szeregowej i ustawienie prędkości
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(A_ENC), COUNT_A, CHANGE); // włączenie przerwań zewnętrznych
  attachInterrupt(digitalPinToInterrupt(B_ENC), COUNT_B, CHANGE);
  wdt_reset();
}
void loop() {

    if(meas_count == 10){
       meas_av = meas_sum/11;
       meas_count = 0;
       meas_sum = 0;
    }
    meas_sum += analogRead(A0);   // pomiar napięcia baterii 
    meas_count ++;
  
  volt = meas_av * (0.0097752);  // przeliczenie na wartość dziesiętną
  Serial1.print(" "); // wysłanie wartości przez bluetooth
  Serial1.print(volt); //
  
  /*while (volt < 5.0){ //kontrola napięcia
    digitalWrite(ALR, !digitalRead(ALR)); // napięcie poniżej 5V włącza alarm
    Stop();
    delay(500);
    wdt_reset();
  }*/
  digitalWrite(ALR, LOW); // wyłączenie alarmu
  
  if (state == '0') { // czyszczenie odczytów z enkoderów
    clearenc();
  } 
  if (Serial1.available()) { // odczyt danych z bluetooth
    state = Serial1.read(); // przypisanie odebranej danej do zmiennej
  }
  switch (state) {
    case '0': //stop
      Stop();
      clearenc();
      break;
    case '1': //
      forward(Speed1); //do przodu
      break;
    case '2':
      backward(Speed1); //do tyłu
      break;
    case '3':
      left(Speed1); //w lewo
      break;
    case '4':
      right(Speed1); //w prawo
      break;
    case '5': // nauka
      clearenc();
      break;
    case '6':                          // powrót
      for (char  i = 125; i >= 0; i--) {
        clearenc();
        if (macierz[i][0] > 0) {
          while (A_enc < macierz[i][0]) { //do tyłu
            backward(Speed3);
            wdt_reset();
          }
          Stop();
          macierz[i][0] = 0;
        }
        else if (macierz[i][1] > 0) { // do przodu
          while (A_enc < macierz[i][1]) {
            forward(Speed3);
            wdt_reset();
          }
          Stop();
          macierz[i][1] = 0;
        }
        else if (macierz[i][2] > 0) { // w prawo
          while (A_enc < macierz[i][2]) {
            right(Speed3);
            wdt_reset();
          }
          Stop();
          macierz[i][2] = 0;
        }
        else if (macierz[i][3] > 0) { // w lewo
          while (A_enc < macierz[i][3]) {
            left(Speed3);
            wdt_reset();
          }
          Stop();
          macierz[i][3] = 0;
        }
      }
      line = 0;
      break;
    case '7': //do przodu w trybie nauki
      forward(Speed2);
      Forward = 1;
      break;
    case '8': //do tyłu w trybie nauki
      backward(Speed2);
      Backward = 1;
      break;
    case '9': //w lewo w trybie nauki
      left(Speed2);
      Left = 1;
      break;
    case 'A': //w prawo w trybie nauki
      right(Speed2);
      Right = 1;
      break;
    case 'B':
      Stop(); // zatrzymanie w trybie nauki + zapamiętanie przejechanej trasy
      if (Forward == 1) { //zapisanie drogi do przodu
        macierz [line] [0] = A_enc;
      }
      else if (Backward == 1) { //zapisanie drogi do tyłu
        macierz [line] [1] = A_enc;
      }
      else if (Left == 1) { //zapisanie obrotu w lewo
        macierz [line] [2] = A_enc;
      }
      else if (Right == 1) { //zapisanie obrotu w prawo
        macierz [line] [3] = A_enc;
      }
      line ++;
      Forward = 0;
      Backward = 0;
      Left = 0;
      Right = 0;
      clearenc();
      break;
  }
  wdt_reset();
}
void COUNT_A() { //zliczanie impulsów ennkodera silnika A
  A_enc++;  
}  
void COUNT_B() { //zliczanie impulsów ennkodera silnika B
  B_enc++;
}
void forward(byte Speed) { //funkcja jazdy do przodu + synchronizacja prędkości obrotowej silników
  diff = A_enc - B_enc;
  u = w_zad - diff;
  p = k_p * u;
  d = k_d * (u_p - u);
  out = p + d;
  u_p = u;
  x = Speed - out;
  y = Speed + out;
  if(x > 255){
    x = 255;
  }else if(x < 35){
    x = 0;
  }
  if(y > 255){
    y = 255;
  }else if(y < 35){
    y = 0;
  }
  digitalWrite(A_IN1, HIGH); 
  digitalWrite(A_IN2, LOW);
  digitalWrite(B_IN1, LOW); 
  digitalWrite(B_IN2, HIGH);
  analogWrite(B_PWM, x);
  analogWrite(A_PWM, y);
  digitalWrite(STDBY, HIGH);
}
void backward(byte Speed) { //funkcja jazdy do tyłu + synchronizacja prędkości obrotowej silników
  diff = A_enc - B_enc;
  u = w_zad - diff;
  p = k_p * u;
  d = k_d * (u_p - u);
  out = p + d;
  u_p = u;
  x = Speed - out;
  y = Speed + out;
  if(x > 255){
    x = 255;
  }else if(x < 35){
    x = 0;
  }
  if(y > 255){
    y = 255;
  }else if(y < 35){
    y = 0;
  }
  digitalWrite(A_IN1, LOW); 
  digitalWrite(A_IN2, HIGH);
  digitalWrite(B_IN1, HIGH); 
  digitalWrite(B_IN2, LOW);
  analogWrite(B_PWM, x);
  analogWrite(A_PWM, y);
  digitalWrite(STDBY, HIGH);
}
void left(byte Speed) { //funkcja jazdy w lewo  + synchronizacja prędkości obrotowej silników
  diff = A_enc - B_enc;
  u = w_zad - diff;
  p = k_p * u;
  d = k_d * (u_p - u);
  out = p + d;
  u_p = u;
  x = Speed - out;
  y = Speed + out;
  if(x > 255){
    x = 255;
  }else if(x < 35){
    x = 0;
  }
  if(y > 255){
    y = 255;
  }else if(y < 35){
    y = 0;
  }
  digitalWrite(A_IN1, HIGH); 
  digitalWrite(A_IN2, LOW);
  digitalWrite(B_IN1, HIGH); 
  digitalWrite(B_IN2, LOW);
  analogWrite(B_PWM, x);
  analogWrite(A_PWM, y);
  digitalWrite(STDBY, HIGH);
  
}
void right(byte Speed) { //funkcja jazdy w prawo  + synchronizacja prędkości obrotowej silników
  diff = A_enc - B_enc;
  u = w_zad - diff;
  p = k_p * u;
  d = k_d * (u_p - u);
  out = p + d;
  u_p = u;
  x = Speed - out;
  y = Speed + out;
  if(x > 255){
    x = 255;
  }else if(x < 35){
    x = 0;
  }
  if(y > 255){
    y = 255;
  }else if(y < 35){
    y = 0;
  }
  digitalWrite(A_IN1, LOW); 
  digitalWrite(A_IN2, HIGH);
  digitalWrite(B_IN1, LOW); 
  digitalWrite(B_IN2, HIGH);
  analogWrite(B_PWM, x);
  analogWrite(A_PWM, y);
  digitalWrite(STDBY, HIGH);
}
void Stop() {
  digitalWrite(A_IN1, HIGH); // stop
  digitalWrite(A_IN2, HIGH);
  digitalWrite(B_IN1, HIGH); 
  digitalWrite(B_IN2, HIGH);
  analogWrite(A_PWM, 0);
  analogWrite(B_PWM, 0);
  delay(200);
  digitalWrite(STDBY, LOW);
}
void clearenc() { //funkcja czyszczenia odczytów z enkoderów
  A_enc = 0;
  B_enc = 0;
}
 
Odpowiedź
  


Wiadomości w tym wątku
RE: Odtwarzanie trasy przejazdu robota - poprawność programu - przez BourbonKid - 06-01-2019, 22:07

Skocz do:


Przeglądający: 1 gości