Sider

lørdag 15. januar 2011

IMU Razor from sparkfun has arrived!

Finally it has arrived!
I placed my order at desember 16 2010, but i guess because of chrismas it takes a month for mail to reach norway.

So you ask, IMU Razor, what are you talking about?
Well, it is actualy just 3 gyros and 3 accelerometers. With a IMU you can messure the orientation in relations to the earths gravity. To do this you use the gyros to messure change in angles and the accelerometer calibrate and to compensate for drifting in the gyros. This will require some farly advanced filtering algorithms.

My original intention was to use this in a tricopter i am building and later i will try to make the scorpion copter from the movie Avatar. Wish me good luck!


Other usfull applications:
- Drones
- 2 Wheel balancing robot
- Game interface

I will be back lather with som example scetches and circuits.

onsdag 12. januar 2011

Spectrum receiver satellite to arduino duemilanove - Finally, it works!!

I'm not sure where I first read about the concept of using the spectrum satellite receivers to read all the DSM2 channel signals through only one pin, but it sure got my interest. I took a great deal of hacking, coding and debugging for me to get it working, but the satisfaction when it finally worked was so enormous that i just had to start a blog;-)


Here i first discribe the quick way to get started and for you more intrested in the details may read on. I also encurrage you to install and run the example of my SatelliteRecive library for easy interpreting the DSM2 protocol. Sorry for the long blog post. Feel free to skip topics.


How to get started:
You need:
  1. Spectrum Transmitter (I used DX6i)
  2. Spectrum Receiver with satellite (I used this receiver and this satellite)
  3. Arduino (Duemilanove)
  4. 10k resistor
  5. Breadboard
  6. Jumper wires
Steps:
  1. Connect the satellite to the receiver.
  2. Bind your transmitter and the receiver.
  3. Pull out the Atmega chip from the arduino and set up the circuit shown below. (The reason for doing this is the usb chip on the arduino board will disrupt the receiver signal).
  4. Transfer the scetch to the arduino.
  5. Disconnect Atmega RX from arduino board
  6. Connect Spectrum receiver satellite:
    1. Ground
    2. 3V3
    3. Signal to RX on the Atmega chip
  7. Open up serial monitor.
  8. Set baud rate to 115200
  9. Start testing transmitter stick inputs.
The circuit when using the running the schetches.
Image developed using Fritzing.
The circuit used when uploading scetches.
Image developed using Fritzing.


















