• 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
Wykonanie całej kolejki przerwań zanim program ruszy dalej.
#1
Cześć, robię sobie robota na inżynierkę, co śmiga po pomieszczeniu i tworzy mapę jego ścian.

Działa to tak, robot jedzie wzdłuż ścian i co 3 impulsy z enkodera optycznego (MH-Sensor-Series Foto Interruptor; Tarcza 20 otworów -> 20 impulsów na obrót koła) wrzuca na KONIEC LISTY aktualny kąt i aktualną odległość od ściany. 

W czasie wykonywania pętli głównej na bieżąco przesyła dane z POCZĄTKU lity do mojego komputera i usuwa je, żeby zwolnić pamięć. W ten sposób dane są ładnie ustawione w kolejce. Te z przodu są przesyłane i usuwane, a z tyłu są dostawiane nowe.

I w sumie wszystko spoko, bo program działa poprawnie i spełnia swoje zadanie, ale jest dość obszerny i Arduino nie wyrabia się z wykonywaniem przerwań na bieżąco. Z tego co wyczytałem w tej sytuacji ustawiają się one w kolejkę.

Problem pojawia się, kiedy robot dojedzie do rogu ściany. W tym miejscu generuję sztucznie współrzędne punktu odpowiadającego rogowi ściany i wrzucam do kolejki. Niestety niewykonane wcześniej przerwania następują po tym i punkty, które powinny być przed lądują w kolejce później. To rozwala mapę, bo punkty nie są ustawione po kolei.

Próbowałem różnych sposobów, żeby interrupty  wykonały się do końca zanim przejdę dalej. Timerów, delay, for i tak dalej. Sprawdzam nawet czy w kolejce są jeszcze elementy

 while(ListaKaty.size() != 0 && ListaOdl.size() != 0) WyslijKatIOdl();

i to nie pomaga. Jak robot obróci się i pojedzie dalej, dopiero wtedy wcześniejsze punkty ( z zakolejkowanych przerwań) trafiają na listę i  są przesyłane.

Czy jest jakiś sposób, żeby sprawdzać czy są jeszcze przerwania oczekujące na wykonanie i żeby zostały wykonane? Lub jak zrobić, żeby się wykonywały, a program poczeka sobie np. 2 sekundy. Bo akurat czas nie jest tutaj problemem.

wiersze,  o których mówię za-komentowałem //PROBLEM

Jakby trzeba było coś jeszcze wyjaśnić to proszę pytajcie.

Z góry dzięki za wszelką pomoc,
Michał

Kod:
#include <NewPing.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Timers.h>
#include <Wire.h>
#include <MPU6050.h>
#include <LinkedList.h>
#include <math.h>

RF24 radio(7, 8); // CE, CSN
const byte addresses[][6] = {"00001", "00002"};
boolean buttonState = 0;

#define PrawyPrzod 10
#define PrawyTyl 9
#define LewyPrzod 5
#define LewyTyl 6
#define Lewe 0.47
#define Prawe  0.39
#define WspWzmocKata 0.005
#define PrzGoraEchoPin A3
#define PrzDolEchoPin A1
#define TylBokEchoPin A2
#define PrzBokEchoPin A0
#define OdlegloscPrzodOdSciany 25
#define WspWzmSciana 1.5
#define IloscProb 1
#define Dystans 250

Timer RozruchTimer;

NewPing Gora(PrzGoraEchoPin,PrzGoraEchoPin,OdlegloscPrzodOdSciany+5);
NewPing Przod(PrzBokEchoPin,PrzBokEchoPin,OdlegloscPrzodOdSciany+5);
NewPing Tyl(TylBokEchoPin,TylBokEchoPin,45);
NewPing Dol(PrzDolEchoPin,PrzDolEchoPin,45);

