pomysły, inspiracje…

Nowy termin spotkań

Zapraszam w piątki godz. 10:00, sala 1064

Theo Jansen

Pan Bartek chyba się nudzi w czasie sesji 😉 Podczas gdy inni studenci poświęcają się zaliczeniom/egzaminom, to on zainspirował się pracami Theo Jansena:

Wynikiem tych inspiracji są poniższe symulacje:

A co z tego wyniknie? Czas pokaże…

KG (c) 2020

UPDATE:
Model 3D wykonany, drukarka w ruch, program wgrany i oto efekt:

Brawo Pan Bartek!

KG (c) październik 2020

Wojny robotów i czujka pola magnetycznego

Mamy nowy pomysł: WOJNY ROBOTÓW ! Będzie trochę zabawy z prostym sterowaniem pojazdami trójkołowymi, połączonymi z elementami rywalizacji. Będzie też zabawa w modelowanie 3D i wydruk gotowych „pojazdów”. Szkice z „burzy mózgów”:

Właśnie z powodu nowego pomyłu przetestowaliśmy działanie czujki pola magnetycznego SS49E – dziecinnie proste 😉 Podłączamy do zasilania (5V z Arduino UNO) a wyjście #3 do portu analogowego.

Odczytywane napięcie z portu analogowego tłumaczymy na wartość pola  magnetycznego zgodnie z poniższym rysunkiem (z noty katalogowej czujnika).

Zaletą tego konretnego czujnika (SS49E) jest możliwość odczytywania pola z obu biegunów magnesu – czyli z biegunu półnonego i południowego. Są bowiem inne czujki, które informują nas jedynie o wartości pola z jednego bieguna, a na pole z przeciwnego bieguna są „głuche”. 

Nas nie interesują wartości w mT, a raczej sama informacja zbliżenia do magnesu. No właśnie – przetesowaliśmy kilka małych (i większych) magnesów, w tym neodymowe – bardzo silne. Będzie się działo!

(c) K.G.

regularnie

Regularne zajęcia, omówienie planów na przyszłość – różne projekty.

  • finisz Line Folowera (brawo p. Bartek),
  • rozwiązanie kwestii Arduino Mega i biblioteki SoftwareSerial w kontekście obsługi modułu BlueTooth – nie działa z powodów opisywanych tutaj (zwracam uwagę na sekcję Limitations), ale … po co nam SoftwareSerial skoro Mega ma 3 part UARTów? Zamiana SoftwareSerial na Serial1 rozwiązuje problem,
  • pojazd (miniaturka) przekazany p. Mateuszowi – trzeba zrobić sterowanie, aby przenieść to na większy model,
  • sterowanie wieżyczką (2x serwo) – p. Łukasz ma zadanie z układem współrzędnych na kartce papieru i laserem sterowanym przez port szeregowy (ponownie UART),
  • kolorowe kółka (ws2812) ciągle czekają na p. Mariusza,
  • kolorowe ozdoby (ws2812) do naszego robota – p. Bartek?

(c) K.G. 2019

Optymalizacja sterowania

Słowem wstępu…

Dzisiejszego dnia pracowaliśmy nad optymalizacją naszego sterowania pojazdem.

Wciąż używamy do tego naszego smartfona, a konkretniej aplikacji „ArduinoRC”, która za pomocą bluetooth w naszym telefonie łączy się z modułem Bluetooth XM-15B podłączonego do Arduino. Więcej o tym w tym artykule.

Na poniższym zdjęciu nasz wypasiony „panel sterowania” 🙂

 

Dotychczas nasz program działał w dosyć prosty sposób – jeżeli Arduino odczytało określony znak z komunikacji szeregowej  bluetooth, to przekazywało do silniczka konkretne stany tak aby koła kręciły się na przykład w przód.

 

Poznaliśmy jednak głębszą teorię sterowania i pojawił się następujący problem:

