Skocz do zawartości

Kurs budowy robotów - #9 - ekspander I/O, serwo


Pomocna odpowiedź

Do leepa79

Skorzystam z Twoich rad. Byłbym jednak wdzięczny gdybś przesłał mi poprawiony kod.

Nadminiam że mam prawie 70 lat jestem emerytowanym ekonomistą. Boję się że zaplątam sie i nic z tego nie wyjdzie. Posiadając poprawiony kod porównam z efektami moich poprawek i napewno pozwoli mi to wyłapać błędy.

Jeśli nie chcesz publikowć tego na forum to poniżej podaję swój adres: jaroslawpestka6@gmail.com

Link do komentarza
Share on other sites

Niestety kręcę się w kółko i nic mi nie wychodzi.

Drobne korekty programu sterowania pilotem oraz drobne korekty konstrukcji takie jak: zaprogramowałem klawisze 144, 149, 150, 151, 145 do szybszej jazdy do przodu, po łuku, stop i w tył. Do każdej jazdy wstecz dodałem sygnał buzera. Przy skręcie orczyk obraca czujnik w kierunku skrętu. Do orczyka zamontowałem dwie czerwone diody, Serwo zamontowałem tak aby było wyżej, z obawy by nie wjeżdżał pod meble. Czujniki wykorzystywane przy światłolubie zastosowałem jako przednie lampy.

Czy ktoś nie napisał by takiego programu, którego założenia podaje poniżej, byłbym wdzięczny.

Do programu sterującego pilotem dodać funkcje, która po wciśnięciu przycisku na pilocie ( na przykład klawisz, który po naciśnięciu wysyła wartość 56) uruchamiał by cały program sterowania za pomocą ruchomego czujnika skanującego otoczenie. Następnie po naciśnięciu wcześniej zaprogramowanych przycisków na piloci wracał by do sterowania ręcznego.

[ Dodano: 26-03-2017, 09:28 ]

Zdjęcie mojego robota.

Link do komentarza
Share on other sites

Pesjar, To będzie trzeba inaczej zrobić 🙂 Sam bym chciał wiedzieć jak. Może Treker nas naprowadzi na odpowiedni trop. Po wciśnięciu przycisku na pilocie (tego '56') wykona się instrukcja wewnątrz i na koniec napotka 'break' więc nie będzie to tak działało jak chcemy 🙂 Zaciekawił mnie ten problem. Do tej pory instrukcji switch case używałem do raczej prostych zadań typu 'po wciśnięciu przycisku na pilocie --> jedź prosto' lub zapal lampkę i wykonaj jakiś odczyt jak np tu:

case 144: //instrukcja dla listwy LED zwiekszanie
           if(jasnosc < 255) {jasnosc = jasnosc+51;} 
           Serial.println(jasnosc); 
           analogWrite(diodaPin, jasnosc);
           zamigajLED(); //funkcja kontrolki odbioru 
           ekranDane(); //odczyt danych z czujnikow
           ekranLed(); //czasowe podswietlenie wyswietlacza
           break;

A tutaj chcemy, żeby po wciśnięciu przycisku instrukcja wew działała w pętli. Da się tak w ogóle? A może da się odczytywać sygnały z pilota inaczej, np if'em? Pomoże ktoś znaleźć odpowiednie tory? Tak czy siak idę googlować, może coś wyszukam.

Link do komentarza
Share on other sites

leepa79, najprościej będzie wrzucić do tego słynnego case '56' pętle while, która będzie wykonywała się w koło (w jej wnętrzu program korzystający z serwa i czujnika). Wyjście z pętli powinno odbywać się w momencie odebrania konkretnego sygnału z pilota. Oczywiście w związku z tym w pętli znajdującej się wewnątrz case '56' trzeba powtórzyć fragment odpowiedzialny z odczytywanie RC5.

Inna metoda to zapamiętywanie ostatnio wciśniętego klawisza na pilocie. Jeśli poprzedni miał wartość 56, a nie odebrano żadnych nowych danych to idziemy do case '56' i tak cały czas. Wymaga to jednak wyciągnięcia całego switch...case poza warunek sprawdzający, czy odebrano dane przez RC5.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Dalej walczę nad połączeniem programów i brak sukcesu, może jeszcze jakaś podpowiedź. Ponżej ostatnie moje wypociny.

#include <RC5.h>
#include <Servo.h>
Servo serwo;
#define SERWO_PIN 11
#define L_PWM 5
#define L_DIR 4
#define R_PWM 6
#define R_DIR 9
#define PWM_MAX 165
//Piny od czujnika odleglosci
#define trigPin 7
#define echoPin 8
#define BUZZER 10
#define LED 13
#define TSOP_PIN 3

RC5 rc5(TSOP_PIN); //Informacja o podłączeniu odbiornika TSOP
byte address;
byte command;
byte toggle;