Notice: The only thing you realy have to change in the circuit is where the jumperwire connected to the atmega RX pin is connected. (RX on the arduino board when uploading, and signal on the receiver when running the scetch.


Notice 2: Maping between the atmega pins and the arduino can be found here:
http://www.arduino.cc/en/Hacking/PinMapping


Gathering information

For the talented googlers theres actually some information on the topic available out there (Most useful i found was these):


Reading up on the info I found googling, I learned the following.
The satellite:

  • Uses serial communication with 115200 baudrate.
  • Requires 3.3V powersupply.
  • After the RX and TX are binded together, you may disconnect the satellite and tap the serial signal from one of the wires.
The basics of the protocol:
  • Signal starts with a 2 byte header of 0x03 and 0x01
  • Then the channels follow with 2 byte pr channel
  • Bout the 6 and 7 channel radios transmits 7 channels.(My DX6i just transmits the middle value for channel 7)
Initial Hacking
So the first logic thing to do was connecting the 3 wires(colors may wary) of the satellite to ground, 3.3V and RX pin 0 on my arduino duemilanove. I wrote a little scetch for the arduino to pass on any received serial data to my computer, but i could not seem to get any data. Reading some more i found that the usb chip connected to RX pin 0 pulls this up from 0 to 5+ with a 1k resistor. This might be upsetting the arduino. Some have suggested the use of SoftwareSerial libraries, but not eaven the faster NewSoftwareSerial comes with 115200 baudrate reading. Therefor a lot of people has decided to go fore the larger and more expensive arduino mega witch has adittional hardware serial pins not connected to the usb chip.

Pulling out the chip
After a while i finally overcame my setback and I had an idea i wanted to test out before I backed out buying the arduino mega. What if i disconnect the usb chip after uploading my scetch. I decided to pull out the Atmega chip from the arduino board, so i had full control over the pin connections.
My setup - image developed using Fritzing.
I uploaded the following scetch:
int redLedPin = 13;

int prev;

void setup()  
{
  pinMode(redLedPin, OUTPUT);
  Serial.begin(115200);
}

void loop()
{
  if (Serial.available() > 0) {
    int val = Serial.read();
    if(val == 0x01 && prev == 0x03){
      Serial.println();
    }
    Serial.print(val);
    Serial.print("\t");
    prev = val;
  }
}
When the scerch is uploaded:

  1. Disconnect Atmega RX from arduino board
  2. Connect Spectrum reciver satellite:
    1. Ground
    2. 3V3
    3. Signal to RX on the Atmega chip
  3. Open up serial monitor.
  4. Set baud rate to 115200
  5. Start testing transmitter stick inputs.
AND IT WORKS!!!


The software
Here I present to you some example scetches from the simplest kind to the more complex. And finally the use of my custom library for the DSM2 protocol.

Nr. 1 - A simple test scetch:
int redLedPin = 13;

int prev;

void setup()  
{
  pinMode(redLedPin, OUTPUT);
  Serial.begin(115200);
}

void loop()
{
  if (Serial.available() > 0) {
    int val = Serial.read();
    if(val == 0x01 && prev == 0x03){
      Serial.println();
    }
    Serial.print(val);
    Serial.print("\t");
    prev = val;
  }
}
Nr. 2 - A more complex example for parsing out the different channels.
Running this example and the serial monitor will will give you a better understanding of the protocol.There is a better way of doing this used in the library, maby I wil change this example later. Also you should use the Servo library rather then the analogWhrite to pin 3 when running servos.

const int redLedPin = 13;


int channels[7];
int index = 0;
int prev;

void setup()  
{
  pinMode(redLedPin, OUTPUT);
  Serial.begin(115200);
}

void loop()
{
  if (Serial.available() > 0) {
    int val = Serial.read();
    
    //Detect headers/New data set
    if(val == 0x01 && prev == 0x03){
      Serial.print(channels[0]);
      Serial.print("\t");
      Serial.print(channels[1]);
      Serial.print("\t");
      Serial.print(channels[2]);
      Serial.print("\t");
      Serial.print(channels[3]);
      Serial.print("\t");
      Serial.print(channels[4]);
      Serial.print("\t");
      Serial.print(channels[5]);
      Serial.print("\t");
      Serial.print(channels[6]);
      Serial.println();
      analogWrite(3,map(channels[0],1024,2046,0,179));
      if(channels[5] > 4607) digitalWrite(redLedPin,1);
      else digitalWrite(redLedPin,0);
      
      index = 0;
    }
    else { //Register value to apropriate channel
      
      switch(index){
        case 0:
          channels[0] = val * 256;
          break;
        case 1:
          channels[0] = channels[0] + val;
          break;
        case 2:
          channels[1] = val * 256;
          break;
        case 3:
          channels[1] = channels[1] + val;
          break;
        case 4:
          channels[2] = val * 256;
          break;
        case 5:
          channels[2] = channels[2] + val;
          break;
        case 6:
          channels[3] = val * 256;
          break;
        case 7:
          channels[3] = channels[3] + val;
          break;
        case 8:
          channels[4] = val * 256;
          break;
        case 9:
          channels[4] = channels[4] + val;
          break;
        case 10:
          channels[5] = val * 256;
          break;
        case 11:
          channels[5] = channels[5] + val;
          break;
        case 12:
          channels[6] = val * 256;
          break;
        case 13:
          channels[6] = channels[6] + val;
          break;
        default:
          break;
      }
      
      
      
      prev = val;
      index++;
    }
    
  }
}

Nr. 3 - Using the SatelliteRecive library.
#include <satelliterecive.h>
#include <servo.h>

#define ledPin 13
SatelliteRecive reciver;
Servo myServo;
int time = 0;

void setup(){
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
  myServo.attach(3);
}

void loop()
{
  if (Serial.available() > 0) {
    reciver.regByte(Serial.read());
  }
  /* Will fail after a while. Maby to high baudrate. Could use SoftwareSerial for this dump to pc.
  if(millis() - time > 100){
    Serial.print(reciver.getThro());
    Serial.print("\t");
    Serial.print(reciver.getAile());
    Serial.print("\t");
    Serial.print(reciver.getElev());
    Serial.print("\t");
    Serial.print(reciver.getRudd());
    Serial.print("\t");
    Serial.print(reciver.getGear());
    Serial.print("\t");
    Serial.print(reciver.getFlap());
    Serial.println();
  
    time = millis();
  }*/
  
  
  myServo.write(map(reciver.getAile(),RXMIN,RXMAX,0,179));
  
  if(reciver.getGear() > RXCENTER) digitalWrite(ledPin,1);
  else digitalWrite(ledPin,0);
  
}

The Protocol
The protocol transmitts data in frames of 16 bytes. The first 2 bytes are header bytes used for syncing the communication. Then the channels are transmitted one by one. Where one channel consist of two bytes.


[Header][Aileron][Flaps][Elevator][Rudder][Throttle][Gear][Ch7]



(The channel order might change depending on 6 vs 7 channel transmitter and Mode 1 vs Mode 2 Stick setup on the transmitter, use serial monitor to find the right order of the channels)


Header
always consist of
byte 0x03 followed by 0x01.


Aileron
Range: 1024 - 2046
Center: 1535


Flap
Range: 5120 - 6142
Center: 5631


Elevator
Range: 2048 - 3070
Center: 3582


Rudder
Range: 3072 - 4094
Center: 3582


Throttle
Range: 0 - 1022
Center: 511


Gear
Range: 4096 - 5118
Center: 4607 (Theoretic)


Channel 7
Range: 6144 - 7166
Center: 6144


NOTICE: You will normaly newer reach the endpoints of the ranges. For example the throttle channel will normaly go from aproximately 150 to 850. The rest of the range is avilable for trim and travel adjustment. Setting the traveladjustment to 125% and subtrim all the way in one direction will let jet you reache the end points.


The SatelliteRecive library
The SatelliteReceive library makes it easier for you to translate the data from the receiver.
It consists of 7 public methods:


regByte(int byte) - Must be called for each byte received from the receiver.


And one method for each of the 6 channels (Does not support the 7. channel at this point)
getThro()
getAile()
getElev()
getRudd()
getGear()
getFlap()
All thease methods returns a value between 0 - 1022 where 511 is the center position of the channel.


It also includes the usefull constants:
RXMIN - lowes possible value.
RXMAX - Highest possible value.
RXCENTER - Channel center value.


Please check out the example to understand how to make use of the library.


Install:

  1. Download the library here.
  2. Unzip the library to the folder "[PATH TO ARDUINO IDE]/libraries/"
  3. Restart the arduino IDE
  4. Go to File -> examples -> SpectrumRC -> SerialChannelMonitor and test the example.
  5. You should be able to turn on and of a led connected to digital pin 13 with the gear switch and control a servo connected to digital pin 3 with the aileron stick.