[072] Arduino i lokomotywa - cz. 1

[072] Arduino i lokomotywa - cz. 1

Nie odkryję koła na nowo, elektronika w modelarstwie już dano ustaliła standardy i oczywiście można do nich przystać, używając znanych protokołów i zasad. Jednak nie to jest zadaniem, które sobie dziś postawiłem, a wynika to także z innego powodu. Zabawa w miniatury pociągów – nie oszukujmy się – jest droga. Większość z nas chciałaby, ale rozsądek przemawia wyraźnie: żeby mieć więcej niż tylko jeżdżąca dookoła ciuchcia, trzeba wyskoczyć nawet z kilkudziesięciu tysięcy złotych. Czyżby nie było dla nas ratunku? Nie do końca.


Na portalach można znaleźć sporo ofert wręcz złomu kolejkowego, który zupełnie nie spełnia żadnych współczesnych standardów sterowania, ale stanowi wyzwanie: najpierw doprowadź to do porządku, a potem spraw, by zachowywało się jak miniatura pociągu, a nie zabawka. Gdzie jest problem? Pominę zupełnie uproszczenia w odwzorowaniu szczegółów takich zabawek, gdyż chcę się tu skupić na innym aspekcie. Jeśli ktoś nie jest w stanie zaakceptować takich uproszczonych miniatur, zawsze może użyć modelu wysokiej klasy, tylko z czasów gdy jeszcze użycie cyfrowego świata do sterowania lokomotywami nie było tak powszechne. W każdym razie ja tylko pragnę zwrócić uwagę, że zabawa może być dużo tańsza i bardziej kreatywna niż w wypadku zakupu topowych zestawów.

Problem wygląda tak. Mamy jakiś tam sterownik kolejki – zabawki, układamy sobie wszystko i czas na odjazd. I niestety, czar pryska. Pociąg skacze, zrywa, rusza jakby startował w wyścigu formuły pierwszej; to nie ma nic wspólnego z prawdziwą koleją. Dlaczego? Bo wszystko mamy przeskalowane. Lokomotywy, tory, wagony i kolejarze są 87 razy mniejsi – w przypadku najbardziej popularnej skali H0. Mało tego, są też 87 do trzeciej potęgi lżejsi – w uproszczeniu. I dobrze, dzięki temu mieści się nam to w mieszkaniu i waży niewiele. Tylko niestety przeskalowała się także bezwładność i w ogóle zmienne praw związanych z mechaniką. Pociąg, który w rzeczywistości hamuje kilkaset metrów i dłużej, po wyłączeniu zasilania na naszej podłodze przejedzie najwyżej kilka centymetrów i stanie dęba. Żadnej jazdy luzem tu nie ma, żadnej symulacji hamowania jak i rozpędzania. Jedyne co można zrobić, to symulować takie zachowania, operując gałką manipulatora, ale o ile przy większych prędkościach jakoś to jeszcze działa, o wrażeniu naturalności podczas manewrowania możemy zapomnieć. A już gdy mowa o lokomotywkach z tanich zestawów startowych, kiepskich i wyeksploatowanych, krzywych torach i samych sterownikach bez stabilizacji, jest wręcz tragicznie. Co zatem zrobić?

Cóż, skoro jest prąd elektryczny, to znaczy, że można nim pewno jakoś manipulować, by do realizmu zachowania się małych pociągów próbować się zbliżyć. I w tę stronę dziś pójdziemy, ale najpierw trzeba pokonać przeszkodę charakteru czysto analogowego: brak styku. Tory ze śmietnika trzeba po prostu przeszlifować i zapewnić dobry kontakt pomiędzy segmentami. Przyłącza zwykle są równie kiepskie, więc polecam lutowanie. Podobnie z lokomotywą. Koła winny być oczyszczone z nalotów, a połączenia wewnątrz pewne.

Znacznie lepszym byłoby wożenie ze sobą źródła energii i otrzymywanie informacji bezprzewodowo. I do tego będę chciał kiedyś się zabrać, ale nie dziś. Dzisiaj będzie klasycznie. Gdy już uznamy, iż czyszczenia dość, należy puścić w ruch lokomotywę przy szybkości niewielkiej, a potem maksymalnej i obserwować, czy jeździ równo i nie ma nigdzie martwych stref. Skoro jest dobrze, czas zastąpić oryginalny zasilacz czymś nowoczesnym.

Najpierw garść informacji: kolejki analogowe zwykło się zasilać napięciem stałym sięgającym 12 woltów. Napięcie dostarcza się do torów, a polaryzacja związana jest z kierunkiem jazdy. Zatem źródło musi oferować zmieniające się napięcie stałe do 12 woltów o ustawianej polaryzacji. Pobór prądu przez takie lokomotywy nie przekracza 200 mA, ale już duże mogą zjeść amper. O tym za chwilę przypomnimy sobie.

Typowe „kółeczko początkującego” ma promień 457 mm, co daje obwód długości 2,83 metra, czyli ćwierć kilometra w naturze. Zróbmy teraz doświadczenie i podłączmy pełne napięcie, mierząc czas jazdy dookoła. U mnie wyszło 10 sekund, więc po przeliczeniu skali, taki pociąg zasuwa z szybkości 90 km/h Przyda się nam ta informacja dla emulacji rzeczywistych przyspieszeń i dróg hamowania. Oczywiście po zdjęciu charakterystyki możemy już kółko rozbudować do czegoś ciekawszego.

Podłączmy teraz zasilanie. Będzie nam potrzebny zasilacz stabilizowany 12 woltów z ogranicznikiem prądowym – wszak na naszych torach będą się zdarzać wypadki i zwarcia. Do tego potrzebny będzie układ ULN2003, który już wielokrotnie gościł w moich artykułach. Zawiera siedem kanałów wzmacniaczy, czy raczej kluczy, które mogą być sterowane z Arduino i pracować przy napięciach znacznie wyższych niż świat cyfrowy. No i oczywiście potrzebne będzie samo Arduino, więc jak zwykle wykorzystam płytkę edukacyjną TME, bo mam tu i wyświetlacz, i pstryczki, i potencjometr, co mam zamiar w projekcie wykorzystać.

Na początek połączenia będą prościutkie: Z 11 pinu Arduino wyjdziemy do dowolnego wejścia ULN-a, a jego wyjście połączymy z jednym z torów kolejki. Drugi dołączymy do plusa zasilacza. Trzeba tylko uważać, by napięcie 12 woltów nie przedostało się do Arduino na wskutek jakiegoś zwarcia, bo będzie bieda. Gdybyśmy mieli jakąś dużą lokomotywę albo będziemy chcieli używać kilku naraz, polecam połączyć równolegle dwie lub trzy sekcje ULN-a. Każda wytrzymuje pół ampera.

Czas na program. Wykorzystam sobie zarówno wyświetlacz jak i potencjometr. Na razie będę jeździł tylko do przodu. Jak się można domyślić, nie będziemy regulować napięcia, a zmieniać jego wypełnienie. Lokomotywie wyjdzie na to samo, a nawet więcej – to będzie podstawą symulacji rzeczywistej mechaniki, ale to za chwilę.

#include <Wire.h>                                                      // Biblioteka obsługująca magistralę I2C
#include <hd44780.h>                                                   // Biblioteka obsługująca wyświetlacze 44780
#include <hd44780ioClass/hd44780_I2Cexp.h>                             // Dodatek obsługujący wyświetlacze podłączone do ekspandera I2C
hd44780_I2Cexp lcd(0x20, I2Cexp_MCP23008, 7, 6, 5, 4, 3, 2, 1, HIGH);  // Konfiguracja połączeń wyświetlacza LCD
const byte potencjometr = A1;                                          // Port, do którego podłączymy ślizgacz potencjometru.
const byte lokomotywa = 11;                                            // Port zasilający lokomotywę.
byte szybkosc;                                                         // Zmienna przechowująca aktualną szybkość lokomotywy.

void setup() {
  lcd.begin(16, 2);             // Inicjuj wyświetlacz LCD
  pinMode(lokomotywa, OUTPUT);  // Zadeklaruj port zasilający lokomotywę jako wyjście.
}
void loop() {
  szybkosc = analogRead(potencjometr) / 4;  // Odczytaj położenie potencjometru, konwertując je do zmiennej ośmiobitowej.
  analogWrite(lokomotywa, szybkosc);        // Wyślij do lokomotywy przebieg o wypełnieniu ustawionym potencjometrem.
  lcd.setCursor(0, 0);                      // Ustaw kursor na początku wyświetlacza.
  lcd.print(szybkosc);                      // Wyświetl wartość wypełnienia przebiegu wysyłanego do lokomotywy.
  lcd.print(F("  "));                       // Wyświetl dwie spacje.
}

Na początku zatem deklaruję wszystko, co jest związane z wyświetlaczem, co już czyniłem nieraz. Przypomnę, że wyświetlacz pracuje u mnie na szynie I2C. Deklaruję też port potencjometru i wyjście sterujące zasilaniem, które nazwę lokomotywa.

Główna pętla jest boleśnie prosta: pobieram napięcie z przetwornika, do którego podłączono ślizgacz potencjometru, dzielę go przez 4 – wszak to dziesięciobitowa wartość, a PWM akceptuje osiem bitów. Następnie wysyłam to do wspomnianego generatora, wysyłając także wartość na wyświetlacz. Kompilujemy, obracamy potencjometrem i pociąg rusza. Już jest o wiele lepiej względem rozwiązania z regulatorem napięcia. Jednak nie pojeździmy z szybkością kilometra na godzinę, bo pociąg przy niskich szybkościach nadal jest niestabilny. Rzecz bierze się z faktu kiepskiej pracy silników komutatorowych przy niskich obrotach i nijak z tym się nie wygra wprost. Można jednak próbować chytrym sposobem, wykorzystując bezwładność wirnika, niewielką co prawda, częstując go tak długimi impulsami prądu, by ten zdążył zdecydowanie drgnąć i nieco się obrócić, po czym od razu należy odciąć napięcie. Poniekąd tutaj tak jest, tylko że owe impulsy są marne: domyślne PWM ma częstotliwość 490 Hz. Nijak nie zrobimy tym energii kinetycznej wirnikowi, który sobie to wszystko scałkuje, jakby był zasilany z zasilacza prądu stałego.

A może by tak jakoś obniżyć tę częstotliwość? A jakże, da się i robiłem to kiedyś, tylko w drugą stronę, chcąc pozbyć się pisków. Bo blisko 500 Hz to niemiłe piszczenie i kto zasilił tak lokomotywę, z pewnością usłyszał charakterystyczne brzęczenie. Arduino umożliwia nam wybór jednej z ośmiu częstotliwości generatora za pomocą trzech najmłodszych bitów zmiennej TCCR2B. Ustawione dadzą nam troszkę powyżej 30 Hz. Dopiszmy zatem tę linię do bloku setup i zobaczmy co nam to da.

void setup() {
  TCCR2B = TCCR2B & B11111000 | B00000111;  // Zmień częstotliwość PWM na 30,64 Hz
  lcd.begin(16, 2);                         // Inicjalizuj wyświetlacz LCD
  pinMode(lokomotywa, OUTPUT);              // Zadeklaruj port zasilający lokomotywę jako wyjście.
}

Właściwie to już jest bardzo dobrze, odzyskujemy kontrolę nad niskimi obrotami, ale może mogłoby być lepiej? A no pewnie, że mogłoby. Nie wykorzystaliśmy całego potencjału bezwładności silnika i przekładni, lecz kolejne działania będą wykorzystywać zachowania nietypowe. Zwiększymy energię owych kopniaków napięcia, poruszających silnikiem. By to zrobić, należy owo napięcie podnieść – do 24 woltów. Ale to nie wszystko, posłanie takiego napięcia na malutką lokomotywkę przeciąży ją i może spowodować spalenie silnika. Dlatego zastosujemy tutaj również zmienne wypełnienie, ale o innym charakterze: po każdym impulsie związanym z pozycją potencjometru nastąpi pauza, dobrana do konkretnej lokomotywy tak, by ta zachowywała się jak najstabilniej przy wolnej jeździe, a jednocześnie by nie była przekroczona moc znamionowa. Niestety takie niesymetryczne zmienne wypełnienie nie jest już możliwe do zrobienia automatem i jak widać poniżej, uczynimy to na piechotę, używając funkcji opóźniających. Wymieńmy więc zawartość pętli głównej na coś takiego:

szybkosc = analogRead(potencjometr);  // Odczytaj położenie potencjometru.
digitalWrite(lokomotywa, 1);          // Włącz napięcie dla lokomotywy.
delayMicroseconds(16 * szybkosc);     // Zaczekaj przez czas związany z pozycją potencjometru.
digitalWrite(lokomotywa, 0);          // Wyłącz napięcie lokomotywie.
delay(50);                            // Dobierz czas do charateru silnika.

 Muszę jeszcze uczciwie dodać, że taki sposób traktowania mechaniki lokomotywy, a konkretnie układu reduktora obrotów i przeniesienia napędu, jest dla niej nieco brutalny. Mamy tutaj duże przeciążenia, które dla mocno nadwyrężonych czasem zabawek mogą być zgubne. Dlatego należy samemu zadecydować, czy nasza zabawka ma prawo być tak traktowana.

Po kompilacji możemy już cieszyć się możliwością pełnego kontrolowania maszyny nawet podczas bardzo wolnej jazdy. Ale wciąż tylko do przodu. Czas na jazdę w tył. Użyjemy tu pradawnego przekaźnika.

Można byłoby oczywiście skorzystać z jakiegoś układu elektronicznego, jednak przekaźnik ma jedną, wielką zaletę: elektronika przełączająca biegunowość może teoretycznie wpaść w stan zwarcia, gdy naraz otworzą się klucze przełączające szyny między biegunami. Tu co prawda niczemu to nie grozi, jednak w automatyce krytycznej bywa to niedopuszczalne. Przekaźnik, by zwarł, musiałby się charakterystycznie rozlecieć, co oczywiście też się zdarza, ale rzadko. Potrzebujemy przekaźnika dwusekcyjnego, to znaczy takiego, w którym mamy dwa niezależne obwody przełączające. Nie jest to konieczne, ale uprości wiele. Będziemy go zasilać z kolejnej sekcji ULN-a, którą podłączymy do pinu 12.

Przekaźnik połączymy w tak zwanym układzie krzyżowym, czyli sekcje wspólne – do torów, a sekcje wybierane – krzyżowo do plusa zasilania i wyjścia ULN-a. W ten sposób, gdy przekaźnik nie będzie zasilany, w torach popłynie prąd w jedną stronę, gdy otrzyma napięcie – w drugą.

#include <Wire.h>                                                      // Biblioteka obsługująca magistralę I2C
#include <hd44780.h>                                                   // Biblioteka obsługująca wyświetlacze 44780
#include <hd44780ioClass/hd44780_I2Cexp.h>                             // Dodatek obsługujący wyświetlacze podłączone do ekspandera I2C
hd44780_I2Cexp lcd(0x20, I2Cexp_MCP23008, 7, 6, 5, 4, 3, 2, 1, HIGH);  // Konfiguracja połączeń wyświetlacza LCD
const byte potencjometr = A1;                                          // Port, do którego podłączymy ślizgacz potencjometru.
const byte lokomotywa = 11;                                            // Port zasilający lokomotywę.
const byte kierunek = 12;                                              // Port zasilający przekaźnik kierunku.
const byte stop = 13;                                                  // Dioda STOP
int szybkosc;                                                          // Zmienna przechowująca aktualną szybkość lokomotywy.