void setup() {
 //Konfiguracja pinow od mostka H
 pinMode(L_DIR, OUTPUT);
 pinMode(R_DIR, OUTPUT);
 pinMode(L_PWM, OUTPUT);
 pinMode(R_PWM, OUTPUT);

 //Konfiguracja pozostalych elementow
 pinMode(BUZZER, OUTPUT);
 digitalWrite(BUZZER, 0); //Wylaczenie buzzera
 pinMode(LED, OUTPUT);
 digitalWrite(LED, 0); //Wylaczenie diody

 //Czujnik odleglosci
 pinMode(trigPin, OUTPUT); //Pin, do którego podłączymy trig jako wyjście
 pinMode(echoPin, INPUT); //a echo, jako wejście
 Serial.begin(9600);
 //Serwo do pinu 11
 serwo.attach(SERWO_PIN);
 serwo.write (90);
}
void loop() {
 if (rc5.read(&toggle, &address, &command)) {
   switch (command) {
     case 2: //Do przodu
       leftMotor(40);
       rightMotor(40);
       serwo.write (90);
       delay (800);
       break;

     case 8: //Do tyłu
       leftMotor(-30);
       rightMotor(-30);
       serwo.write (90);
       delay (800);
       digitalWrite(BUZZER, 1);
       delay(500);
       digitalWrite(BUZZER, 0);
       break;

     case 5: //STOP
       stopMotors();
       serwo.write (90);
       delay (800);
       break;

     case 4: //Obrót w lewo
       leftMotor(-30);
       rightMotor(30);
       serwo.write (160);
       delay (800);
       break;

     case 6: //Obrót w prawo
       leftMotor(30);
       rightMotor(-30);
       serwo.write (20);
       delay (800);
       break;

     case 1: //Jazda do przodu po łuku w lewo
       rightMotor(40); //Prawy przód 30%
       leftMotor(20); //Lewy przód 10%
       serwo.write (160);
       delay (800);
       break;

     case 3: //Jazda do przodu po łuku w prawo
       rightMotor(20);
       leftMotor(40);
       serwo.write (20);
       delay (800);
       break;

     case 7: //Jazad do tył po łuku w lewo
       rightMotor(-40);
       leftMotor(-20);
       serwo.write (90);
       delay (800);
       digitalWrite(BUZZER, 1);
       delay(500);
       digitalWrite(BUZZER, 0);
       break;

     case 9: //Jazad do tył po łuku w prawo
       rightMotor(-20);
       leftMotor(-40);
       serwo.write (90);
       delay (800);
       digitalWrite(BUZZER, 1);
       delay(500);
       digitalWrite(BUZZER, 0);
       break;

     case 144: //Do przodu
       leftMotor(90);
       rightMotor(90);
       serwo.write (90);
       delay (800);
       break;

     case 145: //Do tyłu
       leftMotor(-90);
       rightMotor(-90);
       serwo.write (90);
       delay (800);
       digitalWrite(BUZZER, 1);
       delay(500);
       digitalWrite(BUZZER, 0);
       break;

     case 149: //Jazda do przodu po łuku w lewo
       rightMotor(90); //Prawy przód 30%
       leftMotor(45); //Lewy przód 10%
       serwo.write (160);
       delay (800);
       break;

     case 150: //Jazda do przodu po łuku w prawo
       rightMotor(45);
       leftMotor(90);
       serwo.write (20);
       delay (800);
       break;

     case 151: //STOP
       stopMotors();
       serwo.write (90);
       delay (800);
       break;

     case 12:
       digitalWrite(BUZZER, 1);
       delay(500);
       digitalWrite(BUZZER, 0);
       break;

     case 13:
       serwo.write (90);
       delay (800);
       break;

     case 32:
       serwo.write (20);
       delay (800);
       break;

     case 16:
       serwo.write (160);
       delay (800);
       break;

     case 56:
       while (rc5.read(&toggle, &address, &command)comm == 56)  {
         if (zmierzOdleglosc() > 40) {
           leftMotor(40); //Jesli nie, to jedz prosto
           rightMotor(40);
         } else {
           //Jesli przeszkoda
           stopMotors(); //Zatrzymaj robota
           serwo.write(20); //Skrec czujnikiem w prawo
           delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji

           //Sprawdz, czy po prawej stronie jest przeszkoda
           if (zmierzOdleglosc() > 40) {
             //Jesli jest pusto
             leftMotor(40);
             rightMotor(-40);
             delay(400); //Obracaj w prawo przez 400 ms
           } else {
             //Jeśli po prawej jest przeszkoda
             serwo.write(160); //Obroc czujnik w lewo
             delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji

             //Sprawdz, czy po lowej stronie jest przeszkoda
             if (zmierzOdleglosc() > 40) {
               //Jesli jest pusto
               leftMotor(-40);
               rightMotor(40);
               delay(400); //Obracaj w lewo przez 400 ms
             } else {
               //Jesli z przodu, z lewej i prawej jest przeszkoda
               digitalWrite(BUZZER, 1);
               delay(500);
               digitalWrite(BUZZER, 0);
               //Daj sygnal buzzerem
             }
           }
           //Po sprawdzeniu przeszkod po bokach
           //Ustaw czujnik prosto
           serwo.write(90);
         }

         //Opoznienie 100ms, ponieważ nie ma potrzeby sprawdzać przeszkod czesciej
         delay(100);
       }

       int zmierzOdleglosc() {
         long czas, dystans;

         digitalWrite(trigPin, LOW);
         delayMicroseconds(2);
         digitalWrite(trigPin, HIGH);
         delayMicroseconds(10);
         digitalWrite(trigPin, LOW);

         czas = pulseIn(echoPin, HIGH);
         dystans = czas / 58;

         return dystans;
         if (rc5.read(&toggle, &address, &command)) {
           switch (command) {
           }
         }
       }

       void leftMotor(int V) {
         if (V > 0) { //Jesli predkosc jest wieksza od 0 (dodatnia)
           V = map(V, 0, 100, 0, PWM_MAX);
           digitalWrite(L_DIR, 0); //Kierunek: do przodu
           analogWrite(L_PWM, V); //Ustawienie predkosci
         } else {
           V = abs(V); //Funkcja abs() zwroci wartosc V  bez znaku
           V = map(V, 0, 100, 0, PWM_MAX);
           digitalWrite(L_DIR, 1); //Kierunek: do tyłu
           analogWrite(L_PWM, V); //Ustawienie predkosci
         }
       }

       void rightMotor(int V) {
         if (V > 0) { //Jesli predkosc jest wieksza od 0 (dodatnia)
           V = map(V, 0, 100, 0, PWM_MAX);
           digitalWrite(R_DIR, 0); //Kierunek: do przodu
           analogWrite(R_PWM, V); //Ustawienie predkosci
         } else {
           V = abs(V); //Funkcja abs() zwroci wartosc V  bez znaku
           V = map(V, 0, 100, 0, PWM_MAX);
           digitalWrite(R_DIR, 1); //Kierunek: do tyłu
           analogWrite(R_PWM, V); //Ustawienie predkosci
         }
       }

       void stopMotors() {
         analogWrite(L_PWM, 0); //Wylaczenie silnika lewego
         analogWrite(R_PWM, 0); //Wylaczenie silnika prawego
       }
Link do komentarza
Share on other sites

Połowiczny sukces przy łączeniu programów. Udało się przy pomocy wrzucenia do case ‘56’ pętli while, która wykonuje program jazdy za pomocą czujnika skanujący otoczenie.

Jednak nie mogę wyjść z pętli. Inaczej nie potrafię prawidłowo sformułować fragmentu odpowiedzialnego za odczytanie RC5 oraz ustalenia miejsca wstawienia tego fragmentu w pętle while.

Znów kręce się w kółko, może ktoś ma jakieś sugestie.

#include <RC5.h>
//Biblioteka od serwomechanizmu
#include <Servo.h>
Servo serwo;
#define SERWO_PIN 11
#define L_PWM 5
#define L_DIR 4
#define R_PWM 6
#define R_DIR 9
#define PWM_MAX 165
//Piny od czujnika odleglosci
#define trigPin 7
#define echoPin 8
#define BUZZER 10
#define LED 13
#define TSOP_PIN 3
RC5 rc5(TSOP_PIN); //Informacja o podłączeniu odbiornika TSOP
byte address;
byte command;
byte toggle;
void setup() {
 //Konfiguracja pinow od mostka H
 pinMode(L_DIR, OUTPUT);
 pinMode(R_DIR, OUTPUT);
 pinMode(L_PWM, OUTPUT);
 pinMode(R_PWM, OUTPUT);
 //Konfiguracja pozostalych elementow
 pinMode(BUZZER, OUTPUT);
 digitalWrite(BUZZER, 0); //Wylaczenie buzzera
 pinMode(LED, OUTPUT);
 digitalWrite(LED, 0); //Wylaczenie diody
 //Czujnik odleglosci
 pinMode(trigPin, OUTPUT); //Pin, do którego podłączymy trig jako wyjście
 pinMode(echoPin, INPUT); //a echo, jako wejście
 //Serwo do pinu 11
 serwo.attach(SERWO_PIN);
 //Serwo na pozycje srodkowa 90 (bo zakres 0-180)
 serwo.write(90);
 Serial.begin(9600);
}
void loop() {
 if (rc5.read(&toggle, &address, &command)) {
   switch (command) {
     case 2: //Do przodu
       leftMotor(40);
       rightMotor(40);
       break;
     case 8: //Do tyłu
       leftMotor(-40);
       rightMotor(-40);
       break;
     case 5: //STOP
       stopMotors();
       break;
     case 4: //Obrót w lewo
       leftMotor(-30);
       rightMotor(30);
       break;
     case 6: //Obrót w prawo
       leftMotor(30);
       rightMotor(-30);
       break;
     case 12:
       digitalWrite(BUZZER, 1);
       delay(500);
       digitalWrite(BUZZER, 0);
       break;
     case 56:
       while (command == 56) {
         //Czy wykryto przeszkode w zakresie 0-40 cm
         if (zmierzOdleglosc() > 40) {
           leftMotor(40); //Jesli nie, to jedz prosto
           rightMotor(40);
         } else {
           //Jesli przeszkoda
           stopMotors(); //Zatrzymaj robota
           serwo.write(20); //Skrec czujnikiem w prawo
           delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji
           //Sprawdz, czy po prawej stronie jest przeszkoda
           if (zmierzOdleglosc() > 40) {
             //Jesli jest pusto
             leftMotor(40);
             rightMotor(-40);
             delay(400); //Obracaj w prawo przez 400 ms
           } else {
             //Jeśli po prawej jest przeszkoda
             serwo.write(160); //Obroc czujnik w lewo
             delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji
             //Sprawdz, czy po lowej stronie jest przeszkoda
             if (zmierzOdleglosc() > 40) {
               //Jesli jest pusto
               leftMotor(-40);
               rightMotor(40);
               delay(400); //Obracaj w lewo przez 400 ms
             } else {
               //Jesli z przodu, z lewej i prawej jest przeszkoda
               digitalWrite(BUZZER, 1);
               delay(500);
               digitalWrite(BUZZER, 0);
               //Daj sygnal buzzerem
             }
           }
           //Po sprawdzeniu przeszkod po bokach
           //Ustaw czujnik prosto
           serwo.write(90);            
         }
         //Opoznienie 100ms, ponieważ nie ma potrzeby sprawdzać przeszkod czesciej
         delay(100);
       }
   }
 }
}
int zmierzOdleglosc() {
 long czas, dystans;
 digitalWrite(trigPin, LOW);
 delayMicroseconds(2);
 digitalWrite(trigPin, HIGH);
 delayMicroseconds(10);
 digitalWrite(trigPin, LOW);
 czas = pulseIn(echoPin, HIGH);
 dystans = czas / 58;
 return dystans;
}
void leftMotor(int V) {
 if (V > 0) { //Jesli predkosc jest wieksza od 0 (dodatnia)
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(L_DIR, 0); //Kierunek: do przodu
   analogWrite(L_PWM, V); //Ustawienie predkosci
 } else {
   V = abs(V); //Funkcja abs() zwroci wartosc V  bez znaku
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(L_DIR, 1); //Kierunek: do tyłu
   analogWrite(L_PWM, V); //Ustawienie predkosci
 }
}
void rightMotor(int V) {
 if (V > 0) { //Jesli predkosc jest wieksza od 0 (dodatnia)
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(R_DIR, 0); //Kierunek: do przodu
   analogWrite(R_PWM, V); //Ustawienie predkosci
 } else {
   V = abs(V); //Funkcja abs() zwroci wartosc V  bez znaku
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(R_DIR, 1); //Kierunek: do tyłu
   analogWrite(R_PWM, V); //Ustawienie predkosci
 }
}
void stopMotors() {
 analogWrite(L_PWM, 0); //Wylaczenie silnika lewego
 analogWrite(R_PWM, 0); //Wylaczenie silnika prawego
}

[ Dodano: 02-04-2017, 14:57 ]

Cąg dalszy połączenia programów:

#include <RC5.h>
//Biblioteka od serwomechanizmu
#include <Servo.h>
Servo serwo;
#define SERWO_PIN 11
#define L_PWM 5
#define L_DIR 4
#define R_PWM 6
#define R_DIR 9
#define PWM_MAX 165
//Piny od czujnika odleglosci
#define trigPin 7
#define echoPin 8
#define BUZZER 10
#define LED 13
#define TSOP_PIN 3
RC5 rc5(TSOP_PIN); //Informacja o podłączeniu odbiornika TSOP
byte address;
byte command;
byte toggle;
void setup() {
 //Konfiguracja pinow od mostka H
 pinMode(L_DIR, OUTPUT);
 pinMode(R_DIR, OUTPUT);
 pinMode(L_PWM, OUTPUT);
 pinMode(R_PWM, OUTPUT);
 //Konfiguracja pozostalych elementow
 pinMode(BUZZER, OUTPUT);
 digitalWrite(BUZZER, 0); //Wylaczenie buzzera
 pinMode(LED, OUTPUT);
 digitalWrite(LED, 0); //Wylaczenie diody
 //Czujnik odleglosci
 pinMode(trigPin, OUTPUT); //Pin, do którego podłączymy trig jako wyjście
 pinMode(echoPin, INPUT); //a echo, jako wejście
 //Serwo do pinu 11
 serwo.attach(SERWO_PIN);
 //Serwo na pozycje srodkowa 90 (bo zakres 0-180)
 serwo.write(90);
 Serial.begin(9600);
}
void loop() {
 if (rc5.read(&toggle, &address, &command)) {
   switch (command) {
     case 2: //Do przodu
       leftMotor(40);
       rightMotor(40);
       break;
     case 8: //Do tyłu
       leftMotor(-40);
       rightMotor(-40);
       break;
     case 5: //STOP
       stopMotors();
       break;
     case 4: //Obrót w lewo
       leftMotor(-30);
       rightMotor(30);
       break;
     case 6: //Obrót w prawo
       leftMotor(30);
       rightMotor(-30);
       break;
     case 12:
       digitalWrite(BUZZER, 1);
       delay(500);
       digitalWrite(BUZZER, 0);
       break;
     case 56:
       while (command == 56) {
         //Czy wykryto przeszkode w zakresie 0-40 cm
         if (zmierzOdleglosc() > 40) {
           leftMotor(40); //Jesli nie, to jedz prosto
           rightMotor(40);
         } else {
           //Jesli przeszkoda
           stopMotors(); //Zatrzymaj robota
           serwo.write(20); //Skrec czujnikiem w prawo
           delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji
           //Sprawdz, czy po prawej stronie jest przeszkoda
           if (zmierzOdleglosc() > 40) {
             //Jesli jest pusto
             leftMotor(40);
             rightMotor(-40);
             delay(400); //Obracaj w prawo przez 400 ms
           } else {
             //Jeśli po prawej jest przeszkoda
             serwo.write(160); //Obroc czujnik w lewo
             delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji
             //Sprawdz, czy po lowej stronie jest przeszkoda
             if (zmierzOdleglosc() > 40) {
               //Jesli jest pusto
               leftMotor(-40);
               rightMotor(40);
               delay(400); //Obracaj w lewo przez 400 ms
             } else {
               //Jesli z przodu, z lewej i prawej jest przeszkoda
               digitalWrite(BUZZER, 1);
               delay(500);
               digitalWrite(BUZZER, 0);
               //Daj sygnal buzzerem
             }
           }
           //Po sprawdzeniu przeszkod po bokach
           //Ustaw czujnik prosto
           serwo.write(90);
         }
         //Opoznienie 100ms, ponieważ nie ma potrzeby sprawdzać przeszkod czesciej
         delay(100);
         break;

         if (rc5.read(&toggle, &address, &command));
         switch (command);

       }
   }
 }
}
int zmierzOdleglosc() {
 long czas, dystans;
 digitalWrite(trigPin, LOW);
 delayMicroseconds(2);
 digitalWrite(trigPin, HIGH);
 delayMicroseconds(10);
 digitalWrite(trigPin, LOW);
 czas = pulseIn(echoPin, HIGH);
 dystans = czas / 58;
 return dystans;
}
void leftMotor(int V) {
 if (V > 0) { //Jesli predkosc jest wieksza od 0 (dodatnia)
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(L_DIR, 0); //Kierunek: do przodu
   analogWrite(L_PWM, V); //Ustawienie predkosci
 } else {
   V = abs(V); //Funkcja abs() zwroci wartosc V  bez znaku
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(L_DIR, 1); //Kierunek: do tyłu
   analogWrite(L_PWM, V); //Ustawienie predkosci
 }
}
void rightMotor(int V) {
 if (V > 0) { //Jesli predkosc jest wieksza od 0 (dodatnia)
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(R_DIR, 0); //Kierunek: do przodu
   analogWrite(R_PWM, V); //Ustawienie predkosci
 } else {
   V = abs(V); //Funkcja abs() zwroci wartosc V  bez znaku
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(R_DIR, 1); //Kierunek: do tyłu
   analogWrite(R_PWM, V); //Ustawienie predkosci
 }
}
void stopMotors() {
 analogWrite(L_PWM, 0); //Wylaczenie silnika lewego
 analogWrite(R_PWM, 0); //Wylaczenie silnika prawego
}

Program w tej wersji realizuje wszystkie funkcje z tą wadą, że jazda sterowana czujnikie realizowana jest przy wciśniętym klawiszu "Case56".

Nie mam pomysłu jak się tego pozbyć. Proszę o pomoc.

[ Dodano: 02-04-2017, 14:59 ]

Cąg dalszy połączenia programów:

#include <RC5.h>
//Biblioteka od serwomechanizmu
#include <Servo.h>
Servo serwo;
#define SERWO_PIN 11
#define L_PWM 5
#define L_DIR 4
#define R_PWM 6
#define R_DIR 9
#define PWM_MAX 165
//Piny od czujnika odleglosci
#define trigPin 7
#define echoPin 8
#define BUZZER 10
#define LED 13
#define TSOP_PIN 3
RC5 rc5(TSOP_PIN); //Informacja o podłączeniu odbiornika TSOP
byte address;
byte command;
byte toggle;
void setup() {
 //Konfiguracja pinow od mostka H
 pinMode(L_DIR, OUTPUT);
 pinMode(R_DIR, OUTPUT);
 pinMode(L_PWM, OUTPUT);
 pinMode(R_PWM, OUTPUT);
 //Konfiguracja pozostalych elementow
 pinMode(BUZZER, OUTPUT);
 digitalWrite(BUZZER, 0); //Wylaczenie buzzera
 pinMode(LED, OUTPUT);
 digitalWrite(LED, 0); //Wylaczenie diody
 //Czujnik odleglosci
 pinMode(trigPin, OUTPUT); //Pin, do którego podłączymy trig jako wyjście
 pinMode(echoPin, INPUT); //a echo, jako wejście
 //Serwo do pinu 11
 serwo.attach(SERWO_PIN);
 //Serwo na pozycje srodkowa 90 (bo zakres 0-180)
 serwo.write(90);
 Serial.begin(9600);
}
void loop() {
 if (rc5.read(&toggle, &address, &command)) {
   switch (command) {
     case 2: //Do przodu
       leftMotor(40);
       rightMotor(40);
       break;
     case 8: //Do tyłu
       leftMotor(-40);
       rightMotor(-40);
       break;
     case 5: //STOP
       stopMotors();
       break;
     case 4: //Obrót w lewo
       leftMotor(-30);
       rightMotor(30);
       break;
     case 6: //Obrót w prawo
       leftMotor(30);
       rightMotor(-30);
       break;
     case 12:
       digitalWrite(BUZZER, 1);
       delay(500);
       digitalWrite(BUZZER, 0);
       break;
     case 56:
       while (command == 56) {
         //Czy wykryto przeszkode w zakresie 0-40 cm
         if (zmierzOdleglosc() > 40) {
           leftMotor(40); //Jesli nie, to jedz prosto
           rightMotor(40);
         } else {
           //Jesli przeszkoda
           stopMotors(); //Zatrzymaj robota
           serwo.write(20); //Skrec czujnikiem w prawo
           delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji
           //Sprawdz, czy po prawej stronie jest przeszkoda
           if (zmierzOdleglosc() > 40) {
             //Jesli jest pusto
             leftMotor(40);
             rightMotor(-40);
             delay(400); //Obracaj w prawo przez 400 ms
           } else {
             //Jeśli po prawej jest przeszkoda
             serwo.write(160); //Obroc czujnik w lewo
             delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji
             //Sprawdz, czy po lowej stronie jest przeszkoda
             if (zmierzOdleglosc() > 40) {
               //Jesli jest pusto
               leftMotor(-40);
               rightMotor(40);
               delay(400); //Obracaj w lewo przez 400 ms
             } else {
               //Jesli z przodu, z lewej i prawej jest przeszkoda
               digitalWrite(BUZZER, 1);
               delay(500);
               digitalWrite(BUZZER, 0);
               //Daj sygnal buzzerem
             }
           }
           //Po sprawdzeniu przeszkod po bokach
           //Ustaw czujnik prosto
           serwo.write(90);
         }
         //Opoznienie 100ms, ponieważ nie ma potrzeby sprawdzać przeszkod czesciej
         delay(100);
         break;

         if (rc5.read(&toggle, &address, &command));
         switch (command);

       }
   }
 }
}
int zmierzOdleglosc() {
 long czas, dystans;
 digitalWrite(trigPin, LOW);
 delayMicroseconds(2);
 digitalWrite(trigPin, HIGH);
 delayMicroseconds(10);
 digitalWrite(trigPin, LOW);
 czas = pulseIn(echoPin, HIGH);
 dystans = czas / 58;
 return dystans;
}
void leftMotor(int V) {
 if (V > 0) { //Jesli predkosc jest wieksza od 0 (dodatnia)
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(L_DIR, 0); //Kierunek: do przodu
   analogWrite(L_PWM, V); //Ustawienie predkosci
 } else {
   V = abs(V); //Funkcja abs() zwroci wartosc V  bez znaku
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(L_DIR, 1); //Kierunek: do tyłu
   analogWrite(L_PWM, V); //Ustawienie predkosci
 }
}
void rightMotor(int V) {
 if (V > 0) { //Jesli predkosc jest wieksza od 0 (dodatnia)
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(R_DIR, 0); //Kierunek: do przodu
   analogWrite(R_PWM, V); //Ustawienie predkosci
 } else {
   V = abs(V); //Funkcja abs() zwroci wartosc V  bez znaku
   V = map(V, 0, 100, 0, PWM_MAX);
   digitalWrite(R_DIR, 1); //Kierunek: do tyłu
   analogWrite(R_PWM, V); //Ustawienie predkosci
 }
}
void stopMotors() {
 analogWrite(L_PWM, 0); //Wylaczenie silnika lewego
 analogWrite(R_PWM, 0); //Wylaczenie silnika prawego
}

Program w tej wersji realizuje wszystkie funkcje z tą wadą, że jazda sterowana czujnikie realizowana jest przy wciśniętym klawiszu "Case56".

Nie mam pomysłu jak się tego pozbyć. Proszę o pomoc.

Link do komentarza
Share on other sites

Pytanie do Trekera

Po skorzystaniu z Twojej rady:

"leepa79, najprościej będzie wrzucić do tego słynnego case '56' pętle while, która będzie wykonywała się w koło (w jej wnętrzu program korzystający z serwa i czujnika). Wyjście z pętli powinno odbywać się w momencie odebrania konkretnego sygnału z pilota. Oczywiście w związku z tym w pętli znajdującej się wewnątrz case '56' trzeba powtórzyć fragment odpowiedzialny z odczytywanie RC5."

naciśnięcie i trzymanie wciśniętego case56 powoduje samodzielną jazdę na podstawie wskazań czujnika ultradźwiękowego, kiedy puszczę case56, robot kontynuuje jazdę jaką wykonywał przed puszczeniem przycisku (jazda do przodu, obrót w prawo lub obrót w lewo).

Od tego momentu reaguje na wciśnięcie dowolnego przycisku case.

Wadą tego rozwiązania jest konieczność trzymania wciśniętego case56.

Poniżej fragment programu wykorzystujący Twoją radę:

void loop() {
 if (rc5.read(&toggle, &address, &command)) {
   switch (command) {
     case 12:
       digitalWrite(BUZZER, 1);
       delay(500);
       digitalWrite(BUZZER, 0);
       break;
     case 2: //Do przodu
       leftMotor(40);
       rightMotor(40);
       break;
     case 5: //STOP
       stopMotors();
       break;
     case 56://Jazda samodzielna
       while (command == 56)
       {
         jazdaSAM();
         odczytCZUJ();
         break;
       }
   }
 }
}
void odczytCZUJ() {
   if (rc5.read(&toggle, &address, &command)) {
     switch (command) {
     }
   }
 }

Krótkie wyjaśnienie:

Własna funkcja jazdaSAM() zawiera program samodzielnej jazdy sterowanej czujnikiem ultradźwiękowym .

Program zawiera tylko cztery case co znacznie ułatwiło mi dokonywanie przeróbek i licznych prób.

Zasadnicze pytanie:

Jak pozbyć się opisanej wyżej wady, aby program po krótkim wciśnięciu case56 realizował jazdę na podstawie wskazań czujnika ultradźwiękowego i jednocześnie wyczekiwał na wciśnięcie dowolnego case.

Link do komentarza
Share on other sites

Pesjar, nie było mnie kilka dni - już nadrabiam zaległości. Gratuluję podstępów, idziemy w dobra stronę. Na pewno tutaj jest jakiś błąd:

      case 56://Jazda samodzielna 
       while (command == 56) 
       { 
         jazdaSAM(); 
         odczytCZUJ(); 
         break; 
       } 

Po pierwsze break jest w złym miejscu, jak już to powinien być tutaj chyba:

      case 56://Jazda samodzielna 
       while (command == 56) 
       { 
         jazdaSAM(); 
         odczytCZUJ(); 

       } 
     break; 

Program w chwili obecnej dział poprawnie ponieważ warunek w while mówi "wykonuj kod wewnątrz pętli do czasu, gdy wysyłana komenda to 56" i to się dzieje. Trzymanie przycisku powoduję autonomiczną jazdę. Proponowałbym zmienić tam warunek na taki, który mówi "wykonuj kod wewnątrz pętli do czasu, gdy NIE wysłano np. komendy 1". Wtedy robot po wciśnięciu przycisku z komendą 56 powinien jeździć autonomicznie do czasu wciśnięcia przycisku 1.

Warunek taki powinien więc brzmieć:

while (command != 1) 

Oczywiście zamiast "1" można przypisać inny klawisz 🙂

Link do komentarza
Share on other sites

Treker , wprowadziłem poprawki w programie. Po tych poprawkach naciśnięcie case 56 powoduje wejście w pętle, która realizuje jazdę na podstawie wskazań czujnika ultradźwięków. Naciśnięcie przycisku 1 nie powoduje wyjścia z pętli, dalej jest realizowana jazda na podstawie wskazań czujnika.

...
void loop() {
 if (rc5.read(&toggle, &address, &command)) {
   switch (command) {
     case 12:
       digitalWrite(BUZZER, 1);
       delay(500);
       digitalWrite(BUZZER, 0);
       break;
     case 2: //Do przodu
       leftMotor(40);
       rightMotor(40);
       break;
     case 5: //STOP
       stopMotors();
       break;
     case 56://Jazda samodzielna
       while (command != 1)
       {
         jazdaSAM();
         odczytCZUJ();
       }
       break;
   }
 }
}
void odczytCZUJ() {
 if (rc5.read(&toggle, &address, &command)) {
   switch (command) {
   }
 }
}
...

Gdzie popełniam błąd, który uniemożliwia mi wyjście z pętli i reakcję na pozostałe zaprogramowane przyciski pilota.

Link do komentarza
Share on other sites

Pesjar, pomijając małe błędy powyższe rozwiązanie powinno działać. W ramach demonstracji proponuję uruchomić program z następującą pętlą loop():

void loop() { 
 if (rc5.read(&toggle, &address, &command)) { 
   switch (command) {      
     case 1:
       while (command != 2) { 
         digitalWrite(LED, 1);
         rc5.read(&toggle, &address, &command);
       } 

       digitalWrite(LED, 0);
     break; 

     case 3: 
       digitalWrite(BUZZER, 1); 
       delay(500); 
       digitalWrite(BUZZER, 0); 
     break; 
   } 
 } 
} 

Wciśnięcie przycisku "2" powoduje wyjście z pętli, więc wszystko jest poprawnie. Problem pojawia się, gdy wewnątrz dodanej pętli (while) chcemy wykonywać bardziej zaawansowane operacje. Ogólnie realizacja tego przełączania między zdalnym sterowaniem oraz jazdą autonomiczną brzmi prosto, jednak w tym miejscu napotkamy wiele problemów.

Program do autonomicznej jazdy wykorzystuje kilka opóźnień (delay), dodatkowo czujnik ultradźwiękowy musi mierzyć czas, w którym wracają impulsy itd. To wszystko nakłada nam się z odbieraniem IR, gdzie czas również jest kluczowy. Reasumując w tej nowej pętli nie możemy korzystać z opóźnień, ponieważ zaburza to dekodowanie RC5. W związku z tym muszę w tej chwili napisać, że niestety nie da się tego problemu rozwiązać tak prosto.

Rozwiązania są trzy:

1) Najszybciej, najprościej, ale z małym kompromisem: najlepiej wyjście z trybu autonomicznego uzależnić od warunku, którym będzie np. wciśnięcie przycisku mechanicznego umieszczonego na płytce lub wciśnięcie jednego z czujników krańcowych.

2) Rozwiązanie drugie, to rezygnacja z opóźnień wykonywanych za pomocą funkcji delay. Należałoby skupić się na korzystaniu z funkcji milis, ale to też nie będzie proste.

3) Opcje ostatnia, to wykorzystanie biblioteki (lub napisanie jej samodzielnie), która będzie odczytywała komendy RC5 korzystając z przerwań sprzętowych - rozwiązanie zdecydowanie najtrudniejsze.

