AccShooter

AccShooter to działko strzelające kulkami i sterowane pilotem. To właśnie sposób sterowania decyduje o unikalności tego robota. Działo reaguje na ruchy pilota, a nie na przyciski. W projekcie wykorzystałem swój akcelerometr (strona projektu).

Konstrukcja została zaczerpnięta ze strony HiTechnic (link). Jest bardzo prosta a zarazem niezwykle funkcjonalna. Instrukcję budowy można ściągnąć ze strony, więc nie będę jej umieszczał.

Nie wykorzystałem oczywiście czujnika HiTechnic. Skorzystałem ze swojego czujnika przyspieszenia i pola magnetycznego (link). Do robota dodałem także swój bargraf (strona projektu) jako wskaźnik ilości pozostałych w magazynku pocisków. W tym prostym projekcie wykorzystałem więc oba stworzone przeze mnie czujniki. Na filmie widać, że oba działają znakomicie. Mój akcelerometr działa tak samo dobrze, jak oryginalny od HiTechnic.

Przechodząc do programu, muszę na wstępie zaznaczyć, że NIE korzystałem, ani nawet NIE patrzyłem na implementację ze strony HiTechnic. Sam lubię pisać swoje programy, przy okazji ucząc się nowych technik i rozwiązując powstające problemy. Sami oceńcie, czy sprostałem zadaniu.

Swój kod oczywiście zamieszczam poniżej. Krótko opiszę co tam zaprogramowałem. Na początku dołączam bibliotekę do czujnika przyspieszenia (link). Następnie definiuję kilka stałych oraz pierwsze zadanie. Zadanie to odpowiedzialne jest za monitorowanie przycisku spustu w pilocie i strzelanie, gdy ten zostanie wciśnięty. Po strzale uaktualnia wyświetlacz bargrafu, na którym wyświetlana jest pozostała ilość pocisków.

Przesuwając się w kodzie dalej, znajduje się zadanie główne. Na początku inicjalizuję wszystkie sensory, ustawiam silniki działka na pracę w trybie regulowanym, przypisuję priorytety zadaniom oraz startuję zadanie trigger. W pętli głównej programu odczytuję pomiar z czujnika przyspieszenia, oraz przeliczam do na dwa kąty pochylenia w dwóch osiach równoległych do podłogi. Te kąty to pitch oraz roll. Obliczone wartości wyświetlam na ekranie. Następnie trochę matematyki obliczającej docelowe kąty obrócenia obu silników sterujących działkiem, a na końcu ustalenie pozycji silników. Proste :P

Muszę przyznać, że nad sposobem przeliczania odczytów akcelerometru na kąty obrócenia silników spędziłem trochę czasu. Rozwiązanie jest dość proste i widoczne w kodzie (mam nadzieję).

Testy pochłonęły kilkanaście minut. Co nieco poprawiałem. Natrafiłem na problemy z komunikacją z czujnikiem przyspieszenia, ale po lekkich poprawkach w kodzie biblioteki wszystko działało.

Na filmie widać finalny efekt, który dla mnie był jak najbardziej satysfakcjonujący. Sami oceńcie który program/czujnik, mój czy HiTechnic, są lepsze.

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 #include "accmag.nxc" #define TRIGGER S3 #define ACCSENSOR S2 #define BARGRAPH S1 #define AIM_MOTORS OUT_BC #define AIM_LEFT OUT_B #define AIM_RIGHT OUT_C #define SHOOT_MOTOR OUT_A #define DEG_AIM_MAX 150 byte bar[] = {0x40, 0x7f}; task trigger() { I2CWrite(BARGRAPH, 0, bar); while(1) { if (SensorBoolean(TRIGGER)) { RotateMotorEx(SHOOT_MOTOR, 100, 360, 0, false, true); bar[1] >>= 1; I2CWrite(BARGRAPH, 0, bar); } } } task main() { SetSensorAcceleration(ACCSENSOR); SetSensorTouch(TRIGGER); SetSensorLowspeed(BARGRAPH); PosRegSetMax(AIM_MOTORS, 20, 5); priority main, 50; priority trigger, 2; StartTask(trigger); int prev_p = 0; int prev_r = 0; PosRegEnable(AIM_MOTORS); while(1) { VectorType vec = ReadSensorAccScaledEx(ACCSENSOR, ASCALE_2G); float pitch, roll; pitch = -atan(vec.Y / sqrt(vec.X*vec.X + vec.Z*vec.Z)) * 180 / PI; roll = -atan(vec.Z / sqrt(vec.X*vec.X + vec.Y*vec.Y)) * 180 / PI; ClearScreen(); TextOut(0, LCD_LINE5, FormatNum("PITCH %.2f", pitch)); TextOut(0, LCD_LINE6, FormatNum("ROLL %.2f", roll)); long p = (pitch+20) * DEG_AIM_MAX / 35; long r = roll*3; if (p < 0) p = 0; else if (p > DEG_AIM_MAX) p = DEG_AIM_MAX; if (abs(p-prev_p)+abs(r-prev_r) < 6) continue; long left, right; left = p + r; right = p - r; if (left > DEG_AIM_MAX) { right -= DEG_AIM_MAX - left; left = DEG_AIM_MAX; } else if (right > DEG_AIM_MAX) { left -= DEG_AIM_MAX - right; right = DEG_AIM_MAX; } PosRegSetAngle(AIM_LEFT, left); PosRegSetAngle(AIM_RIGHT, right); prev_r = r; prev_p = p; } }

Pokaż/ukryj cały kod

Komentarze

Szacunek

Dodane przez: katon | 2013-11-22

Dobree xD

Dodane przez: Bekuś | 2013-10-27

Dodaj swój komentarz