Wyrzutnia rakiet na USB sterowana z poziomu Pythona

Idziemy na biurową wojnę z wyrzutniami rakiet podłączanymi do komputera

Pośród sprzętu elektronicznego znajdziemy różne gadżety i zabawki, a w nich narzędzia do wojny totalnej. Przedstawicielem tej grupy jest wyrzutnia rakiet na USB. Pozwala ona ustrzelić w biurze niczego nie spodziewającą się ofiarę. Popularnym producentem takich wyrzutni jest Dream Cheeky. Interfejs do wyrzutni tego producenta jest już rozpracowany i istnieje szereg aplikacji pozwalających kontrolować je. W Europie dostać można je w hightechtoyz.co.uk.

Z aplikacji napisanych w Pythonie mamy pyrocket. Oferuje ładne i rozbudowane GUI, jednak mogą pojawić się problemy ze zgraniem wersji wszystkich bibliotek (np. openCV na Ubuntu). Skrypt retaliation skierowany jest do programistów używających Jenkinsa. Za jego pomocą możemy ostrzeliwać programistów, którzy popsują builda. Na potrzeby tego artykułu stworzyłem także prostą klasę i aplikację PyQt4.

Jak można się domyślać w tym artykule przyjrzę się takiej wyrzutni i sterowaniu z poziomu Pythona - pod Linuksem.

Wyrzutnia rakiet Dream Cheeky
Wyrzutnia rakiet Dream Cheeky

Jak to strzela?

Wyrzutnia posiada "magazynek" na cztery pociski - małe rakiety wykonane z gąbki. Wyrzutnie działają na sprężone powietrze. Przed wystrzałem powietrze jest sprężane wewnątrz urządzenia (co hałasuje). Zasieg nie jest stały i zależy od tego jak głęboko nadziejemy rakietę na wyrzutnię. Im ciaśniej tym zasięg jest większy, ale jeżeli przesadzimy to rakieta utknie na wyrzutni, albo ledwo z niej spadnie. Średnio jest to kilka metrów.

Jak tym sterować?

Wszystkie wymienione Pythonowe aplikacje do obsługi wyrzutni Dream Cheeky używają pyusb do wysyłania poleceń do urządzenia. Żeby to było możliwe trzeba znać specyfikację protokołu jakim urządzenie porozumiewa się z komputerem (oryginalnym oprogramowaniem). Wyrzutnie Dream Cheeky zostały rozpracowane i jest to możliwe bez problemów.

Po podłączeniu wyrzutnia przedstawia się jako:
usb 3-1: New USB device found, idVendor=2123, idProduct=1010
usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 3-1: Product: USB Missile Launcher
usb 3-1: Manufacturer: Syntekv
Do obsługi można wykorzystać poniższą klasę:
import platform
import time
import usb.core
import usb.util


class Armageddon(object):
    """
    Based on https://github.com/codedance/Retaliation
    """
    DOWN = 0x01
    UP = 0x02
    LEFT = 0x04
    RIGHT = 0x08
    FIRE = 0x10
    STOP = 0x20

    DEVICE_ORIGINAL = 'Original'
    DEVICE_THUNDER = 'Thunder'

    def __init__(self):
        self._get_device()
        self._detach_hid()
        self.DEVICE.set_configuration()

    def _get_device(self):
        self.DEVICE = usb.core.find(idVendor=0x2123, idProduct=0x1010)
        if self.DEVICE is None:
            self.DEVICE = usb.core.find(idVendor=0x0a81, idProduct=0x0701)
            if self.DEVICE is None:
                raise ValueError('Missile device not found')
            else:
                self.DEVICE_TYPE = self.DEVICE_ORIGINAL
        else:
            self.DEVICE_TYPE = self.DEVICE_THUNDER

    def _detach_hid(self):
        if "Linux" == platform.system():
            try:
                self.DEVICE.detach_kernel_driver(0)
            except Exception, e:
                pass

    def send_cmd(self, cmd):
        if self.DEVICE_THUNDER == self.DEVICE_TYPE:
            self.DEVICE.ctrl_transfer(0x21, 0x09, 0, 0,
                                      [0x02, cmd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
        elif self.DEVICE_ORIGINAL == self.DEVICE_TYPE:
            self.DEVICE.ctrl_transfer(0x21, 0x09, 0x0200, 0,
                                      [cmd])

    def send_move(self, cmd, duration_ms):
        self.send_cmd(cmd)
        time.sleep(duration_ms / 1000.0)
        self.send_cmd(self.STOP)

W inicie wyszukuje i konfiguruje wyrzutnię poprzez pyusb. Do wysyłania komend służy metoda send_cmd. Wyrzutnia może poruszać się góra/dół oraz prawo/lewo. Wartości liczbowe wywołujące żądaną akcję (zapisane jako hex) podane są na początku klasy. Metoda send_move pozwala przesuwać wyrzutnię w określonym kierunku przez określony czas (żeby wyrzutnia przestała się poruszać trzeba wydać komendę "STOP").

Żeby mieć dostęp do urządzenia trzeba odpalić skrypt poprzez sudo, albo zmienić w udevie poziom uprawnień do niego. Oto przykładowy skrypt wykorzystujący klasę Armageddon:

instance = Armageddon()
instance.send_move(instance.LEFT, 100)
instance.send_cmd(instance.FIRE)
Zaprezentowaną klasę wykorzystałem także w prostej aplikacji PyQt4 pozwalającej sterować i strzelać za pomocą przycisków i strzałek (enter dla strzału):
Aplikacja Armageddon do obsługi wyrzutni rakiet

A więc do czego planujesz zastosować to potężne narzędzie? :)

blog comments powered by Disqus

Kategorie

Strony