Niestety rozwiązania nr 2 i 3 są dość skomplikowane i wykraczają poza ten kurs, więc nie będę się nimi teraz zajmował. Na pewno jednak w przyszłości wrócę do takich tematów. Niestety w tym wypadku trafiliśmy na zadanie do rozwiązania, które pozornie jest bardzo proste, ale w praktyce pojawia się przy nim wiele komplikacji. Jeśli ktoś ma pomysł jak rozwiązać to prościej, to sam chętnie zobaczę taki program - może w związku z późną godziną zapomniałem o czymś prostym 😉

Link do komentarza
Share on other sites

Treker, wszystko się zgadza. W ramach prób, w pętle while, wstawiłem program jazdy do tyłu. Po naciśnięciu przycisku 1 (Przycisk jeden zaprogramowany jako wyjście z pętli) robot kontynuował jazdę wstecz ale od tego momentu reagował na pozostałe zaprogramowane przyciski.

Rozumiem, że z tych samych przyczyn, po wejściu w pętle while, zamiast wyjścia, nie można zaprogramować przycisku na pilocie tak aby zresetował cały program (Podobnie jak wciśnięcie przycisku reset na płytce Arduino). Bo to rozwiązało by sprawę. Można by od nowa korzystać z zaprogramowanych przycisków.

