Miotacz płomieni

Robot ten zrodził się z mojej pasji i fascynacji pirotechniką i ogniem jako takim. Nikt wcześniej nie stworzył jeżdżącego miotacza ognia z klocków Lego (przynajmniej nie na YT), co zmotywowało mnie do budowy tego wspaniałego pojazdu.

Z założenia robot miał poruszać się swobodnie, wykrywać przeszkody i atakować je płomieniami. Jak się później okazało nie było mi łatwo osiągnąć takiej funkcjonalności na początku, ale w miarę jak ulepszałem program osiągnąłem coś co spełniało swoją funkcję. Ale po kolei...

Konstrukcja jeżdżącej podstawy nie była trudna. W zasadzie to najwięcej problemów miałem z umocowaniem pojemnika z gazem i odpowiedniej budowie systemu spustowego. Próbowałem przekładni, kół zębatych, ale najlepsza okazała się konstrukcja prostej dźwigni. Przeglądając instrukcję budowy sam/a przekonasz się, że to rozwiązanie zapewniało największą prostotę i elastyczność konfiguracji. Zapewniłem również możliwość błyskawicznego rozbrojenia systemu poprzez wyciągnięcie jednej osi. Było to niezbędne na wypadek ewentualnej awarii programu.

Jeżeli chodzi o sam program, to działa on bardzo prymitywnie. Robot obraca się wokół własnej osi aż czujnik ultradźwiękowy nie wykryje jakiejś potencjalnej przeszkody. Jeżeli po całym obrocie przeszkoda nie zostanie wykryta, robot obraca się w losowym kierunku i jedzie prosto przez chwilę. Po wykryciu celu robot podąża do niego ruchem falistym. Zapewnia to większy zakres pracy czujnika odległości i zmniejsza prawdopodobieństwo minięcia przeszkody. Jeżeli cel okazał się tylko fałszywym odczytem, robot po 5 sekundach przerywa jazdę i szuka nowego. Ostatecznie, gdy cel jest znaleziony, robot do niego podjechał i zatrzymał się, następuje atak płomieniami, po czym pojazd oddala się do tyłu i zmienia kierunek jazdy.

Całość nie jest zbyt dokładna, ale moim celem nie było opracowanie idealnego programu sterującego, a samo zaprezentowanie idei jeżdżącego miotacza ognia.

Niektórzy powiedzą, że płomienie zniszczyły tylko klocki i cały projekt nie był tego warty. Rzeczywiście może się zdarzyć, że klocki, zwłaszcza z przodu stopią się. Wszystkie jazdy wykonywałem przy całkowicie bezwietrznej pogodzie, czas trwania płomieni ograniczyłem do sekundy, a przy sobie miałem cały czas gaśnicę. W trakcie testów nie zniszczyłem ani jednego klocka! Jeżeli będziesz dostatecznie ostrożny/a i twoje klocki nie ucierpią, gdy zechcesz zbudować podobną maszynkę.

Podsumowując, robot sprawował się wyśmienicie, a półmetrowe płomienie dostarczyły mi nie mało rozrywki. Polecam każdemu ten niecodzienny projekt!

Wideo



Galeria

Galeria 3D

Obrazy w tej galerii możesz oglądać jedynie przy użyciu specjalnych czerwono-niebieskich okularów. Można je nabyć w wielu sklepach internetowych za bardzo małe pieniądze.


Kod programu

//author: Krzysztof Kapusta, All rights reserved #define MOTORS OUT_AB #define TRIGGER OUT_C #define USONIC IN_1 #define EMERGENCY IN_3 #define DIODE IN_4 #define TARGET_FOUND (SensorUS(USONIC) < 130) bool is_fire_on = false; mutex FIRE_MUTEX; void fire(int ms, int power) { int angle = 150*100/power+30; SetSensorColorRed(DIODE); Acquire(FIRE_MUTEX); RotateMotor(TRIGGER, 50, angle); is_fire_on = true; Release(FIRE_MUTEX); Wait(ms); Acquire(FIRE_MUTEX); RotateMotor(TRIGGER, -50, angle); is_fire_on = false; Release(FIRE_MUTEX); SetSensorColorGreen(DIODE); } void init() { SetSensorTouch(EMERGENCY); SetSensorColorGreen(DIODE); SetSensorLowspeed(USONIC); } bool search() { const long ctick = CurrentTick(); OnFwdSync(MOTORS, 60, (Random(2)*2-1)*100); Wait(SEC_1); while (!TARGET_FOUND & CurrentTick()-ctick < SEC_5); if (CurrentTick()-ctick > SEC_5) { Wait(Random(SEC_4)); Off(MOTORS); return false; } else { Wait(MS_400); // so that it turns more to the object if found Off(MOTORS); return true; } } bool approach() { const long firsttick = CurrentTick(); long turntick = 0; // zero makes the robot turn instantly after entering the loop below const int wandertime = 800; // time between turns bool direction = -1; // -1 or 1 for left or right unsigned int turnradius = 10; OnFwdSync(MOTORS, 100, turnradius*direction); // half a turn for the beginning Wait(wandertime/2); while(SensorUS(USONIC) > 27) { // while not too close to the target if (SensorUS(USONIC) == 255 & CurrentTick()-firsttick >= SEC_6) { // if target is lost and the robot drives for more than specified time Off(MOTORS); // shut motors down return false; } if (CurrentTick()-turntick > wandertime) { // changing direction turntick = CurrentTick(); direction = -direction; OnFwdSync(MOTORS, 100, turnradius*direction); } } Off(MOTORS); return true; } task emergency_watch(); task main() { init(); StartTask(emergency_watch); while (true) { if (search()) { if (approach()) { SetSensorColorBlue(DIODE); fire(1000, 100); SetSensorColorBlue(DIODE); RotateMotorEx(MOTORS, -100, 3*360, 0, false, false); RotateMotorEx(MOTORS, -100, 3*360, (Random(2)*2-1)*100, true, false); //turn away from target approach(); SetSensorColorGreen(DIODE); } } else { OnFwdReg(MOTORS, 100, OUT_REGMODE_SPEED); const long tick = CurrentTick(); while (CurrentTick()-tick < SEC_4 & !TARGET_FOUND); Off(MOTORS); } } } task emergency_watch() { while (!SensorBoolean(EMERGENCY)); Acquire(FIRE_MUTEX); if (is_fire_on) RotateMotor(TRIGGER, 100, -180); StopAllTasks(); }

Pokaż/ukryj cały kod

Komentarze

Brak komentarzy. Bądź pierwszy! Dodaj komentarz!

Dodaj swój komentarz