Syma 107G Controller Library

After my work on the Syma 107G was featured on Hackaday, [Maksim] emailed me to talk about writing up a programming library for the Syma 107 control protocol that would allow someone to control an RC boat, car, etc… with the S107T2 controller. I thought this was a cool idea, so I gave it a shot — here’s the lowdown on SymaLib.
SymaLib_example

Download & Requirements

Get the SymaLib library (v0.1) here. The library was written for the Arduino IDE v1.1 and is designed for use with a sketch similar to Adafruit’s IR Commander sketch (reference, github).

Details

I started with the excellent Adafruit Industries IR Commander sketch as it is easy to understand and takes care of populating an array with the on/off pulse lengths for me. With this raw material, all the SymaLib library has to take care of is parse the received pulse lengths into their respective bit-wise values and provide a series of methods to get the parsed values of the handset’s controls.

Version 0.1 currently allows you to parse the 32-bit control packets from the S107T2 controller (described in my protocol spec: here) and return each control value as an integer.

Example

/*
SymaLib Library Example v0.1 by Jim Hung (www.jimhung.com)

 This example code is designed to demonstrate the usage of the SymaLib
 to decode control signals from a S107T2 RC helicopter controller.

 Based on 'Raw IR commander' by Ladyada:

   "This sketch/program uses the Arduno and a PNA4602 to
   decode IR received.  It then attempts to match it to a previously
   recorded IR signal

   Code is public domain, check out www.ladyada.net and adafruit.com
   for more tutorials!"
*/

#include  // include the SymaLib library

#define IRpin_PIN      PIND
#define IRpin          2

#define MAXPULSE 2000
#define NUMPULSES 50

#define RESOLUTION 20
#define FUZZINESS 30

uint16_t pulses[NUMPULSES][2];  // pair is high and low pulse
uint8_t currentpulse = 0; // index for pulses we're storing

SymaLib protocolparser; // declare our SymaLib object

void setup(void) {

  Serial.begin(9600);
  Serial.println("Ready to decode IR!");
}

void loop(void) {

  int numberpulses;
  String ctrldata = "";

  // Listen for IR signals and populate the array of pulse lengths

  numberpulses = listenForIR();

  // Give the SymaLib object the pulse array to parse. If it's a valid Syma107
  // control packet, SymaLib returns boolean True.

  boolean result = protocolparser.setPulseListParse(pulses,numberpulses,RESOLUTION,FUZZINESS);

  if (result) {

	// Read the controller values and do whatever you need to with them.

	  // This example prints out the integer values for each control:

    Serial.print(" Yaw: ");
    Serial.print(protocolparser.getYawDec());
    Serial.print("\tPitch: ");
    Serial.print(protocolparser.getPitchDec());
    Serial.print("\tChannel: ");
    Serial.print(protocolparser.getChanDec());
    Serial.print("\tThrottle: ");
    Serial.print(protocolparser.getThrottleDec());
    Serial.print("\tTrim: ");
    Serial.print(protocolparser.getTrimDec());
    Serial.print("\n");

	  // This example prints out the binary values for the 32-bit control packet:

    Serial.println(protocolparser.getCtrlPacketBin());

  }
  delay(100);
}

int listenForIR(void) {
  currentpulse = 0;

  while (1) {
    uint16_t highpulse, lowpulse;
    highpulse = lowpulse = 0;

    while (IRpin_PIN & _BV(IRpin)) {

       highpulse++;
       delayMicroseconds(RESOLUTION);

       if (((highpulse >= MAXPULSE) && (currentpulse != 0))|| currentpulse == NUMPULSES) {
         return currentpulse;
       }
    }

    pulses[currentpulse][0] = highpulse;

    while (! (IRpin_PIN & _BV(IRpin))) {

       lowpulse++;
       delayMicroseconds(RESOLUTION);

        if (((lowpulse >= MAXPULSE)  && (currentpulse != 0))|| currentpulse == NUMPULSES) {
         return currentpulse;
       }
    }
    pulses[currentpulse][1] = lowpulse;

    currentpulse++;
  }
}

Library Reference

Here are the methods provided by the SymaLib library:

SymaLib()

Constructor. No arguments — initializes control byte array.

setPulseListParse()

Returns: Boolean

Arguments:

uint16_t pulses[][2] — The pulse array populated by the ‘listenForIR’-like method.

int& numpulses — The number of pulses heard by the ‘listenForIR’-like method.

int resolution — The RESOLUTION constant used to calibrate the IR listener.

int fuzziness — The FUZZINESS constant used to calibrate the IR listener.

Description:

This method parses the pulse-array and stores it as an array of integers, either 1 or 0. This array is the basis of the object’s Get methods.

getYawDec()

Returns: Int

Arguments: None.

Description:

Returns an integer of the decimal value of the Yaw control.

getPitchDec()

Returns: Int

Arguments: None.

Description:

Returns an integer of the decimal value of the Pitch control.

getChanDec()

Returns: Int

Arguments: None.

Description:

Returns an integer of the decimal value of the channel switch.

getThrottleDec()

Returns: Int

Arguments: None.

Description:

Returns an integer of the decimal value of the Throttle control.

getTrimDec()

Returns: Int

Arguments: None.

Description:

Returns an integer of the decimal value of the Trim control.

getCtrlPacketBin()

Returns: String

Arguments: None.

Description:

Returns a String of ‘1’ and ‘0’s representing the 32-bit control packet. Useful for debugging.

Conclusion

This is the first Arduino library I’ve ever written (hopefully not the last!) and I hope it is useful for other hackers. [Maksim]‘s idea was cool and I’d love to see any projects that end up using it. Let me know in the comments!

Take care,

Jim

One Comment

  • Hello Jim

    It is possible to see your arduino code with smooth equelizer — this from YT ?

    Greetings

    Max

Leave a Reply

Your email is never shared.Required fields are marked *