bool CzyRozruch;
volatile bool CzyJadePrzyScianie;
int OdlOdSciany;
double OdlegloscPrzod;
double OdlegloscTyl;
int ProbyGora;
int ProbyDol;
int Enkoder[Dystans];
int ZbiorOdleglosci[Dystans];
volatile int LicznikKrokow;
int LicznikWyslania;
int i;
volatile bool Licz;
volatile bool Obrot;
volatile int AktualnyKat;
volatile int AktualnaOdlOdSciany;
String inString = "";
char str2[10];
char str1[10];
char str[10];

LinkedList<volatile int> ListaKaty;
LinkedList<volatile int> ListaOdl;
void setup() {
 radio.begin();
 radio.openWritingPipe(addresses[1]); // 00001
 radio.openReadingPipe(1, addresses[0]); // 00002
 radio.setPALevel(RF24_PA_MAX);
 pinMode (LewyPrzod, OUTPUT);
 pinMode (LewyTyl, OUTPUT);
 pinMode (PrawyPrzod, OUTPUT);
 pinMode (PrawyTyl, OUTPUT);
 CzyRozruch = 1;
 CzyJadePrzyScianie = 0;
 ProbyGora = 0;
 ProbyDol = 0;
 LicznikKrokow = 0;
 LicznikWyslania = 0;
 AktualnyKat = 0;
 RozruchTimer.begin(60);
 Licz = 0;
 Obrot = 0;
attachInterrupt(digitalPinToInterrupt(2), ZliczKrok, FALLING);
Serial.begin(115200);
}

void loop() {
 digitalWrite( LewyPrzod,LOW);
 digitalWrite( PrawyPrzod,LOW);
 digitalWrite( LewyTyl,LOW);
 digitalWrite( PrawyTyl,LOW);
 for(int czekaj = 0; czekaj < 10; czekaj ++){
   delay(2200);
   OdbierzKat();
}
 while(1){
  OdbierzKat();
  WyslijKatIOdl();
  WyslijKatIOdl();
     double Gora = OdlegloscPrzGora();
     double Dol = OdlegloscPrzDol();
     if(Gora > OdlegloscPrzodOdSciany && Dol > OdlegloscPrzodOdSciany){
       if(CzyRozruch) Start();
       if(!CzyJadePrzyScianie) Jazda(0);
       else  JazdaPrzyScianie(0);  
     }
       else{
           Stop();                       //PROBLEM
           for(int k=0; k<200;k++){      //PROBLEM
             WyslijKatIOdl();            //PORBLEM
             delay(10);                  //PROBLEM
           }
           if(CzyJadePrzyScianie){
               while(ListaKaty.size() != 0 && ListaOdl.size() != 0) WyslijKatIOdl();
               double x = OdlegloscPrzodOdSciany;
               double y = AktualnaOdlOdSciany;
               double alfa = atan(x/y);
               ListaKaty.add(-(AktualnyKat+(alfa*180/3.14)));
               double Przekatna = x/sin(alfa);
               if (Przekatna >45) Przekatna = 45;
               ListaOdl.add(Przekatna);
           }
           CzyJadePrzyScianie = 1;
           ObrotPrawo();
           Licz = 1;
           Stop();
       }

 }
}


void Start(){
   digitalWrite(PrawyTyl, LOW);
   digitalWrite(LewyTyl, LOW);
   analogWrite(PrawyPrzod,100);
   analogWrite(LewyPrzod, 120);
   CzyRozruch=0;
   RozruchTimer.restart();
   while(!RozruchTimer.available()){
       if((OdlegloscPrzGora() < OdlegloscPrzodOdSciany) || (OdlegloscPrzDol()< OdlegloscPrzodOdSciany)){
           Stop();
           return;
       }
   }
   return;
}


void Jazda(double Offset){
 digitalWrite(PrawyTyl, LOW);
 digitalWrite(LewyTyl, LOW);
 analogWrite(PrawyPrzod,170*Prawe);
 analogWrite(LewyPrzod, 170*Lewe);
}