A więc w aplikacji „ArduinoRC” klikamy strzałkę w górę. Załóżmy że przekazywany znak to literka 'W', po odczytaniu której kółka mają się kręcić w przód.  Po przekazaniu jej komunikacją szeregową, Arduino posłusznie uruchamia silniczki, po czym je wyłącza. Gdy na telefonie tym razem przytrzymamy strzałkę, zamiast pojedynczego znaku 'W', Arduino odczyta serie znaków – „WWWWWWWWWW … „. Po każdym z odczytanych znaków silniczki na chwilę staną, po czym po wczytaniu następnego – znowu ruszą. Taki efekt 'szarpania' to nienajlepsze rozwiązanie ponieważ ciągłe włączanie i wyłączanie silniczka powoduje większe zużycie baterii. Więc zamiast sekwencji:

włącz(1) – wyłącz(1) – włącz(2) – wyłącz(2) – włącz(3) – wyłącz(3)

proponujemy logiczniejsza sekwencje:

włącz(1) – kontynuuj(2) – kontynuuj(3) – wyłącz(3).

Oczywiście nie zobaczymy tego problemu gołym okiem, ponieważ Arduino może odczytywać parę tysięcy takich znaków na sekundę.

Rozwiązanie problemu

Pomysłów na rozwiązanie tego problemu było parę, trzeba było jednak liczyć się z tym że Arduino to nie komputer stacjonarny i warto zrobić to w miarę możliwości optymalnie, aby nie zaśmiecać pamięci mikrokontrolera.

Z pomocą przyszła nam funkcja millis() z wbudowanej biblioteki, która zwraca czas który upłynął od włączenia urządzenia w milisekundach. Utworzyliśmy też parę pomocniczych zmiennych i utworzyliśmy sprytny sposób aby usprawnić pracę silnika.

Znowu użyłem swoich ponadprzeciętnych umiejętności artystycznych oraz zaawansowanego oprogramowania do obróbki graficznej (Paint i Gimp) aby stworzyć kilka schematów blokowych.

Przedstawiają one po kolei:

1. Działanie głównej pętli loop

Jak widać główna pętla programu Arduino będzie składała się z dwóch bloków: Obsługi Bluetootha, a potem Obsługi stopu silnika. Tak, tylko stopu silnika, bo uruchomienie silników zajdzie się w Obsłudze Bluetooth. Raz puszczone koła w ruch zatrzymają się dopiero w drugim bloku, po upływie określonego czasu. 

2. Działanie obsługi Bluetooth

Powyższy schemat koncentruje się tylko na jednej instrukcji – jedz do przodu (wczytanie W). Gdy już wszystko będzie dobrze działać – w podobny sposób trzeba dodać kolejne polecenia (zda do tylu, w lewo i w prawo). 

Sama obsługa instrukcji jazdy do przodu (obsługa 'W') będzie obszerniej wytłumaczona za chwilę, ale już sam schemat algorytmu dużo może wyjaśnić:

3. Działanie obsługi odczytania znaku 'W'

Na początku, utwórzmy zmienną pomocniczą P i na razie przypiszmy jej liczbę 0. Będzie to zmienna przechowująca czas działania Arduino w milisekundach, po którego przekroczeniu nasze kółka przestaną się kręcić.

Zmienna DeltaT przechowywuje czas w milisekundach, przez jaki nasze kółka mają się kręcić po jednorazowym odczytaniu znaku. My akurat ustaliliśmy wartość 100 milisekund, jest to optymalna wartość przy której w praktyce nasza maszyna śmiga jak należy.

Dla lepszego wyobrażenia sobie tego o czym mowa, poniżej przedstawiłem oś przedstawiającą upływ czasu od włączenia Arduino. Zaznaczyłem zupełnie przypadkową wartość, akurat w tym przypadku oznacza, że minęło 10234 milisekund (czyli jakieś 10,2 sekund od włączenia urządzenia).

