Skocz do zawartości
Komentator

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 😉

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

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

Udostępnij ten post


Link to post
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.

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

@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

Udostępnij ten post


Link to post
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 😉

Udostępnij ten post


Link to post
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

Udostępnij ten post


Link to post
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).

Udostępnij ten post


Link to post
Share on other sites
(edytowany)
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

Udostępnij ten post


Link to post
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ę).

Udostępnij ten post


Link to post
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ę).

Udostępnij ten post


Link to post
Share on other sites

@Adampi314 poeksperymentowałeś trochę z krótszymi/dłuższymi opóźnieniami? Zrób trochę eksperymentów i zobacz co się dzieje 🙂

Udostępnij ten post


Link to post
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.

Udostępnij ten post


Link to post
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...

 

Udostępnij ten post


Link to post
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!

Gość
Napisz odpowiedź...

×   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...