The Memoirs of Jim 'ung

Reverse Engineering a Syma S107G RC Helicopter

Reverse Engineering a Syma S107G RC Helicopter

Reverse Engineering a Syma S107G RC Helicopter

The Syma 107 RC helicopter is a pretty great gadget, all things considered – it’s cheap, fun, and ridiculously good for the price. It’s also a spectacular gadget for fledgling hackers.

** 1-26-2013 UPDATE – I’ve written up a full protocol specification for the Syma 107G – If you are here looking for a purely technical description of the protocol, look here** 

I first discovered a series of articles about this RC Heli on Hackaday, where a number of people had developed proof-of-concept controllers or jammers based on a decoded IR protocol for controlling the chopper. As it happened, these Heli’s were a bit of a fad in our lab and we had a number of them lying around (both alive and dead) so naturally I decided to have a go myself. I initially created a prototype Arduino IR controller that uses Processing to provide a front-end for one helicopter, then expanded it to control two similtaneously by switching the channel bits rapidly. I won’t go on too much about this here because what I actually want to talk about is a quirk in the protocol I decoded.

So there’s a decent body of work in the hacker and RC communities to decode the protocol used by the Syma 107 – here are a couple:

This post [Kerry Wong] is a really great read and a study in methodical analysis in reverse engineering.

This site [Hamsterworks] is also a great practical guide to reverse engineering the protocol and I actually used these timings for my own controller a while back.

One thing these projects both have in common is that they arrived at a protocol specification that uses 32-bits (4 bytes).

Reverse-Engineering the controller

So enter my new Saleae Logic Analyser . I’ve never used a logic analyser or oscilloscope before, so I wanted to start with a project that I knew was possible and would have an output that I already understood (or so I thought…).

As an aside, the Saleae Logic is really an excellent tool – I had read a lot about it and there are any number of superlatives floating around, but I must say it is EXACTLY what I was looking for. Great price-point, loads of features and the software is superb. If you are curious about logic analysers and don’t want to spend too much, I really recommend the Logic – it’s been great for me so far.

I noticed immediately that the board in my controller was markedly different than the ones pictured on either the above links. Mine has way more components for a start:

I began by using a multimeter to ensure that the unlabelled IC wasn’t operating at a voltage higher than 5v and wouldn’t accidentally damage the Logic analyser. Everything was fine so I began probing the pins. Here is a rough guess at the pinout (note: I only really care about the pin that drives the IR LED transmitter circuit so I never looked into confirming how the control input works, etc…):

Now that I know which pin the transmission signal is output on (pin 8), I can sniff it and see the 32-bit control protocol right? Well, almost. I should explain a little about the protocol for those who are unfamiliar.

Decoding the Physical Packet format

The following timings are based on observations I’ve made on a sample of control packets captured with the logic analyser. Here’s a picture of the full packet:

Carrier Modulation

Modulation Freq: 38khz (50% duty cycle, 26us period, so 13us high/13us low)

38khz is a common carrier frequency for consumer Infrared communications. For the uninitiated, the white blocks in the main image above are made up of the high-frequency oscillations you can see on the left. This is usually done so that various transmitters that use the same medium (in this case the Infrared light spectrum – probably around the 940nm wavelength) can transmit on a different carrier modulation frequency and not interfere with the others’ transmissions (this is called Frequency Division Multiplexing).

Symbols

There are 4 types of symbol in the packet format: Preamble, Zero (“0″), One (“1″), and a footer:

Preamble:

High: 2ms (2000us) / Low: 2ms (2000us) / Period: 4ms (2000us)

 

 

Zero:

High: 0.3ms (300us) / Low: 0.3 (300us) / Period: 0.6ms (600us)

 

 

One:

High: 0.3ms (300us) / Low: 0.7ms (700ms) / Period: 1ms (1000us)

 

 

Footer:

High: 0.3ms (300us)

I almost missed this, but there is in fact a footer pulse at the end of the packet 300 microseconds long followed by a long period of low signal until the next packet header.

 

Channels

The Syma 107G controller appears to support 2 “channels” so that two pilots can fly their heli’s at the same time without interfering with each other. Examining the behaviour of the transmitter when switching channels indicated that the only differences between the two is a) the packet transmission interval and b) a special bit in the control packet is flipped (more on this later). The image below shows the differences in packet Tx intervals when the channel select slider is flipped (channel 1 of the Logic analyser):

The transmit interval for Channel A is 120ms (start of a packet header to the start of the next packet), or 8.33 packets per second. The transmit interval for Channel B is 180ms, or 5.55 packets per second.

So surprisingly, the carrier modulation frequency remains the same on both channels – not the most robust design, huh? I suspect the reason the transmit interval is increased is to reduce the likelihood of a collision of control packets from two controllers – if a packet collision does occur, the next control frames from each controller will almost definitely be out of phase with each other, so the chopper shouldn’t just fall out of the air (though in my experience, they do get a bit clumsy when you have two going at once…).

The Control Packet Structure

So now that we understand what a packet looks like, let’s decode one and have a look at it at a higher level:

(Click for a better look)

 And here it is again:

         |     byte 0    |     byte 1    |     byte 2    |
          0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 1 0 1 0 0 1 0
         |  Decimal: 63  |  Decimal: 63  |  Decimal: 82  |

So we have a header, followed by 3 bytes (24 bits) of information, plus a footer pulse that makes up a control packet. Now lets figure out what the data means by trying various permutations of the controls (zero throttle, full throttle, 100% left turn, 100% right turn, etc…) and see how the data changes:

Type:         Data:                     Decimal Values (byte #):
100% Throttle 001111110011111101111111  (0): 63  (1): 63  (2): 127
50% Throttle  001111110011111100111111  (0): 63  (1): 63  (2): 63
100% Left     011111100011111101000110  (0): 126 (1): 63  (2): 70
100% Right    000001100011111101001011  (0): 6   (1): 63  (2): 75
100% Forward  001111110000000001010100  (0): 63  (1): 0   (2): 84
100% Back     001111110111011101010100  (0): 63  (1): 119 (2): 84
Channel A     001111110011111101010010  (0): 63  (1): 63  (2): 82
Channel B     001111110011111111010010  (0): 63  (1): 63  (2): 210

 

Note: The controller requires that there be at least some throttle applied before it will send any packets, which is why byte 2 appears to change a little on the other tests.

From this information, we can make the following assumptions:

Byte 0

- Byte 0 represents the Yaw (left/right) control.
– Byte 0 has a range of 0-127.
– 0-62 is a right turn, 63 is centre (default) value, 64-127 is a left turn.
– the first bit, bit 0, appears to always be 0.

Byte 1

- Byte 1 represents the Pitch (forward/backwards) control.
- Byte 1 has a range of 0-127.
- 0-62 is pitch forward, 63 is centre (default) value, 64-127 is pitch backwards.
- the first bit appears to always be 0.

Byte 2

- Byte 2 represents throttle and channel.
- Byte 2 (throttle) has a range of 0-127.
- 0 is 0% throttle, 127 is 100% throttle.
- the most significant bit of Byte 2 (highlighted red above) indicates which Channel is selected. 0 for Channel A, 1 for Channel B. This is how we can have 2 channels without changing the carrier frequency.

The Mystery of the Missing Byte

You may remember that I said above that everyone else who has reverse-engineered the protocol arrived at a 4-byte control packet. So where was my 4th byte? Well there’s one more dial on the controller we haven’t discussed – Trim. Trim is used to calibrate the rotor speed balance in order to account for any idiosyncrasies in the helicopter’s build that cause it to have a rotational bias to left or right.

In the other’s work, their controller sent a fourth byte containing information about the Trim dial’s setting. My controller doesn’t have that byte, but I do have Trim control… so what’s the deal? Let’s do a bit more testing:

Type:         Data:                     Decimal Values (byte #):
Trim 100% L   010100000011111101010100  (0): 80  (1): 63  (2): 84
Trim Centre   001111110011111101010100  (0): 63  (1): 63  (2): 84
Trim 100% R   001011100011111101010100  (0): 46  (1): 63  (2): 84

We can see that the only byte that changes is Byte 0, so we can assume that rather than have a whole separate packet for trim control, the controller simply offsets the Yaw by a as much as -17 (right/clockwise compensation) or +17 (left/counter-clockwise compensation).

From a reverse engineering point of view, this is an interesting quirk. I have tried and tested both kinds of remote with the same helicopters and they both work flawlessly. What’s more, before I decoded the protocol myself, I built a whole controller based on the 4-byte protocol and never had any issues. So how does the helicopter know which protocol to use?

I think it might have something to do with the footer. The 3-byte protocol doesn’t require the helicopter to do anything in order to account for trim, while the 4-byte protocol requires the chopper’s on-board controller to offset the Yaw by the Trim value. The footer appears to consist a 300us high pulse then nothing until the next header, and this appears to be the case even on the other chaps’ 4-byte packets too. I suspect that if the helicopter’s on-board controller detects the end of a packet and it has only received 3-bytes of data, it pads the trim register with zeroes (no supplied trim offset) because it can assume trim control has been applied by the handset controller. Just a guess, but it seems logical. In any case, who would have thought the helicopter would be backwards/forwards compatible?

Conclusion

So there you have it – my first foray into hardware hacking and exploration. I think I’ve arrived at a definitive physical protocol definition, with timing values even better, perhaps, than the other projects I’ve mentioned throughout.  I put this down to the use of a logic analyser applied directly to the controller – this was unaffected by delays caused by the rise/fall times of the LEDs, IR detector, etc… that were part of the receiver circuits used by Kerry Wong and Hamsterworks to get around the issue of demodulating the 38khz IR signal. I was able to use Saleae’s excellent software to overcome those issues (albeit a little manually – it won’t demodulate the signal for you to my knowledge). The Saleae Logic also allowed me to sample at 16Mhz, certainly fast enough to get a high-resolution picture of the signals and really get some tight timing values for the transitions.

I hope this helps some new hacker get to grips with some of the ideas at play in reverse-engineering and hardware hacking, it’s certainly been a journey of discovery for me. If anyone has any questions, feel free to get in touch at jimhung [at] gmail [dot] com.

On to the next project!

Jim

 ** UPDATE – 12-8-2012 **

I’ve had a little time this weekend to compare a 4-byte controller with 3-byte controller, so here are my findings.

    • The timings for the symbols and transmission intervals are identical between the two controllers, so my timings should work equally well on any revision of the 107G you end up getting.
    • One way to distinguish between which protocol version the controller is using may be the silkscreened model number and date on the controller PCB. The 3-byte controller had the model “S107T1″ and the date “20090818” printed underneath the yaw/pitch and throttle control, respectively. The 4-byte controller had “s107T2″ and “20100308” printed under the yaw/pitch control and on the right of the PCB.
    • The fourth byte indeed  communicates the value of the Trim, but I actually identified something really interesting – the offsetting of the Yaw value occurs anyway, regardless of packet type! Take a look at this:
Control:         Control packet (4 byte)           Yaw:    Trim:
Trim 100% Left:  01010000001111111011010001111011   80      123
Trim Centre:     00111101001111111100100100111000   61      56
Trim 100% Right: 00101101001111111100111100000001   45      1

I suspect that the 107G doesn’t actually do anything with the Trim packet (perhaps I’ll test that with my DIY controller sometime soon), which explains how it’s able to handle both packet types – it simply ignores anything after the 3rd byte. I suspect that the 4th byte may be used by other toys using a similar design.

** UPDATE – April 6th, 2014 **

I finally got round to finishing the post containing an actual implementation of the protocol using an Arduino Uno. You can find it here.

30 thoughts on “Reverse Engineering a Syma S107G RC Helicopter

  1. Pingback: More Fun with Syma 107 Reverse Engineering

  2. no

    A carrier frequency isn’t used for FDM. Pretty much all infrared communications use 38KHz. It’s done to minimize noise / interference from other infrared sources, since infrared light is fairly prevalent (especially in sunlight). 38khz infrared would be rather rare or impossible to occur naturally, so you get much much more reliable data transfer using a carrier frequency (it doesn’t have to be 38k, but that’s pretty much what everything uses).

  3. Pingback: Indagadores |Seguridad informatica |Seguridad en internet » Más diversión con ingeniería inversa Syma 107

  4. Pingback: – More Fun with Syma 107 Reverse Engineering

  5. Pingback: Reverse Engineering an IR Protocol | µC eXperiment

  6. Kerry

    Hi Jim,

    It’s great to see your detailed work here!

    I am a little surprised to see different protocols in different S107 revisions, and even more surprised to hear that either protocol can be used to control the S107.

    1. Jim Post author

      Hey Kerry – thanks! I was really surprised too, it’s certainly whet my appetite to learn more about how toys like this work.

      On a side note, I want to say thanks for writing up your own analysis on this topic, I’m new to this kind of thing and I can honestly say I probably wouldn’t have been able to get my head around it without having first read your great article.

      Take care,

      Jim

  7. Michał

    hi,

    about the fourth byte:
    I’ve got s107 and s800g helicopters. s800g has additional axis on remote for strafe left-right (i believe it is called “roll” in planes). It is probably using the fourth byte. The remotes are exchangeable, ie. I can use any of them to any of the coppters. Of course you can not strafe with 3-axis remote :). The trim knob is working always as the trim.

    1. Jim Post author

      Ahh – that’s really interesting! I’m in the process of taking a few other IR-controlled flying toys apart right now, but based on your tip I think I’ll pick up one of those 4 channel choppers and revisit the Syma protocol.

      It’s interesting that the 3-channel S107G controller works but doesn’t allow you to strafe – based on how most of the other control registers work, I’d assume that the swash-plate servos responsible for the strafe control would be centered on ’63’, right on ‘0-62′ and left on ’64-127′, which means that the Trim control on the S107G controller would also adjust the Strafe on the S800G. From a couple of S800G review videos on youtube, it does appear that the S800G’s strafe has a graduated control servo so I can’t really image how else they do it! I guess we’ll just have to find out…

      Jim

  8. Pingback: Reverse Engineering the Propel ExecuHeli IR Protocol | PetaVolt

  9. Federico Pitto

    Hi Jim,

    I’m really grateful for the hard work you did on the protocol and the controller library. It’s really helping me in my attempt to convert my 107 to RF and using the arduino as transmitter to control it.

    My 107 is the C variant (C standing for Camera):
    http://www.symahelicopters.com/Syma-S107C-Channel-RC-Helicopter-with-HD-Camera-p/eh-syma107c.htm

    I can confirm that the A and B bits on the protocol are used to trigger the camera. The A bit triggers the video recording to start/stop, while the B bit triggers the camera to take a snapshot.

    1. Jim Post author

      Hey Federico – you’re absolutely welcome, I’m glad it’s coming in handy for you! I had no idea there was a Camera variant, that is really neat. I’m going to have to pick one up…

      The A & B bit info is really interesting – I had wondered about those for a while. I have a couple similar (not S107G) IR heli’s and “duelling” robots which can shoot little darts or fire IR beams at each other – I had assumed the spare bits would be for something like that.

      I’d love to read more about your IR to RF conversion – let me know if you end up posting anything online.

      Take care,

      Jim

  10. David

    Hi Jim,

    I’ve really enjoyed reading your post! Thank you for decoding this protocol and posting your findings.

    I’m trying a simpler problem that I’m unable to solve. I’d like to measure the resistance of each of the 3 variable resistors in an s107g (board S107T4). I’ve identified the solder points on the board and can measure the resistors with a multimeter. Though I’d like measure this dynamically with an Arduino.

    I could use a voltage divider, though I’d be concerned thatI would inadvertently alter the current flow of the circuit. The resistance of the variable resistors is about 400 Ohm at max. Suggestions? Any advice would be greatly appreciated!

    Best,
    David

    1. Jim Post author

      Hey David,

      You’re absolutely welcome, I’m glad you enjoyed it – I certainly enjoyed writing it.

      That’s a very interesting idea you mentioned – and one that I’ve been thinking of (different application, though!) too. Your comment spurred me on to take a look at one of my S107G controllers to see how the control mechanism works. It’s interesting that on your S107T4 the variable resistors are 400ohm (I think the closest common series variable resistor is 470ohm) – on mine (a S107T2) they are 5Kohm, including the Trim-control pot.

      As for the Arduino-based voltage measurement, using a voltage divider with a high impedance on your “probe” wire should be fine and not cause any interference with the operation of the controller. The key is choosing values that don’t draw too much current from the circuit under test and ensure the voltage being measured by the the Arduino analogue pin is always between 0-5V. There’s a great page on the idea behind this here: http://startingelectronics.com/articles/arduino/measuring-voltage-with-arduino/.

      I measured the voltages that I’m seeing on my controller and the voltage range is very low (between 0-50mV across the V.Rs, and 70-150mV between the +ve pin on the V.R and Ground). This means you don’t really need to worry too much about input protection (the Arduino’s I/O pin max input voltage is 5V) – though I do see a high of 1.5v on the Throttle V.R to Ground when the controller is powered on with the throttle not at “0” (all the way down).

      Another good resource on Arduino voltmeters and voltage divider impedance: http://www.clarenceho.net/blog/articles/2009/05/17/arduino-test-voltmeter

      I’d love to know how you get on!

      Take care,
      Jim

      P.S. I’m not an electrical engineer, so please correct me if you disagree with any of that!

  11. David

    Hi Jim,

    Thank you for your warm response, I am quite appreciative.

    My multimeter isn’t accurate enough to measure tens of millivolt differences across the V.R.s, although my observations had matched what you are describing, namely the high of ~1.5 V on the Throttle V.R to ground when the controller is powered on with the throttle not at 0.

    Without know the voltage difference across the V.R, it seemed ambiguous to choose an appropriate resister for a voltage divider. And using a few hundred Ohm resistor (certainly too low but I didn’t have anything higher on hand) altered the circuit enough to disrupt the operation of the remote.

    If I absolutely needed to measure the voltage accurately, I believe I could use a non-inverting amplifier (see http://en.wikipedia.org/wiki/Operational_amplifier_applications). The infinite input impedance should, I believe, keep the amplifier from draining any current from the controller itself.

    Though, that brings me to my intention. I started this so that I would eventually have a circuit that could read the current user-input control values, but also be able to drive the controller using an arduino. I’m not actually sure how I would do that at all directly at the variable resistor.

    Several crafty engineers (or engineer-types ;-) have show how to send IR commands with an IR transmitter (which can be driven by a computer, using the protocol you describe above). And presumably building an ad-hoc IR sensor and protocol reader could interpret commands from the output of the controller.

    But that sounds…hard. More challenging then I would seem to be. I don’t know. Any ideas?

    By the way, you seem to reference the S107T2/4 schematics. I’ve searched for them online to no avail (Michael Stoops’ page seems to have been taken down.) Would you mind emailing them if you have them?

    Multiple thank yous. I’m enjoying the conversation.

    1. Jim Post author

      Hey David,

      I’m afraid I don’t have any schematics for the heli’s – the closest I could find was from the RC Groups forums, and then only the on-board heli PCB here.

      I don’t know much about Op-Amps, I’m afraid! I’d be interested to see how such an op-amp based Arduino voltmeter would work – let me know if you try it!

      As for your plans, do you want to basically read the output of the controller (so you can presumably control another device with it)? If so, I actually wrote an Arduino library that will do that for you called SymaLib – all you need is an Arduino and an IR sensor like this one: http://www.adafruit.com/products/157. You connect it to the Arduino like in this tutorial: http://learn.adafruit.com/ir-sensor/making-an-intervalometer. Using SymaLib you can read the values of the Throttle, Yaw, Pitch, Trim, and Channel, and do whatever you want with them.

      You can get SymaLib here: http://www.jimhung.co.uk/?p=1138

      I don’t have a library for sending the commands yet, but I have designed an Arduino/Processing sketch that can control Syma S107G-compatible heli’s. If you’d like, I’ll make a post about it and give you the code, etc…

      It can actually control 2 helicopters independently with one controller by alternating the Channel bit in each control packet and sending them really quickly (but you need 2 people at the keyboard). I will confess that the keyboard is a MUCH more awkward way of controlling them though! The circuit for doing this is really simple, just a few resistors and IR LEDs – here’s a photo of the “IR Shield” I made for my controller:

      IR Shield

      You piqued my curiosity into reversing how the handset controls actually work – I’ll let you know how I get on!

      Take care,

      Jim

    1. Jim Post author

      Hey Emil – absolutely, but I’m afraid I don’t have the code handy right now and I haven’t drawn a schematic for the IR diode board (but it is super simple). I’ll put everything together in a blog post for you and publish it ASAP.

      Cheers,

      Jim

  12. Brian

    Jim,

    Great work and thanks for the article.

    Have you started looking at the control board on the helicopter yet? I very curious to know if anyone has yet started to hack it.

    Thanks,

    Brian

    1. Jim Post author

      Hey Sachin – I’m afraid that the IC in the controller has always been unlabeled in all of the controllers I’ve seen (about 7-8 of various generations). I really doubt you’ll be able to get a drop-in replacement – better of finding a replacement controller somewhere (or building one with an Arduino, or something).

  13. Daniel

    Hi Jim,

    thanks for all of this info. I got another IR-controlled helicopter (cheap little thing) some time ago, but of course it uses a different protocol. Still, I wanted to try my hand at figuring it out. It required some help from the good people at Electronics StackExchange, but I’ve gotten the protocol pretty well described now: http://electronics.stackexchange.com/a/94812/34490

    I’m no electronics guy, so your writeup was a great help in getting it all going. Thanks!

  14. Antonis

    Jim
    thank for the excellent work you’ve done here.
    Did you get around to post the arduino/procesicng sketch that controls a 107G compatible heli?

    BR
    Antonis

  15. Joha

    Hi there

    I was wondering if it would be possible to write code for the helicopter to fly a specific route, and not controlling it with a reverse engineered remote?
    What I mean is using the values of the remote and writing a sketch for the Arduino to make the chopper fly by itself automatically following a pre programmed route.

    1. Jim Post author

      Hey Joha,

      If you mean programming a flight plan and using an Arduino to send the commands to the helicopter, sure – but it’s quite tricky! The Arduino-based transmitter I designed (http://www.jimhung.co.uk/?p=1241) would be fine, for this you just need to write the program to send the flight plan control commands to the Arduino. All you need to send the Arduino is which control you want to change (Throttle, Yaw, etc…) and what value to set – you could write it in Python, Processing, whatever you wanted!

      The real problem is that you need feedback as to the position and heading of the helicopter in order to reliably control it – the helicopters are really inconsistent and do all sorts of crazy things like sometimes turn faster in one direction than the other, ascend faster/slower depending on the battery charge, things like that. This means that you can’t just send commands like ‘turn to the right for 2 seconds, then forward for 5 seconds’ because you can’t be sure it will have turned the expected amount every time. Basically the helicopter and Arduino on their own are an Open Loop system (http://en.wikipedia.org/wiki/Open-loop_controller).

      You could try and create a closed-loop feedback controller using some kind of positional measurement – maybe a webcam fed through OpenCV could be used to observe the helicopters position – but you’d have to write the computer vision routines and figure out how to tell which way the helicopter is facing. I bet something like an Xbox Kinect (due to it’s depth sensing ability) could be useful for this too.

      Hope all that makes sense!

      Jim

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>