Kolejny krok w naszym schemacie to instrukcja warunkowa:

Czy P<milis() ?

W tej chwili Arduino wywołuje funkcje millis() i porównuje ją ze zmienną P. Między uruchomieniem urządzenia a wczytaniem znaku z naszego telefonu musiała minąć przynajmniej 1/1000 sekundy. Warunek zostaje więc spełniony – upływ czasu w milisekundach jest większy od 0. Przechodzimy więc do następnego bloku zgodnie ze schematem.

  1. P = millis() + DeltaT
  2. włączSilnik()

1.Zmienna P przyjmuje wartość sumy aktualnego upływu czasu   i   czasu przez jaki nasze kółka mają się kręcić po jednorazowym odczytaniu znaku.

2.Nasz silnik uruchamia się a wehikuł jedzie do przodu.

 

Tak jak wspominałem, zmienna P będzie przetrzymywała czas działania Arduino po którym silnik przestaje działać – teraz widzimy to na osi. Działa to mniej więcej w ten sposób:

  1. Wczytany został sygnał 'W'.
  2. Aktualnie minęło 10234 milisekund od czasu uruchomienia urządzenia.
  3. Silnik uruchamia się.
  4. Silnik ma pracować dopóki czas działania Arduino nie przekroczy 10334 milisekund.

Całkiem proste prawda? 🙂

To co opisałem do tej pory, to reakcja na pojedynczy znak 'W'. Jednak ja chcę aby mój samochodzik podjechał dwa metry do przodu, a co mi tam! Zobaczmy więc co zdarzy się jeśli przytrzymam strzałkę w aplikacji sterującej, a Arduino dostanie serie znaków „WWWWWWWWWWW … „.

Ok, analogiczna do powyższej sytuacja:

  1. Arduino odczytuje pojedynczy znak 'W'
  2. zmienna P przyjmuje odpowiednią wartość
  3. silniczek rusza

Jednak zanim minie nasze DeltaT czyli 100 milisekund, Arduino dostaje kolejny znak – kolejne 'W'. I co teraz? Wróćmy do naszego schematu blokowego nr 2 – tym razem zacznijmy działanie od instrukcji warunkowej (zmienne przypisuje tylko na początku działania programu) – i spójrzmy na poniższy wykres:

Aktualnie nasze P jest większe od czasu który upłynął dotychczas – rozpatrując więc działanie schematu blokowego, pierwszy warunek nie zostaje spełniony – wykonuje się instrukcja:

P = P + DeltaT

Czyli zmienna P która dotychczas przyjmowała konkretną wartość, powiększy się o kolejne DeltaT – czyli o 100. Oznacza to że czas działania urządzenia w którym silnik ma się wyłączyć wydłuża się o 100 milisekund.

Po odczytywaniu kolejnych znaków – analogicznie czas ten będzie się wydłużał. Będzie tym bardziej dłuższy, im dłużej przytrzymam strzałkę i im więcej znaków w jednej sekwencji odczyta Arduino. Przy tym warto zauważyć że w takiej sytuacji nasz silnik nie zatrzyma się, będzie działał dopóki trzymam strzałkę. Tak więc nasz problem został rozwiązany.

Na koniec ostatni blok programu – sprawdzenie, czy trzeba zatrzymać silniki.

4. Działanie obsługi stopu silników

 

PROGRAM i obiekty

Teraz zapoznajmy się z praktycznym kodem na Arduino. Naturalnie jest on obszerniejszy niż schematy blokowe, ponieważ obsługuje On całe działanie samochodu. W tym przykładzie zdecydowałem się na stworzenie klasy – jest to forma programowania obiektowego,  co umożliwia język C++. Różni się więc od poprzednich programów z fi-bot-a – gdzie programowaliśmy strukturalnie (język C). Opiszę więc komentarzem kluczowe linijki kodu których działanie opisałem wcześniej.

