Skocz do zawartości

Kurs budowy robotów - #8 - zdalne sterowanie IR (RC5)


Pomocna odpowiedź

14 godzin temu, ethanak napisał:

Po prostu: nie ma takiej możliwości, chyba że zrobisz sobie własnego pilota i własny protokół komunikacji.

Dla jasności - nie ma możliwości wykonania tego przypadku, w którym robot reaguje na trzymanie dwóch przycisków, ale z jednym nie będzie przecież problemu 🙂

14 godzin temu, Adampi314 napisał:

Dzięki za odpowiedzi, @Treker ale bit toggle zmienia się tylko jeśli znowu wciśniemy jakiś przycisk, a jeśli puszczamy to w zapisanej wartości pozostaje ta poprzednia, czyli 0, no i tak jak np w przykładzie trzeba jeszcze wcisnąć przycisk. A ja próbuję tak zrobić żeby przy puszczeniu przycisku przestawał jechać (kombinowałem z else po tym pierwszym if-ie, ale wtedy robot nawet nie ruszał).

@Adampi314 bardziej chodziło mi o to, że w przykładzie z toggle widać jakąś reakcję na ciągłe trzymanie przycisku (myślałem, że naprowadzi Cie to na rozwiązanie). Pokaż program, który napisałeś. Zobaczymy gdzie jest problem 😉

Link do komentarza
Share on other sites

Tu też jest pewien problem: nie ma kodu "puszczenie przycisku". Zamiast tego pilot co jakiś czas wysyła sygnał "trzymam klawisz" (identycznie jak repeat w klawiaturze komputera). Stąd jedyną możliwością wykrycia puszczenia klawisza jest odnotowanie braku kodu "trzymam klawisz", ew. przyjęcie innego kodu.

Pytanie - co oznacza "brak". Czy jest to przypadkowe zakłócenie, które spowodowało przekłamanie, czy rzeczywiście ktoś puścił klawisz? Jak długo mamy czekać aby stwierdzić, że klawisz faktycznie został puszczony?

10 minut temu, Treker napisał:

przykładzie z toggle widać jakąś reakcję na ciągłe trzymanie przycisku

Tak - ale nie ma natychmiastowej reakcji na puszczenie (a raczej taka jest tu potrzebna).

Edytowano przez ethanak
  • Pomogłeś! 1
Link do komentarza
Share on other sites

16 minut temu, ethanak napisał:

Tu też jest pewien problem: nie ma kodu "puszczenie przycisku". Zamiast tego pilot co jakiś czas wysyła sygnał "trzymam klawisz" (identycznie jak repeat w klawiaturze komputera). Stąd jedyną możliwością wykrycia puszczenia klawisza jest odnotowanie braku kodu "trzymam klawisz", ew. przyjęcie innego kodu.

Pytanie - co oznacza "brak". Czy jest to przypadkowe zakłócenie, które spowodowało przekłamanie, czy rzeczywiście ktoś puścił klawisz? Jak długo mamy czekać aby stwierdzić, że klawisz faktycznie został puszczony?

Oczywiście masz rację, zakłam jednak, że przy hobbystycznym projekcie osoby początkującej taka forma realizacji tego programu całkowicie wystarczy. Żadne zakłócenia i ewentualne problemy z transmisją nie będą tutaj groźne 😉 Warto nawet napisać coś takiego dla samego treningu.

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

@ethanak @Treker dzięki za odpowiedzi, no mi faktycznie chodziło o jakiś taki kod na puszczenie przycisku, ale skoro się nie da no to wystarczy przycisk stop.

#include <RC5.h>
#include <Servo.h>
#define TSO_PIN 3//pin z czujnikiem podczerwieni
 
#define L_PWM 5
#define L_DIR 4
#define R_PWM 6
#define R_DIR 9
#define PWM_MAX 165
#define SERVO 11
#define BUZZER 10
#define LED 13

RC5 rc5(TSO_PIN); //deklaracja czujnika podczerwieni na danym pinie
Servo servo;

byte toggle;
byte address;
byte command;

int poz = 90;
 
void setup() {

  pinMode(L_DIR, OUTPUT);
  pinMode(R_DIR, OUTPUT);
  pinMode(L_PWM, OUTPUT);
  pinMode(R_PWM, OUTPUT);
 
  pinMode(BUZZER, OUTPUT);
  digitalWrite(BUZZER, 0); 
  pinMode(LED, OUTPUT); 
  digitalWrite(LED, 0); 
 
  Serial.begin(9600);

  servo.attach(SERVO);
}
 