int OdlegloscPrzGora() {
 int  dystans ;
 dystans = Gora.ping_median(2)/58;
 if (dystans == 0) dystans = OdlegloscPrzodOdSciany+5;
 delay(5);
 return dystans;
}
int OdlegloscPrzDol() {
 int  dystans;
 dystans = Dol.ping_median(2)/58;
 if (dystans == 0) dystans = OdlegloscPrzodOdSciany+5;
 delay(5);
 return dystans;
}
int TylBokZmierzOdleglosc(int x) {
 Licz = 0;
 int  dystans;
 dystans = Tyl.ping_median(x)/58;
 if (dystans == 0) dystans = 45;
 Licz = 1;
 return dystans;
}

int PrzBokZmierzOdleglosc(int x) {
 int  dystans;
 Licz = 0;
 dystans = Przod.ping_median(x)/58;
 if (dystans == 0) dystans = 45;
 Licz = 1;
 return dystans;
}

void Stop(){
 digitalWrite( LewyPrzod,HIGH);
 digitalWrite( PrawyPrzod,HIGH);
 digitalWrite( LewyTyl,HIGH);
 digitalWrite( PrawyTyl,HIGH);
 WyslijKatIOdl();
 delay(500);
 digitalWrite( LewyPrzod,LOW);
 digitalWrite( PrawyPrzod,LOW);
 digitalWrite( LewyTyl,LOW);
 digitalWrite( PrawyTyl,LOW);
 WyslijKatIOdl();
 CzyRozruch = 1;
}

void ObrotPrawo(){
 
 digitalWrite(PrawyPrzod, LOW);
 digitalWrite(LewyTyl, LOW);
 if((OdlegloscPrzGora() < 15 ) || (OdlegloscPrzDol()< 15)) Cofnij();
 analogWrite (PrawyTyl, 90);
 analogWrite (LewyPrzod,110);
 delay(150);
 analogWrite (PrawyTyl, 50);
 analogWrite (LewyPrzod,70);
 Obrot =1;
 int LicznikObrotu =LicznikKrokow;
 double PrzodOdl;
 double TylOdl;
 double Roznica;
 while(LicznikKrokow-LicznikObrotu <=6);
 do{
 PrzodOdl = PrzBokZmierzOdleglosc(1);
 TylOdl = TylBokZmierzOdleglosc(1);
 Roznica = PrzodOdl - TylOdl;
 Roznica = abs(Roznica);
 }while(2 >= Roznica && PrzodOdl<OdlegloscPrzodOdSciany + 3 && TylOdl<OdlegloscPrzodOdSciany + 3);
 
 Stop();
 Obrot  = 0;
 OdlOdSciany = OdlegloscPrzodOdSciany;
 AktualnaOdlOdSciany = (TylOdl + PrzodOdl)/2;
 LicznikKrokow = 0;
 return;
}





void WyslijDane(int Value){
 
 radio.stopListening();
 radio.write(&Value, sizeof(Value));

}

void JazdaPrzyScianie(double Offset){
 digitalWrite(PrawyTyl, LOW);
 digitalWrite(LewyTyl, LOW);
 double WspOdl = 1;
 double WspRownoleg = 1.1;
 int Predkosc = 170;
 double OdlegloscPrzod = PrzBokZmierzOdleglosc(1);
 double OdlegloscTyl = TylBokZmierzOdleglosc(1);
 if((OdlegloscPrzod+OdlegloscTyl)/2 != 45) AktualnaOdlOdSciany = (OdlegloscPrzod+OdlegloscTyl)/2;
 double KorektaOdleglosci = (OdlOdSciany-AktualnaOdlOdSciany)*WspOdl;
 double KorektaRownolegla = (OdlegloscPrzod-OdlegloscTyl)*WspRownoleg;
 double P = Predkosc*Prawe - KorektaOdleglosci+ KorektaRownolegla;
 if (P<Predkosc*Prawe-10) P=Predkosc*Prawe-10;
 if (P>Predkosc*Prawe+12) P=Predkosc*Prawe+12;
 double L = Predkosc*Lewe + KorektaOdleglosci- KorektaRownolegla;
 if (L<Predkosc*Lewe-12) L=Predkosc*Lewe-12;
 if (L>Predkosc*Lewe+10) L=Predkosc*Lewe+10;
 analogWrite(PrawyPrzod,P);
 analogWrite(LewyPrzod, L);
 
}

