Cheap Helicopters In My Living Room
[Reverse Engineering the Syma S107G IR Protocol](http://www.kerrywong.com/2012/08/27/reverse-engineering-the-syma-s107g-ir-protocol/)
[s107g helicopter control via arduino](http://abarry.org/s107g-helicopter-control-via-arduino/)
Ned Jackson Lovely
@nedjl / njl@njl.us
slides @ www.njl.us
Python + Arudino + Helicopter
The goal of This Entire Talk is a Transparent Attempt to get You into Mucking with Physical Things
Arduinos are the gateway drug
The
Syma S107G
is Less Than $20 on Amazon
It Goes Up and Down
It Rotates Left and Right
It Goes Forwards and Backwards
It Has a Blinking Light
USB Charger
howardignatius
Literally, a fan that blows itself into the air
You go up and down by blowing harder and softer
Counter-rotating propellers, turn by spinning on faster or slower than the other.
"yaw" & "trim"
0 to 127
63 is the middle
There's a teeny-tiny propeller on the back that rolls the helicopter a little bit forwards and backwards
If you tilt just a little bit forward, the big propellers pull you forward
"pitch"
0 to 127
63 is "off"
The IR Protocol is easy
Four bytes, one for each setting
Atmel ATMEGA328 chip has digital & analog I/O, can talk over serial, a little bit of flash, a little bit of RAM, etc, etc, etc.
This is a full little 8-bit computer on a chip you can buy for less than $5.
The arduino is all the support stuff, the usb connection, some headers, assorted things to deal with
power, and a reset button.
int led = 13;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
digitalWrite(led, HIGH);
delay(1000);
digitalWrite(led, LOW);
delay(1000);
}
Kinda the canonical Arduino program. setup() is called after the
reset button or power is brought on, then loop is run in a loop.
This environment is to help ease people who don't really program
into hacking away with this simplified language, instead of figuring
out a C tool chain.
int led = 13;
void setup(){
pinMode(led, OUTPUT);
Serial.begin(9600);
}
void serialEvent(){
byte in = Serial.read();
if(in == 0){
digitalWrite(led, LOW);
}else if(in == 1){
digitalWrite(led, HIGH);
}
}
void loop(){
delay(1000);
}
import serial, time
s = serial.Serial('/dev/tty.usbmodem1421', 9600)
while True:
s.write([1])
time.sleep(1)
s.write([0])
time.sleep(1)
byte cmds[] = {63, 63, 0, 63};
//yaw, pitch, throttle, trim
void setup(){
pinMode(LED, OUTPUT);
digitalWrite(LED, HIGH);
Serial.begin(9600);
}
void serialEvent(){
if(Serial.available() != 4){
return;
}
for(int i=0;i<4;++i){
cmds[i] = Serial.read();
}
}
byte sendPacket(byte cmds[]){
//Blinks LED, returns time to sleep
}
void loop(){
delay(sendPacket(cmds));
}
class Heli(object):
def __init__(self):
path = [x for x in os.listdir('/dev')
if x.startswith('tty.usb')][0]
path = '/dev/'+path
self._s = serial.Serial(path, 9600)
self.yaw = 63
self.pitch = 63
self.throttle = 0
self.trim = 63
def send(self):
msg = [self.yaw, self.pitch,
self.throttle, self.trim]
self._s.write(msg)
self._s.flush()
print('sent {}'.format(msg))
Belts & Suspenders
def land(self):
for _ in range(3):
self._s.write([63, 63, 0, 63])
self._s.flush()
time.sleep(0.01)
sys.exit()
def takeoff(self):
self.yaw = self.pitch = self.trim = 63
self.throttle = 40
self.send()
time.sleep(5)
self.throttle = 90
self.send()
time.sleep(1)
self.throttle = 68 #Magic
self.send()
if __name__ == '__main__':
h = Heli()
h.takeoff()
h.yaw = 0
h.pitch = 50
h.send()
time.sleep(10)
h.land()
import heli
from flask import Flask, request, jsonify
app = Flask(__name__)
h = heli.Heli()
_ARGS = ('yaw', 'pitch', 'throttle', 'trim',)
@app.route('/api', methods=['POST'])
def api():
for k,v in request.values.items():
if k not in _ARGS:
continue
setattr(h, k, int(v))
h.send()
return jsonify(**{k:getattr(h,k) for k in _ARGS})
def main():
vc = cv2.VideoCapture(0)
tracker = Tracker()
h = Heli()
while True:
rval, frame = vc.read()
if not rval:
break
tracker.handle_frame(frame)
h.correct_drift(tracker)
if cv2.waitKey(20) == 27:
break
h.land()
It's (almost) All Just Software!
Thank You!
Ned Jackson Lovely
@nedjl / njl@njl.us
slides @ www.njl.us