#include <SoftwareSerial.h>
#define RxD 2
#define TxD 3
#define IN1 4
#define IN2 5
#define IN3 6
#define IN4 7

SoftwareSerial btSerial(RxD,TxD);
unsigned long int przod = millis();                           
unsigned int delta_t=100;               

class Silnik      //w tym przykladzie zdecydowalem sie na stworzenie klasy - jest to forma 
{                 //programowania obiektowego co umozliwia język C++, a nie jak w poprzednich
  public:         //artykulach - tylko programowania strukturalnego a'la język C

  void wylaczSilnik()
  {
    digitalWrite(IN1,HIGH);
    digitalWrite(IN2,HIGH);
    digitalWrite(IN3,HIGH);
    digitalWrite(IN4,HIGH);
  }
 
  void doPrzodu()                        
  {
    digitalWrite(IN1,HIGH);
    digitalWrite(IN2,LOW);
    digitalWrite(IN3,HIGH);
    digitalWrite(IN4,LOW);
  }

  void doTylu()
  {
    digitalWrite(IN1,LOW);
    digitalWrite(IN2,HIGH);
    digitalWrite(IN3,LOW);
    digitalWrite(IN4,HIGH);
  }

  void wPrawo()
  {
    digitalWrite(IN1,HIGH);
    digitalWrite(IN2,LOW);
    digitalWrite(IN3,HIGH);
    digitalWrite(IN4,HIGH);
  }

  void wLewo()
  {
     digitalWrite(IN1,HIGH);
     digitalWrite(IN2,HIGH);
     digitalWrite(IN3,HIGH);
     digitalWrite(IN4,LOW);
  }
};

  Silnik Maria;