void loop() {

  if(rc5.read(&toggle, &address, &command))
    {
      switch(command)
      {
        case 2:
        leftMotor(40);
        rightMotor(40);
        break;
        
        case 8:
        leftMotor(-40);
        rightMotor(-40);
        break;
        
        case 4:
        rightMotor(40);
        leftMotor(-40);
        break;
        
        case 6:
        leftMotor(40);
        rightMotor(-40);
        break;

        case 5:
        stopMotors();
        break;

        case 1:
        leftMotor(20);
        rightMotor(40);
        break;

        case 3:
        leftMotor(40);
        rightMotor(20);
        break;

        case 7:
        leftMotor(-20);
        rightMotor(-40);
        break;

        case 9:
        leftMotor(-40);
        rightMotor(-20);
        break;
        

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

        case 150:
        if(poz < 180)
        poz += 5;
        else
        poz = 180;
        servo.write(poz);
        break;

        case 149:
        if(poz > 0)
        poz -= 5;
        else
        poz = 0;
        servo.write(poz);
        break;
        
        
      }
    }
  else if(rc5.read(&toggle, &address, &command) == 0)
    stopMotors();

}

 
 
void leftMotor(int v){
  byte kierunek = 0;
  if(v < 0)
    kierunek = 1;
  v = map(abs(v), 0, 100, 0, PWM_MAX);
  digitalWrite(L_DIR, kierunek);
  analogWrite(L_PWM, v);
  
  
}

void rightMotor(int v){
  byte kierunek = 0;
  if(v < 0)
    kierunek = 1;
  v = map(abs(v), 0, 100, 0, PWM_MAX);
  digitalWrite(R_DIR, kierunek);
  analogWrite(R_PWM, v);
  
}

void stopMotors(){
    analogWrite(L_PWM, 0);
    analogWrite(R_PWM, 0);
}

Kod wygląda w ten sposób, myślałem że jeśli uznamy że nie odebraliśmy sygnału to tak jakbym puścił przycisk, ale wtedy robot nawet nie startował(jak usunąłem tego else to wszystko zaczęło dobrze działać).

Edytowano przez Adampi314
dodanie informacji
Link do komentarza
Share on other sites

16 godzin temu, Adampi314 napisał:

@ethanak @Treker dzięki za odpowiedzi, no mi faktycznie chodziło o jakiś taki kod na puszczenie przycisku, ale skoro się nie da no to wystarczy przycisk stop.

Jeszcze raz, na spokojnie 😉 Przykład z trzymaniem i puszczeniem przycisku da się zrobić. Nie da się zrobić przykładu z jednoczesnym trzymaniem 2 przycisków.

16 godzin temu, Adampi314 napisał:

Kod wygląda w ten sposób, myślałem że jeśli uznamy że nie odebraliśmy sygnału to tak jakbym puścił przycisk, ale wtedy robot nawet nie startował(jak usunąłem tego else to wszystko zaczęło dobrze działać).

Spróbuj zaraz za switchem dodać krótkie opóźnienie typu 10-50 ms. Zobacz co wtedy się stanie 😉

Link do komentarza
Share on other sites

Ja bym proponował na początek odłożenie robota na półkę i napisanie programu na Arduino, który na serialu będzie po prostu wypisywał komunikaty w stylu "naciśnięto klawisz X" i "puszczono klawisz X". Dopiero kiedy to będzie działać, zaimplementowanie tego w robocie.

W samym robocie można to zrobić na co najmniej dwa sposoby:

a) funkcja w stylu getEvent() - zwraca zero jeśli nic się nie stało lub numer klawisza plus kod naciśnięty/puszczony. Trzeba uwzględnić przypadek, kiedy zachodzą na siebie dwa zdarzenia (tzn. jeśli odebrano wciśnięcie klawisza A jeśli wciśnięty był B należy najpierw zwrócić "puszczono B", a dopiero za następnym wywołaniem "naciśnięto A").

b) funkcja wywoływana za każdym obrotem pętli głównej, która ustawia jakąś globalną zmienną, w której mamy kod wciśniętego klawisza lub zero jeśli żaden nie jest wciśnięty.

Oczywiście możliwości jest więcej, ale te wydają mi się najprostsze w realizacji.

  • Lubię! 2
Link do komentarza
Share on other sites

Dzięki za odpowiedzi.

@Treker dodałem delay w tym miejscu:

switch(command)
      {
    	delay(30);
        case 2:

ale to nic nie dało(tzn robot wciąż stoi, przy innych wartościach też).

@ethanak no właśnie coś takiego chciałbym zrobić ale nie wiem czy się da (np. chciałem pokombinować z keyboard, ale okazało się że tylko płytki z microcontrollerami typu 32u4 i SAMD to obsługują). Można by też spróbować podłączyć np. matrycę przycisków 4x4 (i wtedy kontrola robota jest łatwa bo wykrywa czy przycisk jest wciśnięty), ale wtedy musiał bym mieć 2 płytki i jakieś nadajniki i odbiorniki bezprzewodowej łączności). Podsumowując, potrzebuje wykrywać czy dany przycisk jest wciśnięty czy puszczony(np. na klawiaturze, keypadzie lub pilocie).

Link do komentarza
Share on other sites

11 godzin temu, Adampi314 napisał:

dodałem delay w tym miejscu:

Taaa...

Cytat

W niedzielę kąpała się w smole,
A w poniedziałek w rosole,
(...)
A na myśl jej nie przychodzi,
Żeby wykąpać się w wodzie.

Nie chodzi o to aby wstawić delay gdziekolwiek, tylko we właściwe miejsce! Czyli po odebraniu i przetworzeniu komendy (za blokiem switch).

Spróbuj!

po edycji

Według Wikipedii kod klawisza jest powtarzany co niecałe 120 milisekund - może to będzie wskazówką?

Edytowano przez ethanak
Link do komentarza
Share on other sites

@Adampi314 tak jak porada wyżej 😉 Wstaw opóźnienie za całym switchem (czyli całą funkcją warunkową), a nie za słowem "switch". Na upartego, opóźnienie możesz też wstawić tuż przed końcem pętli loop (jako ostatnią instrukcję).

Link do komentarza
Share on other sites

Racja, sory że nie pomyślałem i tak głupio wstawiłem, po wstawieniu faktycznie po switchu (poniżej zawartość loopa):

  if(rc5.read(&toggle, &address, &command))
    {
      switch(command)
      {
        case 2:
        leftMotor(40);
        rightMotor(40);
        break;
        
        case 8:
        leftMotor(-40);
        rightMotor(-40);
        break;
        
        case 4:
        rightMotor(40);
        leftMotor(-40);
        break;
        
        case 6:
        leftMotor(40);
        rightMotor(-40);
        break;

        case 5:
        stopMotors();
        break;

        case 1:
        leftMotor(20);
        rightMotor(40);
        break;

        case 3:
        leftMotor(40);
        rightMotor(20);
        break;

        case 7:
        leftMotor(-20);
        rightMotor(-40);
        break;

        case 9:
        leftMotor(-40);
        rightMotor(-20);
        break;
        

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

        case 150:
        if(poz < 180)
        poz += 5;
        else
        poz = 180;
        servo.write(poz);
        break;

        case 149:
        if(poz > 0)
        poz -= 5;
        else
        poz = 0;
        servo.write(poz);
        break;
        
        
      }
      delay(40);
    }
    
  else if(rc5.read(&toggle, &address, &command) == 0)
    stopMotors();

robot cały czas podjeżdża i zatrzymuje się co chwilę (tzn. tak rusza i staje rusza i staje co chwilę).

Link do komentarza
Share on other sites

Eksperymentowałem, i widać pewne zmiany, ale niestety wciąż nie jest to płynne, przy wartościach delay ok 10 to ledwo ruszał, a przy tych bliżej wyższych(np 300) to trochę płynniej jeździł (pewnie dlatego że dłużej mógł otrzymać daną prędkość), ale wciąż stawał co chwilę. Przy jeszcze wyższych sterowanie zaczynało robić się bardzo trudne.

Link do komentarza
Share on other sites

To dlaczego nie chcesz zrobić tego normalnie, tylko kombinujesz z jakimiś durnymi delayami? @Treker, nic nie chcę mówić ale za te sugestie to powinieneś co najmniej cztery zdrowaśki zmówić i na kolanach zrobić trzy okrążenia naokoło najbliższego przystanku autobusowego 🙂

Załóżmy, że nie sprawdzasz kiedy klawisz został naciśnięty, tylko który klawisz w tej chwili jest naciśnięty. W sumie jedna chwała - robisz sobie switcha w stylu "naciśnięta dwójka: jedziemy prosto; naciśnięta ósemka:jedziemy do tyłu; nic nie naciśnięte: nigdzie nie jedziemy".

Teraz trzeba tylko sprawdzić, jaki klawisz jest naciśnięty na pilocie.