Z mniejszą nadzieją na sukces eksperymentuje dalej.

Pięknie dziękuje za pomoc i cierpliwośc.

[ Dodano: 09-04-2017, 08:41 ]

Treker, jeszcze nasuwa mi się inne rozwiązanie. Po zaprogramowaniu przycisku case 56 jako jazdy autonomicznej, przycisk 56 reaguje w ten sposób, że po wciśnięciu i trzymaniu, realizuj jazdę autonomiczną, po puszczeniu, zatrzymuje się a pozostałe zaprogramowane przyciski są aktywne.

Czy istnieje taka możliwość aby do programu dopisać taką sekwencję, która mimo puszczenia przycisku symulowała by, że jest on wciśnięty, przy jednoczesnym pozostawieniu aktywności pozostałych zaprogramowanych przycisków.

Link do komentarza
Share on other sites

Czy istnieje taka możliwość aby do programu dopisać taką sekwencję, która mimo puszczenia przycisku symulowała by, że jest on wciśnięty, przy jednoczesnym pozostawieniu aktywności pozostałych zaprogramowanych przycisków.

Mówiąc najkrócej: nie 🙁 Biorąc pod uwagę, że Twoje próby stworzenia tego programu zaczynały się od kopiowania fragmentów programów (trochę na chybił-trafił), to i tak przymykam tutaj oko na pewne błędy. To, że program działa w opisany sposób (autonomiczna jazda, gdy przycisk jest wciśnięty) to właściwie efekt uboczny kilku nakładających się błędów. Nie da się tego tutaj sensownie wykorzystać. Tak jak pisałem, wykorzystanie opóźnień delay blokuje możliwość odczytywania komend z RC5. Jazda autonomiczna podczas trzymania przycisku (w dużym uproszczeniu) działa dlatego, że po wywołaniu komendy 56 robot na sztywno wywołuje raz funkcję do sprawdzenia przeszkód (i ewentualnie je omija). Później wraca do wykonywania całego programu, gdzie nie ma opóźnień, więc ponownie odbiera kod 56 i tak dzieje się w koło. Ten dodatkowy while praktycznie nic tu nie daje.

Link do komentarza
Share on other sites

Dla jasności. Jazdę autonomiczną podpiełem pod jeden z przycisków pilota bez pętli while.

Natomiast dzisiaj wykorzystałem pętle while do połączenia programu sterowania pilotem z światłolubem. W tym przypadku rozwiązanie to spisuje się doskonale.

Pozdrawiam i życzę cierpliwości w interpretowaniu moich nieudolnych prób.

Walczę dalej.

Link do komentarza
Share on other sites

Ma ktoś problem z dodaniem biblioteki do ekspandera?

Postępuje zgodnie z informacjami w artykule i niestety wyskakuje mi błąd:

In file included from sketch_jul04d.ino:5:0:
C:\Program Files (x86)\Arduino\libraries\Adafruit_MCP23008/Adafruit_MCP23008.h:20:20: fatal error: Wire.h: No such file or directory
  #include <Wire.h>
                   ^
compilation terminated.
Błąd kompilacji.

Tak jakby w ogóle nie widział tej dodanej przeze mnie biblioteki

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.