void setup() {
  Serial.begin(9600);
  Serial.println("start!");
  btSerial.begin(9600);
  pinMode(4,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
 
}
              
void loop() {                          //schemat blokowy nr 1
  if(btSerial.available())             //schemat blokowy nr 3
  {
    char zn=btSerial.read();           
    Serial.println(zn);

   
    switch(zn)
    {
      case 'W':                        //schemat blokowy nr 2
      if(przod<millis())               
      {
        przod=millis()+delta_t;        
        Maria.doPrzodu();
      }

      else                              
      {
        przod+=delta_t;
      }

      break;

      case 'S':
      if(przod<millis())
      {
        przod=millis()+delta_t;
        Maria.doTylu();
      }

      else
      {
        przod+=delta_t;
      }
     
      break;

      case 'A':
      if(przod<millis())
      {
        przod=millis()+delta_t;
        Maria.wLewo();
      }

      else
      {
        przod+=delta_t;
      }
      break;
     
      case 'D':
      if(przod<millis())
      {
        przod=millis()+delta_t;
        Maria.wPrawo();
      }

      else
      {
        przod+=delta_t;
      }
      break;
    }
  }

  if(millis()>przod)                    //schemat blokowy nr 4
    {
      Maria.wylaczSilnik();             
    }
}

To by było na tyle, bądźcie na bieżąco 🙂

Pozdrawiam!

(c) Przemysław Baj 2018

Robot – maskotka (cz. 1)

Dziś trafiło mnie olśnienie – dziękuję Szymonowi, Mateuszowi i Przemkowi za naszą wspólną rozmowę, w wyniku której powstał ten właśnie koncept. Czyli: aby nasza maskotka była atrakcyjna (przypominała bardziej robota niż popielniczkę na kółkach :P) zakupiłem taki oto gadget:

KASK OTWARTY JET WL708 SKUTER WHITE XS HOMOLOGACJA

Na korpusie (jak na razie z aluminiowego śmietnika) zamocujemy efektowny kask 😉 No z takim bajerem to będzie prawdziwy robot 😉 Warto zadbać o ciekawą kolorystykę samego korpusu. Trafił mnie taki oto pomysł (już mówiłem – w stylu „artystów” znad polskiego morza zarabiających na tworzeniu futurystycznych obrazów sprejami i czym-tam popadnie). Chodzi mi o taki efekt (jest kto chętny do malowania? albo ma znajomego?):

Jeśli chodzi o sam korpus: to kupno kosza już nieaktualne – lepiej akusz blachy duraluminiowej i ją sobie wygiąć. Na allegro arkusz 100x50cm i grubość 1mm (czyli grubość aż aż) to koszt ~40zł. Dużo bardziej opłacalne. Już się dowiedziałem, że taką blachę Wydział ma na stanie (procedura przejęcia arkusza już rozpoczęta!). Ale jest lepszy pomysł niż tworzenie walca… mianowicie konstrukcja typu łezka. Proszę przyjrzeć się poniższym obrazkowi (rzut z góry):

Łatwo przygotować podstawę takiej konstrukcji (płyta meblowa 18mm oraz wyrzynarka). Zyskujemy:

  • stabilność konstrukcji – dwa koła wewnątrz „łezki”, szerko jak się da. Trzecie koło (skrętne) na dole konstrukcji
  • łączenie blachy (na dole) proste wo wykonania – umieszczamy kawał drewienka (znowu płyta meblowa? cóż, to mam pod ręką!) i przewiercamy do niej
  • to dużo ciekawszy kształt niż walec – nikt nie powie, że to kosz na śmieci

Arkusz blachy może mieć wysokość ~50cm, więc cała konstrukcja może wyglądać jakoś tak (proszę sobie zwizualizować jeszcze ten kask na górze! mi się projektować w 3d nie chciało :P)

 

Jeszcze jedno: głowa (kask) może (musi!) być ruchoma (kręcić się o 360 stopni) a może nawet…. podnosić się do góry! Potrzeba przekładnia ślimakowa. Skąd? Hmm…. ma ktoś stary, niepotrzebny fotel obrotowy? 😉 Tak tak, trzeba kombinować 😉

I co Wy na to? Dziękuję za inspirację i dzisiejszą rozmowę!

(c) KG 2018

sterujemy pojazdem – oprogramowanie

Kontynuujemy oprogramowywanie pojazdu – ciągle chodzi nam o jak najpłynniejszą jazdę.

Propozycje softu:

  • tworzymy liczniki czasu jazdy (w milisekundach) do przodu, w lewo, w prawo
  • każdorazowe naciskanie przycisków na pilocie zwiększa odpowiednie liczniki
  • w pętli głównej unikamy zatrzymywania Arduino – czyli funkcji delay, zamiast to
  • używamy funkcji millis() do sprawdzenia aktualnego czasu i wyłączeniu silników, jeśli liczniki pracy do przodu (w lewo, w prawo) się skończyły
  • a teraz najciekawsze modyfikacje:
  • jeśli oba liczniki: do przodu i skrętu (nieważne: w lewo czy w prawo) są niezerowe, to w zależności od ich stosunku sterujemy PWM-em koła i robimy albo lekki skręt, albo bardzo mocny (bez jechania do przodu).

Kolejne zajęcia po Świętach – wtorek 25 kwietnia – sterujemy pilotem platformą – nie zapomnijcie przynieść ze sobą pilota na podczerwień.  Zapraszam!

 

sterujemy pojazdem (TSOP 2236) + tuning platformy

Rozpoczęliśmy od sprawdzenia, na ile czasu jazdy starczą nam zainstalowane akumulatorki. Pierwszy program był się bardzo prosty – cała naprzód (i  mierzymy prąd).

Potem zamonotowaliśmy czujkę TSOP 2236 i wpisaliśmy obsługę poleceń: jedź do przodu, tyłu, skręcaj (niektórzy nawet dwa rodziaje skrętów – ciasny, oraz szeroki).

Okazuje się, że pojazdy jeżdzą, ale trudno się nimi steruje – wykręcenie „ósemki” na przygotowanym torze nie jest wcale łatwe. Sprawa wymaga odpowiedniego oprogramowania rozkazów jazdy – na tym trzeba się skupić.

Kolejne zajęcia – także we wtorek 16:00 – sterujemy pilotem platformą – nie zapomnijcie przynieść ze sobą pilota od TV/radia/odkurzacza.  Zapraszam!

 

pilot od TV — czujka TSOP 22xx + platforma pojazdu

Poznaliśmy odbiornik podczerwieni TSOP 2236. 

#define VCC 13
#define IR 12
#include <IRLib.h>
IRrecv pilot(IR);//pin
IRdecode dekoder;

void setup(){
  pinMode(VCC, OUTPUT);
  digitalWrite(VCC, 1);//wlaczamy napiecie dla odbiornika IR
  pilot.enableIRIn();//uruchamiamy odbiornik IR
  Serial.begin(9600);
}

void loop() 
{
   if (pilot.GetResults(&dekoder)) {
     dekoder.decode();    //dekoduj dane
     pilot.resume();     //restartuj odbiornik
     Serial.print("0x");      
     Serial.println(dekoder.value, HEX);//szesnastkowo - tak tylko...
   }//if
}/loop

W powyższym przykładzie zakładam, że pilot odbiornik IR podłączony był bezpośrednio do płytki Arduino o tak:

co jest bardzo stabilne i (warto podkreślić) nie wymaga płytki stykowej. Wszystko zgodnie ze specyfikacją – odbiornik IR dostaje zasilanie 5V z pinu #13 Arduina, a wymagany prąd to tylko 5mA (czy pamiętasz, jakim maksymalnie prądem można obciążyć piny cyfrowe Arduino?). Dlatego na początku kodu pojawia się deklaracja VCC i włączenie tego pinu. Reszta zgodna z biblioteką IRLib – nie musimy bawić się w dekodowanie sygnału, wszystko zostało zrobione przez Chris Younga – dziękujemy!

Dodatkowo: zbudowaliśmy platformę pojazdu, którą za tydzień – będziemy sterować pilotem od TV. Jak widać stawiam na prostotę i możliwość późniejszej rozbudowy – dlatego nasze pojazdy są dość sporych rozmiarów. Zachęcam do tego typu prac ręcznych.

Kolejne zajęcia – także we wtorek 16:00 – sterujemy pilotem platformą – nie zapomnijcie przynieść ze sobą pilota od TV/radia/odkurzacza.  Zapraszam!

 

Zaczynamy!

No i rozpoczynamy nasze spotkania w roku akademickim 2016/2017. Wygląda na to, że będziemy poznawać platformę Arduino od zera (ze względu na nowe osoby) ale kto wie, co z tego wyjdzie? Zobaczymy!

Ustaliliśmy, że nasze spotkania będą we wtorki godz. 16:00 sala 1064. Zapraszam wszystkich, także tych mało zdecydowanych 😉

robocomp_logotyp

Przy okazji – w Krakowie odbędzie się Festiwal Robotyki ROBOCOMP w dniu 22-10-2016. Nie pchamy się tam, ale warto zajrzeć co robią inni i czerpać inspirację. A może zafascynowani takim i zawodami sami nabierzemy ochoty na uczestnictwo? Warto przyjrzeć się konkurencjom…Proszę oglądać i chłonąć bakcyla robotyki 😉

A może trochę więcej sztucznej inteligencji? Czyli jak nauczyć robota wydostawania się z labiryntu? Warto przeczytać ten artykuilik.vintage maze structure with red arrows showing the perfect path through the maze Jest to o tyle ciekawe, że zmagamy się tutaj ze skromnymi zasobami mikrokontrolera, czyli właśnie szkolimy się mądrego dysponowania pamięcią operacyjną i mocą obliczeniową. Jest to fajne wyzwanie!