Controlling USB missile launchers from Python
Office gadgets and toys are quite interesting and useful to those spending long hours in work. From time to time everyone wants to have a little bit of fun. In this article I'll take Dream Cheeky USB missile launcher and I'll control it from within a Python applications.
The Dream Cheeky missile launcher is quite popular and there is a lot of code available to control it. In Europe you can get it from for example hightechtoyz.co.uk (it's not very widespread). In America use the company shop.
Among Python apps there is pyrocket. It has a nice GUI and a lot of features but there may be problem with getting it to work (problems with matching openCV or wxPython versions). Those using Jenkins for continuous integration can use retaliation to shoot a developers breaking builds. You can also check my repository with an Armageddon class and PyQt4 GUI application. This have been tested under Linux but should also work on other operating systems.
How does it shoots?
There are four launchers that use combusted air to launch missiles made out of foam. Before every shot the launcher compress air which is quite noisy and may blow the surprise factor. The range may vary. If you push the rockets to deep they may end up stuck on the launcher. If they will be loose the air may escape without ejecting the rocket. Find an optimum configuration for your launcher first. Usually it can fire up to few meters.
How to control it?
To control a USB based devices you need something like pyusb. This library can find, configure and exchange data with an USB devices. As the protocol for Dream Cheeky missile launchers is now known it's easy to write code controlling the device.
At start, when we connect it under Linux we can notice the manufacturer and its ID: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
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)
In init we look for the device and configure it. After that we can use send_cmd method to send commands to the toy. The launcher can move up/down left/right and shoot. Hexed numerical values triggering each of those operations are at the top of the class. For ease there is also send_move method that moves the launcher in given direction for given amount of milliseconds. Sending move signal will start the movement but you also have to send the "STOP" signal to stop it at given point.
By default you will have to run scripts via sudo (or as root) as plain user doesn't have access to such hardware. Here is an example script:
instance = Armageddon()
instance.send_move(instance.LEFT, 100)
instance.send_cmd(instance.FIRE)
So now what sinister plans you have for your missile launcher? :)
Comment article