void setup() {
  lcd.begin(16, 2);             // Inicjuj wyświetlacz LCD
  pinMode(lokomotywa, OUTPUT);  // Zadeklaruj port zasilający lokomotywę jako wyjście.
  pinMode(kierunek, OUTPUT);    // Zadeklaruj port zasilający przekaźnik kierunku jako wyjście.
  pinMode(stop, OUTPUT);        // Zadeklaruj port zasilający diodę STOP.
}
void loop() {
  szybkosc = analogRead(potencjometr);  // Odczytaj położenie potencjometru.
  lcd.setCursor(0, 0);                  // Ustaw kursor na początku wyświetlacza.

  if (szybkosc > 640) {                        // Jeśli pozycja potencjometru jest wyższa od 640...
    digitalWrite(stop, 0);                     // Wyłącz diodę STOP.
    digitalWrite(kierunek, 0);                 // Wyłącz przekaźnik kierunku (jazda do przodu).
    digitalWrite(lokomotywa, 1);               // Włącz napięcie dla lokomotywy.
    delayMicroseconds(42 * (szybkosc - 640));  // Zaczekaj przez czas związany z pozycją potencjometru.
    digitalWrite(lokomotywa, 0);               // Wyłącz napięcie lokomotywie.
    delay(50);                                 // Dobierz czas do charakteru silnika.

  } else if (szybkosc < 384) {                 // Jeśli pozycja potencjometru jest niższa od 384...
    digitalWrite(stop, 0);                     // Wyłącz diodę STOP.
    digitalWrite(kierunek, 1);                 // Włącz przekaźnik kierunku (jazda do tyłu).
    digitalWrite(lokomotywa, 1);               // Włącz napięcie dla lokomotywy.
    delayMicroseconds(42 * (384 - szybkosc));  // Zaczekaj przez czas związany z pozycją potencjometru.
    digitalWrite(lokomotywa, 0);               // Wyłącz napięcie lokomotywie.
    delay(50);                                 // Dobierz czas do charakteru silnika.

  } else {                  // Jeśli pozycja potencjometru należy do środkowego zakresu...
    digitalWrite(stop, 1);  // Włącz diodę STOP.
  }

  lcd.setCursor(0, 0);  // Ustaw kursor na początku wyświetlacza.
  lcd.print(szybkosc);  // Wyświetl wartość wypełnienia przebiegu wysyłanego do lokomotywy.
  lcd.print(F("   "));  // Wyświetl dwie spacje.
}

W programie powołamy do życia port przekaźnika. Główna pętla będzie się teraz różnić. Podzielimy zakresy pracy potencjometru na trzy przedziały. Środkowemu damy szeroki zapas i osadzimy go w przedziale od 384 do 640. Jeśli potencjometr znajdzie się tutaj, program zinterpretuje to jako zatrzymanie kolejki. Zapas jest konieczny, żeby za każdym razem nie szukać punktu środkowego i ten przedział należy sobie ustawić tak, by było wygodnie.

I teraz jeśli potencjometr znajdzie się powyżej tego zakresu, wyłączymy przekaźnik, a następnie zrobimy to, co robiliśmy już poprzednio, lecz odejmiemy od opóźnienia 640, czyli wartość początku przedziału, by przesunąć działanie potencjometru od zera właśnie tutaj. Zmienił się też mnożnik, z 16 na 42, bo trzeba nieco zagęścić przyspieszanie – wszak teraz do ustawiania szybkości mamy mniej niż połowę zakresu pracy potencjometru.

Jazda do tyłu jest symetryczna, tylko po pierwsze, musimy włączyć przekaźnik kierunku jazdy, a po drugie – tutaj zamieniamy miejscami szybkość i przesunięcie, by odwrócić działanie potencjometru. Im bardziej w lewo, tym szybciej się cofamy.

Na koniec pozwoliłem sobie wykorzystać nudzącą się diodę na porcie trzynastym. Włącza się ona, gdy kolejka stoi, co pozwala na szybkie orientowanie się, że potencjometr znajduje się w pozycji neutralnej. Może się tak zdarzyć, że ustawimy go tuż za nią i wtedy lokomotywa jeszcze się nie poruszy, ale silnik już się będzie grzać. Dioda poinformuje nas, że tak nie jest.

W kolejnym artykule będę kontynuował temat, bo jeszcze wiele zostało do zrobienia, a poza tym jest to świetna zabawa, która tak naprawdę uczy podstaw działania automatyki przemysłowej.

Płytka edukacyjna TME-EDU-ARD-2Płytka edukacyjna TME-EDU-ARD-2Sprawdź tutaj

Przeczytaj również

Nasi partnerzy

TMETech Master EventTME EducationPoweredby
Copyright © 2024 arduino.pl