Ten wpis dotyczy kolejowych modułów Arduino. Dowiesz się z niego:
- Jakie są możliwe stany zajętości toru?
- Jak odczytać informację o zajętości wybranego odcinka toru?
- Jak zmienić sygnał na semaforze pod wpływem zajęcia toru?
Wprowadzenie
Do tego przykładu wykorzystam moduł detektora niezajętości odcinków oznaczonego kodem 0204. To urządzenie umożliwia sprawdzanie obecności taboru na 4 odcinkach torów.
Zaczniemy od tego jak odczytać dane, a potem zastosujemy to w konkretnym przykładzie.
O tym jak podłączyć moduł do torów i innych urządzeń możesz przeczytać w tym artykule.
Stan zajętości torów
Z punktu widzenia prowadzenia ruchu pociągów, ważne jest uzyskaniu potwierdzenia, że tor na który chcemy skierować pociąg jest pusty i nie dojdzie to zderzenia. Stąd też mówimy o detekcji niezajętości torów.
Definicja niezajętości toru w kodzie biblioteki przewiduje kilka możliwych wartości:
enum TrackUnoccupancy{
TRACK_UNOCCUPANCY_UNKNOWN = 0,
TRACK_OCCUPIED = 1,
TRACK_UNOCCUPIED = 2
};
Stan TRACK_OCCUPIED oznacza, że tor jest zajęty przez tabor.
Stan TRACK_UNOCCUPIED oznacza, że tor nie jest zajęty przez tabor.
Stan TRACK_UNOCCUPANCY_UNKNOWN wykazywany jest, gdy nie można jednoznacznie określić stanu niezajętości toru lub odczyt informacji nie był możliwy.
Sprawdzanie stanu niezajętości toru
Sprawdzanie stanu niezajętości wybranego odcinka toru odbywa się poprzez wysłanie do modułu detektora odpowiedniej ramki danych. Możesz to zrobić z wykorzystaniem programu w urządzeniu do którego podłączony jest sterownik (np. płytki typu Arduino z własnym kodem) lub gotowego kontrolera segmentu.
Aby wysłać ramkę danych do odczytu stanu zajętości toru wykonujemy polecenie checkObjectState, podając jako argument wybrany detektor niezajętości:
TrackOccupancyDetectorRef track1 = new TrackOccupancyDetector(30, 1, "Track 1);
TrackOccupancy result = modules->checkObjectState(track1);
Jest na to też inny sposób, który pokaże Ci w przykładzie.
Przykład
W tym przykładzie wykorzystamy płytkę z podłączonymi sterownikami i czujnikami. Do napisania programu sterującego semaforem i odczytem danych z czujnika wykorzystamy bibliotekę trainbrains SDK. W tym celu należy pobrać bibliotekę i dołączyć ją do projektu. Zależnie od środowiska programistycznego (IDE) będzie się to odbywało nieco inaczej. Możesz obejrzeć to w materiale wideo.
Pełny kod do tego przykładu możesz pobrać z repozytorium trainbrains.
Projekt
Załóżmy, że budujemy makietę z 1 semaforem i jednym czujnikiem niezajętości. Wykorzystamy więc różne 2 moduły:
- jednokanałowy sterownik semafora świetlnego pod adresem 10
- czterokanałowy czujnik niezajętości toru pod adresem 30
Nasze urządzenia przytorowe są podłączone do sterowników w następujący sposób:
- Model semafora świetlnego A jest podłączony do sterownika pod adresem 10, kanał 1;
- Tor 1 jest podłączony do czujnika niezajętości pod adresem 30, kanał 4.
Cel
Celem programu niech będzie samoczynne podawanie sygnału zezwalającego na jazdę, gdy odcinek za semaforem jest wolny, oraz sygnału „Stój!” gdy odcinek jest zajęty.
Będzie to w dużym uproszczeniu przypominać sytuację jaką możemy obserwować gdy tabor zajmuje odcinki toru na linii wyposażonej w Samoczynną Blokadę Liniową (choć naprawdę działa ona inaczej).
Krok 1. Deklaracja użytych urządzeń przytorowych
Deklarujemy w kodzie programu jakimi urządzeniami przytorowymi będziemy sterować. Można to zrobić na przykład w ten sposób:
#include <Arduino.h>
#include "TrainbrainsModules.h"
TrainbrainsModulesRef modules = new TrainbrainsModules();
TrackUnoccupancyDetectorRef track1 = new TrackUnoccupancyDetector(30, 1, "Track 1");
LightSignalRef signalA = new LightSignal(10, "Signal A");
void setup()
{
modules->init();
modules->use(track1);
modules->use(signalA);
}
Domyślnym numerem kanału jest 1. W tym przypadku nie trzeba podawać go ręcznie
Krok 2. Reagujemy na zajmowanie toru
Zmianę sygnału na semaforze powiążemy bezpośrednio ze zdarzeniem zajęcia i zwolnienia toru:
void setup()
{
modules->init();
modules->use(track1);
modules->use(signalA);
track1->whenTrackOccupied([](TrackUnoccupancyDetectorRef detector){ modules->setSignalAspect(signalA, PKPSignalAspect::Stop); });
track1->whenTrackReleased([](TrackUnoccupancyDetectorRef detector){ modules->setSignalAspect(signalA, PKPSignalAspect::Clear); });
}
A następnie, w pętli głównej programu wykonamy cykliczne sprawdzanie stanu wszystkich wykorzystywanych obiektów:
void loop()
{
modules->checkUsedObjectsState();
}
Cała reszta zadzieje się samoczynnie. Gdy w trakcie sprawdzania zajętości toru stwierdzona zostanie zmiana na stan „zajęty”, wówczas wykonane zostanie polecenie skojarzone z tym zdarzeniem, czy podanie na semaforze sygnału „Stój!”. W odwrotnej sytuacji, wykonane zostanie drugie skojarzone polecenie.
Pełny kod tego przykładu możesz pobrać tutaj.
To już prawie wszystko
Hej!
Mam nadzieję, że ten wpis jest dla Ciebie wartościowy. Może chcesz pomóc w rozwoju tych materiałów? Wystarczy, że zostawisz poniżej komentarz co o nim myślisz, czego Ci zabrakło lub co Twoim zdaniem trzeba poprawić albo dasz mu łapkę w gorę 👍
Otrzymuj informacje o nowych ciekawych materiałach. Dołącz do newslettera trainbrains!