Wiemy, że jeśli klawisz jest naciśnięty to co niecałe 120 miliekund powtarzany jest kod. Więc możemy założyć, że jeśli przez 120 milisekund nie dostaliśmy powtórki - klawisz nie jest naciśnięty.

A więc spróbujmy:

Jeśli odebraliśmy kod klawisza, zapamiętujemy kiedy go odebraliśmy i ustawiamy jakąś zmienną na jego kod. Koniec.

Jeśli nie odebraliśmy żadnego kodu, sprawdzamy czy od zapamiętanej chwili minęło już 120 milisekund. Jeśli nie - nie robimy nic. Jeśli tak - ustawiamy zmienną z poprzedniego zdania na "żaden" (czyli pewnie zero).

I teraz dopiero sprawdzamy, co siedzi w tej nieszczęsnej zmiennej, i w zależności od tego sterujemy silnikami robota.

Pasuje?

Oczywiście - nie ma szans, aby wyciągnąć moment puszczenia klawisza wcześniej, niż 120 milisekund po ostatnim wysłaniu sygnału przez pilota. Ale niestety - tak to działa, jeśli chcesz mieć dokładne informacje o wciśnięciu/puszczeniu klawisza to nie możesz posługiwać się typowym pilotem; po prostu się nie da i tego nie przeskoczysz.

Pytanie: czy 120 milisekund to jest tak dużo? Jeśli nie robisz wyścigówki to raczej nawet nie zauważysz opóźnienia...

 

Link do komentarza
Share on other sites

Witam

Mam taki problem. Chciałbym dodać do robota zdalnie sterowanego koguty policyjne z opcją wyłączenia przyciskiem na pilocie. Miały by one po kliknięciu przycisku migać, a po ponownym naciśnięciu zgasić się. Próbowałem różnych sposobów (pętli while, for, if, funkcji boolean) ale rezultatem moich prób było zacięcie się programu (utykał w pętli, która migała diodami i nie reagował na inne przyciski). Poniżej jest kod, który po wciśnięciu przycisku jednorazowo zamiga niebieską diodą i przełączy się na czerwoną, a po ponownym kliknięciu wyłączy obydwie diody. Próbuje znaleźć sposób na zapętlenie programu do momentu ponownego wciśnięcia przycisku.

#include <RC5.h>      //Biblioteka

#define L_PWM 5      // Zdefiniowanie pinów
#define L_DIR 4
#define R_PWM 6
#define R_DIR 9
#define PWM_MAX 165
#define blue 7
#define red 19
#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
  pinMode(blue, OUTPUT);
  digitalWrite(blue, LOW); //Wylaczenie diody niebieskiej
  pinMode(red, OUTPUT);
  digitalWrite(red, LOW);  ////Wylaczenie diody czerwonej

  Serial.begin(9600);
}

void loop() {


  if (rc5.read(&toggle, &address, &command)) {  // jeżeli sygnał odebrany
    Serial.print(command);
    Serial.print(toggle);

    switch (command) {      // sprawdź byte command

      case 144: //Do przodu
        leftMotor(40);
        rightMotor(40);
        break;

      case 145: //Do tyłu
        leftMotor(-40);
        rightMotor(-40);
        break;

      case 151: //STOP
        stopMotors();
        break;

      case 149: //Obrót w lewo
        leftMotor(-30);
        rightMotor(30);
        break;

      case 150: //Obrót w prawo
        leftMotor(30);
        rightMotor(-30);
        break;

      case 13: //Klakson
        digitalWrite(BUZZER, 1);
        delay(200);
        digitalWrite(BUZZER, 0);
        break;

      case 35: //koguty policyjne
        policja();
        break;
    }
    if (toggle == 0 && command == 35) {  //jeżeli przycisk 35 wciśniety po raz drugi
      digitalWrite(blue, LOW);         //wyłącz koguty
      digitalWrite(red, LOW);
    }
  }
}




void leftMotor(int V) {                                                   //lewy silnik
  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) {                                                // prawy silnik
  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() {                                                   //zatrzymanie silników
  analogWrite(L_PWM, 0); //Wylaczenie silnika lewego
  analogWrite(R_PWM, 0); //Wylaczenie silnika prawego
}

void policja() {                                                    // Koguty policyjne

  digitalWrite(blue, HIGH);
  digitalWrite(red, LOW);
  delay(200);
  digitalWrite(blue, LOW);
  digitalWrite(red, HIGH);
  delay(200);

}

PS: @TrekerŚwietny kurs,  wszystko przedstawione w sposób prosty do zrozumienia👌

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.