void Cofnij(){
   Licz  = 0;
   digitalWrite(PrawyPrzod, LOW);
   digitalWrite(LewyPrzod, LOW);
   if((OdlegloscPrzGora() > OdlegloscPrzodOdSciany) && (OdlegloscPrzDol()> OdlegloscPrzodOdSciany)) return;
   analogWrite(PrawyTyl,75);
   analogWrite(LewyTyl, 95);
   delay(500);
   Stop();
   Licz = 1;
   return;
     
}

void ZliczKrok(){
 if(Licz && CzyJadePrzyScianie) LicznikKrokow++;
 if (LicznikKrokow >= 3 && !Obrot) {
   ListaKaty.add(AktualnyKat);
   ListaOdl.add(AktualnaOdlOdSciany);
   LicznikKrokow = 0;
  }
}

void OdbierzKat(){
 Licz =0;
   Serial.println('$');
   while (Serial.available() > 0) {
     int inChar = Serial.read();
     if (isDigit(inChar)) {
       // convert the incoming byte to a char and add it to the string:
       inString += (char)inChar;
     }
     // if you get a newline, print the string, then the string's value:
     if (inChar == '\n') {
       //Serial.print("Value:");
       //Serial.println(inString.toInt());
       AktualnyKat = inString.toInt();
       
       // clear the string for new input:
       inString = "";
       break;
     }
   }
   Licz = 1;
 return;
}

void WyslijKatIOdl(){
         Licz=0;
         if(ListaKaty.size() != 0 && ListaOdl.size() != 0){
           if(ListaKaty.get(0)<0){
             sprintf(str,"%d",0);
             sprintf(str1, "%d", -ListaKaty.shift());
             sprintf(str2,"%d", ListaOdl.shift());
           }
           else{
             sprintf(str,"%d",1);
             sprintf(str1, "%d", ListaKaty.shift());
             sprintf(str2,"%d", ListaOdl.shift());
           }
           strncat (str,str1,6);
           strncat (str, "   ", 6);
           strncat (str,str2,6);
           delayMicroseconds(10);
           radio.stopListening();
           radio.write(&str, sizeof(str));
         }
     Licz=1;
     return;
       
}
 
Odpowiedź
#2
(17-01-2019, 15:22)MajkelAngelo napisał(a): Arduino nie wyrabia się z wykonywaniem przerwań na bieżąco.
Pewnie jest źle napisany, przerwania są zbyt często bo nie jest używany sprzęt tylko protezy programowe albo w przerwaniach delay czy pętle czekające na jakieś zdarzenie.

(17-01-2019, 15:22)MajkelAngelo napisał(a): Z tego co wyczytałem w tej sytuacji ustawiają się one w kolejkę.
W AVR nie ma czegoś takiego jak kolejka przerwań.

(17-01-2019, 15:22)MajkelAngelo napisał(a): Próbowałem różnych sposobów, żeby interrupty  wykonały się do końca zanim przejdę dalej.
Program główny nie ruszy dalej, dopóki nie wykonają się wszystkie przerwania. Dokładniej, po każdym przerwaniu wykona się jeden rozkaz programu głównego.
 
Odpowiedź
#3
No dobra, to jaki może być powód tego, że te przerwania wykonują się z opóźnieniem? Po tym jak robot wykona zakręt do List wrzucane są dane sprzed zakrętu( A są wrzucane tylko w przerwaniach), a przecież obecnie zmienna globalna kąt ma już przypisaną aktualną wartość. Więc te wartości gdzieś sobie czekają.
 
Odpowiedź
#4
Tak, jak kolega wyżej pisze.
Arduino się do takich rzeczy nie nadaje. Musisz napisać tak program, aby można było przerywać przerwanie.
Normalnie to się stosuje atrybut ISR_BLOCK, ale w Arduino nie ma czegoś takiego jak obsługa przerwań, tylko te wyżej wspomniane protezy programowe.
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
#5
AVR wyrobi a jak program napisany źle, to i 1GHz nic nie zmieni. Na Z-80 dałbym radę zrealizować zadania, które realizuje robot bo robi niewiele.
Należy zacząć od tego, jak często wykonują się przerwania?
Pokaż rozwinięcie asm procedury obsługi przerwania.

Dalej, moc CPU jest zabijana przez delay i to bardzo długie. Stąd pozorne wrażenie, że przerwania czekają w imaginowanej kolejce. Wystarczy w przerwaniu "tachlować" sobie jakimś pinem GPIO i zobaczyć na oscyloskopie, że przerwania wykonują się natychmiastowo. Przy okazji bedzie widać ile czasu zostaje na program główny.

Dlaczego zliczanie kroków jest realizowane programowo? Timerów zabrakło?

Po co liczby zmiennoprzecinkowe? Po co double? W AVR double i float to jedno i to samo!
Ciekawostka: Kiedyś "long" i "long long" było 32-bit teraz na szczęście już nie ale i tak AVR-GCC wymaga wielu protez bo uwiązał się do 16-bit w wielu operacjach dlatego nie nadaje się do poważnych zastosowań, chyba, ze ktoś ma dużo czasu na pisanie softu.
 
Odpowiedź
#6
20 razy na obrót koła.

Prędkość to mniej więcej 20cm/sekundę.
Średnica koła 6.5 cm -> Obwód: 20,4 cm.

Czyli można powiedzieć, że 20 razy na sekundę.

Na angielskim forum podpowiedzieli żeby wymienić wszystkie delaye na millis(), i to trochę pomogło, ale nadal jest takie coś, że dane pojawiają się w listach z opóźnieniem. Kąt zmierzony przed wykonaniem skrętu jest wrzucany do kolejki po wykonaniu skrętu, czyli w momencie wrzucenia nie mógł być zapisany w zmiennej, która przechowuje kąt.

Ja wiem, że Arduino to zły kontroler do tego projektu, ale już za późno na zmiany Big Grin będę miał wniosek do inżynierki. Ale pytam, bo może jest jakieś rozwiązanie.
 
Odpowiedź
#7
(17-01-2019, 19:00)MajkelAngelo napisał(a): Czyli można powiedzieć, że 20 razy na sekundę.
20 na sekundę możesz zliczać programowo. AVR wyrobi 20..50 a nawet 70kHz, naturalnie to głupota, bo CPU będzie obciążony w 80 czy 90%. Użycie timera zmniejszy obciążenie do jakiś promili.

(17-01-2019, 19:00)MajkelAngelo napisał(a): Na angielskim forum podpowiedzieli żeby wymienić wszystkie delaye na millis(),
Delay nie powinien pojawiać się w pętli głównej a już na pewno nie rzędu dziesiątek czy tym bardziej setek ms.

(17-01-2019, 19:00)MajkelAngelo napisał(a): Ja wiem, że Arduino to zły kontroler do tego projektu
Arduino z definicji nie nadaje się do ŻADNYCH poważniejszych projektów! To platforma do testowania, nauki a nie realizowania realnych projektów. Porównam (niebyt trafnie) do zasilacza laboratoryjnego. Używasz go do uruchamiania urządzenia czy w finalnej konstrukcji?
 
Odpowiedź
#8
Tu jest Twoje rozwiązanie. Ta biblioteka wznosi arduino na wyżny.  https://majsterkowo.pl/forum/viewtopic.php?f=38&t=1974 sam jej używam do sterownia silników krokowych i obliczeń.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości