Magnometer calibration

All of our smartphones have an integrated compass. It can be very useful when you are looking for in which direction you should start heading while walking. However, you have probably noticed that sometimes, the direction showed by our phones can be quite...wrong! It happens when the compass has not been calibrated correctly. But if you try to turn the compass around in every direction, you'll probably notice that the direction arrow finally takes the right direction. Why? Because the smartphone is doing a "live" calibration as you move the compass.

What you should keep from this introduction is that compass calibration is fundamental ! Don't intend on using a magnetic sensor in your project unless you have it calibrated. Otherwise, the data you'll be using will probably be inaccurate, if not completely random 😀

Back to basics
What does a magnetometer do?

"Well, it obviously gives you your heading!"

"NOPE! (Chuck Testa)"

The magnetometer gives you a three dimensional vector of the magnetic field it senses. This magnetic field is a combination of both the earth's field and of the magnetic field created by all the surrounding objects. And this second magnetic field is far from being negligible,  especially in our hobbyist projects where there's electronics (and motors) all around.

Theoretically, the measured magnetic field should :

  •  be centered around 0
  • always have the same strength

If we could represent it in 3D, it should basically look like a perfect sphere centered in 0.

In reality :

  • it is not centered around 0, because of the presence of other magnetic fields around the sensors(such as other magnets, electric wires) : it is hard iron distortion.
  • it does not have a constant strength, because of the presence of other ferromagnetic materials around the sensors, which skew the magnetic field. This is soft iron distortion.

What we get is essentially a potato-shaped magnetic field (because of soft iron distortion), that is not even centered (because of hard iron distortion).

Calibration techniques
Hard Iron distortion

Hard iron errors introduce an offset in the magnetometer data

\mathbf(Field_{magnetomer} =Field_{earth} +Field_{hard iron})

 

To get this offset is pretty simple : we keep track of the maximum and minimum values the magnetometer outputs on each axis while moving it in space. From what we know the maximum and minimum should be centered around 0, so we get the offset by :

 x_{offset} = \frac{x_{min} + x_{max}}{2}

We can then subtract the measured offset from each raw measurement in order to get  hard iron free data.

Soft Iron distortion

Here, the work consist in transforming a potato in an orange. Or, transforming an ellipsoid into a sphere, if you prefer. It's actually easier than it sounds. There are  obviously mathematical formulas that involve matrices but let's keep it simple here.

Let's say earth magnetic field's value is F. It is the norm of the vector given by the magnetometer. While we've seen it should be the same on the three axes, experience shows it's not. So let's assume we have measured the maximum magnetic field Fx for the x axis,Fy for the y axis, Fz for the z axis.

We then calculate the average field value F by :

 F = \frac{F_x+F_y+F_z}{3}

Let's assume that F = 1. If F_x = 0.8, it means that F_x is only 80% of the average field value. Hence the potato. Now if we simply multiply all the incoming x values by F/F_x, the potato effect, will be gone, as we expand the range of the x values so that it is no longer 80% of what it should be, but 100%.

Scale_x = \frac{F}{F_x}

Final equation

If we no combine the two equations and use vectors, we get:

\mathbf(Field_{corrected} = Scale * (Field_{raw} - Offsets) )

Scale transforms the potato into an orange(soft iron distortion) and the Offsets vector brings it back in the center(hard iron).

Calibration process

The calibration consist in getting the min/max values of x/y/z fields, and then calculations the offsets and scale factors. The more you move the magnetometer in all directions, the more efficient your calibration will be.

Using calibration data

// We get the raw values here  in mx,my,mz

//(this is pseudo code)

mag.getHeading();

// Now we apply the calibration data

mx = (int)((scale_x)*(mx-x_offset));
my = (int)((scale_y)*(my-y_offset));
mz = (int)((scale_y)*(mz-z_offset));

Results

Using Processing and  a slightly modified version of this program, I was able to quickly draw the 3D representation of the magnetic field. The video shows the before/after.

 

As you can see, hard irons distortion was HUGE before calibration. I could never have gotten reliable readings without correcting them. Soft iron errors were also present, and completely removed by the calibration. 🙂

 

 

 

 

 

PiWeather part 4 : first PCBs

Hello again, dear readers!

I don't have so much time to give to this project, but PiWeather is still moving forward!

The first prototype only had a DS18B20 temperature sensor, and was working on a breadboard, so the next logical step was to design and realize a first PCB for the project. I also moved from the DS18B20 to the DHT22 sensor because it gives both temperature and humidity, and is pretty accurate. I added to that a pressure sensor : the BMP085, sometimes referred to as GY 65 on eBay! This would give my sensor unit the ability to read pressure, temperature and humidity.  That's a good start !

I used EAGLE to design the schematics and the PCB :


PiWeather 0.1 schematics under EAGLE.
PiWeather 0.1 schematics under EAGLE.
The first PCB design.
The first PCB design.

We made the PCB ourselves like we did for our old quadcopter flight controller shield. It is pretty hard to get good results with homemade PCBs, and the tracks have to be very big if you want to be sure there won't be any problems. We got a working PCB on which we soldered the components, and it succesfully worked, powered by two AA cells!

Yep. It is definitely homemade.
Yep. It is definitely homemade.
Isn't it beautiful ? ;)
Isn't it beautiful ? 😉
On this top view, you can see we accidently took a 2 layer plate for our PCB. So we had to remove the copper with a sander :D
On this top view, you can see we accidently took a 2 layer plate for our PCB. So we had to remove the copper with a sander 😀

 

I am pretty happy with this PCB as it works great, but it obviously has drawbacks:

  • PCB making is the worst. It never works as you want, there always is a problem, some tracks are too thin, some are too thick, you have to carefully check for possible shorts...
  • There is no protection against oxydation. Of course you can by some sprays for that, but I don't know if that would work great for an outdoor sensor.
  • The minimum track width is too big to make something small and reliable
  • It's very, very ugly 😀

So I started to look for inexpensive solutions for my PCB to get produced in a "professional" way. And I found exactly what I wanted on Seeedstudio.com .They offer a very cheap PCB service starting at 9.99$ for 5 PCBs of max 5cm x 5cm. Perfect!

Seeedstudio provides you design rule files for EAGLE, so you can see directly if your design will respect their process. I designed a new 2 layer PCB that Seedstudio produced and sent to me in a few days.

The 2 layer PCB for PiWeather v0.2
The 2 layer PCB for PiWeather v0.2

 

I was blown away by the quality of the boards 😀

Here are the two sides of the v0.2
Here are the two sides of the v0.2
It just looks perfect. Nothing more to say.
It just looks perfect. Nothing more to say.
A board ready to be soldered :)
A board ready to be soldered 🙂

 

The v0.2 finally took life and is ready for duty !

In red: the NCP1402 regulator In blue : GY65 barometer White: DHT22 Black: nrf24L01+ The Atmega328p proudly stands in the middle :)
In red: the NCP1402 regulator
In blue : GY65 barometer
White: DHT22
Black: nrf24L01+
The Atmega328p proudly stands in the middle 🙂

v0.2

 

In the next weeks we'll try to build the first outdoor sensor, which will be solar powered. Then we'll probably deploy the website hosting the data gathered by the numerous PiWeather stations 😀

Cheers 🙂

 

Update 25/10/14 : The schematics are on github : https://github.com/psykhi/PiWeatherEAGLE

I also created a Raspberry Pi shield in order to plug the nRF24L01+ 🙂

I will write an article about it!

PiWeather, part 3: low power design of the first prototype

In this third article about the PiWeather project, I will present a few techniques I used to design the first PiWeather prototype.

The first sensor unit prototype.
The first sensor unit prototype.

When I tried to write down for the first time the "specifications" of my sensor units, I thought that getting to more than one year of battery life would be satisfying. But I really didn't have any idea if I could reach this goal with an Arduino. It turns out you can. And, depending on your project obviously, you can reach very, very long battery lives with a regular Atmega328p used on a regular Arduino UNO.Let's go through a case study here, with a 220 mAh CRC2032 battery. It delivers 3V but let's pretend here it can deliver 5V for the sake of simplicity.

Get rid of the Arduino board.

This decision is a no brainer. There is no way to make something low powered when using the Arduino board. It's actually quite logical when you think about it. It packs many more things than the 328p itself, like an FTDI chip, 3.3 and 5V regulators.

A program running on a regular Arduino UNO board will draw about 55mA, which is a LOT .The CR2032 battery will live 4 hours.

Now remove the 328p from the UNO board, put it on a breadboard with a 16 MHz quart and a, 5V power supply. You get down to 11mA. Now the battery will last 5 times longer, so 20 hours.  Only 20?!

Does your application need to run at 16MHz@5V ?

If you' re working on a low power project, what you want is to only monitor some values, and take simple actions from the data you read. My sensor units only need to read what the sensors tell them, and send these data back to the Pi. There is absolutely no need for performance, therefore no need to run at 16MHz.

A side effect of lowering operating frequency, is that you can also lower the AtMega328 voltage. Indeed, it requires 4.2V to safely operate at 16MHz. At 8MHz, you only need to give it more 2.4V. Which means you could use a single cell battery such as a CR2032, or two AA/AAA batteries.

The difference between running at 16MHz@5V and 8MHz@3V is huge : power consumption drops from 11mA to roughly 3-4mA! Another very big save. Another advantage of running the ATMega at 8MHz is that you can use its internal oscillator, thus eliminating the need for a crystal(or resonator). That's why I chose the 8MHz frequency for this project.

Save power with good software

The software part is as important as the hardware part, when trying to reach lowest consumptions. Indeed, the ATMega328 has different sleep modes that can theoretically reduce its power draw to barely 100nA!

When used in the "default" mode, the Arduino will just endlessly run through the loop function, event if there is nothing to do. This will draw around 4mA running 8MHz@3V. This barely gives us a battery life of 56 hours with a CR2032 cell.

Use interrupts

The ATMega328 can be put into different sleep modes. The "highest" sleep mode basically turns off the Arduino. The only to wake it up is then to trigger an interrupt (that you will have previously registered in your setup() function !). A possible source of interrupt is the change of state on one of the Arduino's pins. Another  way of triggering an interrupt is to use a timer. Timers can generate an interrupt periodically to trigger an action. The maximum sleeping time you can achieve with the Arduino is unfortunately pretty low : 8 seconds. This means that if you want, like me, to sleep for minutes between every action, you'll have to keep track of a counter to reach the desired sleeping time. I found the Low-Power library to be pretty useful. It keeps away the ugly register assigning code and makes sleeping a breeze 🙂

The results

My code is pretty simple. Sleep 800 seconds (around 13 minutes), wake up,acquire and send the sensors data (a few seconds), and go back to sleep for 800 seconds. The average power draw while sleeping is 6 µA, due to the watchdog timer of the Arduino. The few milliamps drawn at wake up can be ignored since they represent less than 0.5% off the total time, which gives us approximately 225/0.006=1562.5 days of battery life. This is much better. If you don't need the timers and can get external interrupts to wake up your device, you can achieve a lifetime that will essentially be your battery life time!

Sleeping with the watchdog timer on draws 6 µA, more than 9000 times less than using the Arduino Un board!
Sleeping with the watchdog timer on draws 6 µA, more than 9000 times less than using the Arduino Un board!

First prototype

The first sensor unit prototype is very simple. A DS18B20 temperature sensor, an ATMega328p and a nF24L01+ for RF communication. The power is given by a CR2032 battery.
First prototype

One of the flaws of this design is the minimum voltage required by the DS18B20. It theoretically is 3V. The CR2032 voltage is 3V when new, but slowly goes down until around 2.8V (then it's pretty much flat). It turns out the DS18B20 behave completely normally, even at 2.8V, but powering a sensor outside its recommended operating voltage range is probably never a good thing.The second prototype, which I'll present in a future article, fixed this 🙂

That's it for this short introduction to low power design for Arduino. If you want to know everything about Arduino and low-power, read Nick Gammon's great posts here 🙂

PiWeather : How to communicate wirelessly between an Arduino and a Raspberry Pi

If you wonder what PiWeather is, check out the first article I wrote !

Raspberry Pi FTW !
Raspberry Pi FTW !

One of the key part of this project is to first determinate what technology to use to transmit the data and second how to encode the data to send. What I wanted was:

  • Reliability
  • Low power design
  • Good range (enough to cover a small house)
  • Ease of use
  • Something cheap
  • Something that could work simply on the Arduino and Raspberry Pi side

RF chip

A standard 433 MHz RX/TX couple

My first choice was spontaneously to pick 433MHz RX and TX as they are incredibly cheap and can reach a pretty long range if you associate them with the right antennas. The problem with these is that the very low-level side of the transmission. If you put the TX pin high, the RX pin will go high too, and that's it. You really have to do all the encoding by yourself, and if you want it to be really reliable, you must provide a way to ensure all your data were transmitted correctly (like a CRC).  I first thought I would have to cope with this and handle all this low-level part by myself on both the Pi and Arduino's sides, when I stumbled upon the one RF chip I needed: the 2.4GHz nRFL24L01+.

nRF24L01+
The nRF24L01+ used on my first prototype.

The nRF24L01+ was exactly what I needed: cheap, low power, easily connected to a Pi or an Arduino through SPI, built-in CRC, both RX and TX at the same time, multi pipe, and more!

It also is really easy to use through SPI: just give it the bytes you want to send (up to 32), and send it to the address of your choice. The same thing goes for the RX mode, it can even generate an IRQ when a message has come!

I used the library from Stanly Seow on both Arduino and Raspberry's side, and it works pretty good! One flaw of the Pi's implementation is that it doesn't use interrupts generated by the nRFL2401+, so it kind of stalls the Pi polling the chip. I modified it a bit to use interrupts from the great WiringPi library, allowing my program to sleep 99.9% of the time. I will get into these details in an other post, stay tuned 😉

Okay, so I know how data will go from my sensor units to the Pi. But what am I going to send?

Messages

So far, I've thought about sending the following data to the Pi from the sensor units:

  • Temperature
  • Pressure
  • Humidity
  • Wind speed
  • Wind direction
  • Rain metrics
  • Unit battery level, to detect low voltage

Also, my units needed some kind of address or unique ID so the Pi could easily recognize them, so I added an ID in the list of things I could possibly send. I could have decided of my own encoding format, but what if I change in the future the things I send and in which order, etc? You can see now that encoding the data in a forward compatible way is really not that simple!

I actually never thought about encoding myself the data 😀 It was just to show you that it is definitely not a piece of cake. I knew exactly what I needed to use : Google Protocol Buffers

From the Google website , "Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler". You can find libraries to use them in almost any available language, from a micro controller with 2kB of RAM running C code, to a server running PHP or Python.

So how does it work?

You first describe the messages you want to send in a file having the .proto extension:

message SensorData{
 required int32 id=1;
 optional bool binding= 2;
 optional float temperature = 3;
 optional int32 battery_level = 4;
 optional float pressure = 5;
 optional float humidity = 6;
 optional int32 type = 7;
 }

message is the keyword required to start defining a message. Then it looks a bit like a mix of a C structure and enum declaration. You define your fields and attribute them a unique ID (ex : the field temperature has the ID 3), and then add if your field is optional or required in the message. In this case, each of my sensor units will have to send its ID to the Pi during a transaction so the Pi know who it is talking to, but some sensors will retrieve temperatures, some wind speed, some pressure, so I made all the other fields optionals.
If I want in the future, to add a new data to my message SensorData, such as windspeed, I can just modify my the proto file like so:

message SensorData{
 required int32 id=1;
 optional bool binding= 2;
 optional float temperature = 3;
 optional int32 battery_level = 4;
 optional float pressure = 5;
 optional float humidity = 6;
 optional int32 type = 7;
 optional float wind_speed = 8;
 }

And you know what the great part about this is? It will be backward compatible with the existing sensor units using the "old" messages! So no need to re-flash the existing sensor units if I had optional fields in my messages, which is a very, very nice thing 🙂 I won't get more into details for GPB here, their website has tons of examples of how to use them!

To actually use these messages, you need to translate them into the language you are using. I chose to use NanoPb, which is a very good implementation of protocol buffers for embedded systems. It has a tiny footprint (less than 2kB!) and generates all the code you need to include in your project, so no need to link against a lib, which is always good news 😉

NanoPb takes the proto file and creates the associated C structures, encoding/decoding functions for my messages. The generated structure looks like this:


typedef struct _SensorData {
 int32_t id;
 bool has_binding;
 bool binding;
 bool has_temperature;
 float temperature;
 bool has_battery_level;
 int32_t battery_level;
 bool has_pressure;
 float pressure;
 bool has_humidity;
 float humidity;
 bool has_type;
 int32_t type;
} SensorData;

Let's say my sensor unit has both a temperature sensor, and a humidity sensor. If I want to send the data to the Pi, I can do like so:

 SensorData message;
 uint8_t sensorDataBuffer[32];/*Maximum size you can send with the nRF24L01*/
 pb_ostream_t stream;

 message->has_temperature=true;
 message->temperature=sensor.temp();
 message->has_humidity=true;
 message->humidity=sensor.humidity();
 message->id=42; /*The unit ID*/

/*Let's encode this with nanopb*/

 stream = pb_ostream_from_buffer(sensorDataBuffer, sizeof(sensorDataBuffer));
 pb_encode(&stream, SensorData_fields, message);

/*Now our encoded data is in the sensorDataBuffer, ready to be sent ! */
 nRF24.send(sensorDataBuffer);

It's as simple as that, and very powerful. I think protocol buffers are really the right way to go for size constrained embedded applications such as this one. But don't think they are only used for small applications, they can be so powerful that they are wildly used in different industries to send big loads of data, through nested messages for example 😉

So that's it, I introduced you the chip I use to make the communications, and the format I adopted for the messages my sensors send wirelessly. I think I will go back on this in a coming article where I will define exactly how the software I developed works.

Cheers 🙂

PiWeather weather station : introduction

The weather station project (codename : PiWeather)

It's been quite a while we haven't posted anything here, but it doesn't mean we're not working on cool things !

A few months ago, I thought it would be cool and useful if I could monitor temperatures inside and outside of my apartment. This way I could know when to open the windows or close them in summer when it gets warmer outside than inside, and the other way around. Then I figured that I might as well add other data, such as pressure, humidity, maybe wind speed and others if I gather the time and the energy to go through with my project, which I admit, rarely happens 😀

Anyway, things are now moving with the project so now is the time to write here. The idea for this first article is to introduce briefly what I will do and how I am planning to do it. I will update this article in the future with links to the latest articles I post about the PiWeather project.

Architecture

The PiWeather main architecture
The PiWeather main architecture

As you probably guessed from the project's codename, the central unit is a Raspberry Pi. The Pi itself does not host any sensor. It will instead be connected wirelessly to them, or more precisely, to what I will call from now on “sensor units”. These sensor units will be Arduino based (what a surprise!) sensor platforms. I mean by this that a sensor unit can host more than one sensor on board, like both a pressure sensor and a temperature sensor for example.

Goals

My goals are :

  • No wires : While the Pi will be connected both to a power source and through Ethernet, the sensor units must be wireless.
  • Plug and play sensors. Just put a battery inside a sensor unit, and you're done. No complicated setup on the computer, through switches, nor command lines.
  •  Longest possible battery life for the sensor units. If you have to change batteries every other week, then being wireless has in fact no point.
  •  Web interface to monitor and access all the logged data
  •  Use cheap parts

There are probably tons and tons of similar projects on the Internet, and I don't really care. The point is as always to have fun, learn, design, and do something useful...Okay, it's not always useful 🙂

Technical topics

On a technical side, the topics I will try to approach during this long journey are:

  • The sensors I used or plan to use
  • Low power Arduino design
  • Arduino development in Eclipse
  • Raspberry Pi program cross compilation
  • Communicate wirelessly between an Arduino and a raspberry Pi
  • Google protocol buffers
  • Symfony 2 PHP framework
  • Create a daemon for Linux
  • Interrupts on Raspberry Pi
  • PCB design
  • Case design (if I make to this stage obviously :D)
  • Twitter Bootstrap
  • Javascript
  • jQuery
  • mySQL
  • phpmyadmin

This list is not exhaustive, but it shows that this project approaches a very broad range of domains and languages .

The articles won't be a series of tutorials. Nothing I will do is new, I will instead focus more on how  all of these things work together, and how the design evolves through time.

And this ends this introduction post 🙂

Follow our RSS feed if you want to hear more about the PiWeather project !

Animal motion detection : an Arduino project for photography

Hungry (angry?) pigeon
A real angry bird.

I'm going to talk to you about a simple, yet fun project I did last year : an animal detection device that could control my DSLR and take pictures.

I thought that it would be a fairly simple thing to do with Arduino and a motion sensor. I chose to use an IR sensor because they are very cheap and efficient, and bought the PIR sensor from parallax. It just has a single bit output, so it's super simple to use with an Arduino. It is very sensitive and fits well this application. The only bad thing about it is that it has an incorporated LED that turns red every time a motion is detected, which is probably useful for most use cases, but not in my situation 😀 I just cut the circuit track leading to the LED so it wouldn't turn red anymore.

Motion detection on Arduino
The motion sensor and its 3 pins : The one bit output, VCC, and GND.

Once we have the information about whether  a living thing is in front of the sensor or not, we need to control the camera to trigger it. This part really depends on what kind of camera you own, if it can accept a remote control or not. If it doesn't, one way to trigger it is to use a servo motor to press the shutter button (with the Arduino Servo library), but the problem might be the noise it generates when moving, which could scare the animals. My DSLR ( a  Canon 550D) has a jack input for remote control which makes it really easy to command. What you will need is a standard 2.5mm stereo male jack, some wires and that's it!

Canon Remote Controller Wiring (2.5mm mini-plug and N3 plug)

You just need to solder the 3 wires to the jack connector. One for the ground, one for the focus command, and one for the trigger command. To focus, just put the focus contact to the ground; and it works the same way to take a picture.

So how to control the camera with an Arduino?

We will use two digital ports of the Arduino to control trigger and focus of the camera. When these outputs will be set LOW, they will fire the action they are supposed to create (focus or trigger). When set HIGH, nothing will happen. To protect the camera, you should put a resistor between the outputs and the camera (I used 2.2K resistor) just to make sure no current goes into the DSLR.

The final schematics look like this:

The very simple schematics of the breadboard circuit. The LED is simply there to control if everything is working (on when something is detected). You can click for the full size image.
The very simple schematics of the breadboard circuit. The LED is simply there to control if everything is working (on when something is detected). You can click for the full size image.
Motion detection on Arduino
The real life schematics 🙂

The program will be pretty simple too : if something is detected, take a picture and turn on the control LED 🙂

Here it is:


#include <Camera.h> // The Camera library makes it easier to control a DSLR

/********PINS*********/

int PIR_Pin = 3; //the digital pin connected to the PIR sensor's output
int LED_Pin = 2;
int focusPin=6;
int shutterPin=7;

/********VARIABLES****/

int idletime =0; // The time since last picture
int lastshot=0; // The millis() when the last picture was taken
int burstInterval=5000; //The time between pictures when motion is on
int calibrationTime = 30; // The sensor calibration time (so we don't get false positives when we start the Arduino up)
long unsigned int lowIn;//the time when the sensor outputs a low impulse
long unsigned int pause = 2000;// The time necessary for the motion to be gone after the sensor has gone to a LOW state
boolean lockLow = true; // goes to false when a motion is detected
boolean takeLowTime;
boolean burst=false;// burst mode indicator
Camera* eos; // a pointer to our DSLR

void setup()
{
 eos =new Camera(focusPin,shutterPin);
 Serial.begin(9600);
 pinMode(PIR_Pin, INPUT);
 pinMode(LED_Pin, OUTPUT);
 digitalWrite(PIR_Pin, LOW);

 //Sensor calibration
 Serial.print("Calibrating sensor ");
 for(int i = 0; i < calibrationTime; i++){
 Serial.print(".");
 delay(1000);
 }
 Serial.println("SENSOR READY");
 delay(50);
}

void loop()
{

 if(digitalRead(PIR_Pin) == HIGH){ //If a motion is detected
 if(idletime>30000){ // If the camera is in sleep mode
 (*eos).TriggerFocus(); // wake up the camera
 idletime=0;
 }

 digitalWrite(LED_Pin, HIGH); //signal that a motion is detected
 if (burst){ //Once the motion has been detected and a picture taken, we go into this mode to keep taking pictures every 5s until the motion ends
 delay (burstInterval);
 (*eos).TriggerShutter();
 lastshot=millis();
 idletime=0;
 }
 if(lockLow){
 lockLow = false;// We enter in "motion" mode
 (*eos).TriggerShutter();// We take a picture right away
 delay(1000);
 (*eos).TriggerShutter();// We take a second picture 1s later
 delay(2000);
 lastshot=millis();
 idletime=0;
 burst=true; //Now we go in burst mode,ie picture will be taken every 5S
 }
 takeLowTime = true;
 }
 if(digitalRead(PIR_Pin) == LOW){ //If mothing is detected
 digitalWrite(LED_Pin, LOW); //Turn off the LED
 if(takeLowTime){
 lowIn = millis(); //save the time of the transition from high to LOW
 takeLowTime = false; //make sure this is only done at the start of a LOW phase
 }
 idletime=millis()-lastshot;
 burst=false;

 if(!lockLow && millis() - lowIn > pause){ // If there has been more than 2000ms inactivity, we exit the motion mode
 lockLow = true;
 }
 }

}

The Camera library is included in the project. It is a very simple library that avoids you to code the boring stuff (like setting LOW the trigger output, then HIGH again etc 🙂 )

To host the electronics and the camera, I built a wooden box big enough to put everything in easily, with a lid so It could be weather resistant. Here are the pictures

Motion detection on Arduino
You can see the PIR sensor, and a layer of tape around it. The goal is to make its FOV a bit narrower, so it only fires when the animal is in the camera frame.
Motion detection on Arduino
I used an old remote control from a broken RC helicopter (RIP 🙁 ) to power the Arduino. You can obviously put anything you want in here ( staying in the 7-12V range is recommended )
Motion detection on Arduino
Top view of this masterpiece of engineering.
Motion detection on Arduino
The camera is held here with its tripod mounting hole. You can also see the stereo jack.
Motion detection on Arduino
The lid. The foam layer is there to protect from the rain.
Motion detection on Arduino
The whole thing, with the 550D and the Sigma 10-20mm. The bungee cords can be used to set the device in a tree.

This is obviously far from being perfect, the DSLR shutter noise scaring most of the animals away after the first picture, and the size and weight of this thing making it hard to place anywhere you'd want 😀

On the other hand, it does work pretty well and can take some fun pictures.

Cat eating a pizza

Hungry birds.

Hope this can give little help to those of you looking for ways to photograph animals 🙂

Flashing a Turnigy 9x with an Arduino

Don't you think those programmable transmitters are really expensive ? Well here is one solution to this problem : If you already have an Arduino, some wire, a soldering iron and a litle bit of dexterity, you can have a complete, highly customizable transmitter !

Indeed, some awesome guys made new firmwares for the "well known" Turnigy 9x (a low cost 9 channels transmitter, about $60). Even better, those projects are opensource and free. What else ? Ok lets start this little hack.

Turnigy 9x

There are numerous projects (TH9X, ER9X, GRUVIN9X, ERSKY9X,..) and the choice is up to you. I personnaly used Open9X because it seems to be the better easy-to-use/fonctiunalities ratio. But before talking about software, lets discuss the hardware. The problem is, how to send the new firmware to the radio ? Actually this is where you'll need to solder a little. It can be pretty scary, but it's not that hard if you have a good iron ;-).

Lets add a programming port to your 9X !

[important]If you purchased a "9XR" version, there is no need to to this hack since it's already done in factory ![/important]

The Freshly bought Turnigy 9X

Ok you said goodbye to your beloved radio ? Let's unscrew it ! Note that on mine the screws were really hard to unscrew, and I had unfortunately to destroy one of them. Once i'ts open, you'll first be like "WTF am I doing?". Actually, it's pretty simple. First thing you have to do is disconnect the connector that goes from the front part to the back part. After this you'll be able to separate them. On the front part, locate a "big" chip. It's the heart of this radio, the ATMEGA64. Pretty simple stuff, actually. It will be easy to reflash thanks to the AVR isp (In-System Programming) protocole. You'll just have to add the wire to be able to use that protocole.

Atmega64, heart of the system

You'll need 6 wires for the isp protocole :

  1. MISO (Master In Slave Out) known as PDO (Program Data Out) on the chip
  2. Vcc (5v)
  3. SCK (clock signal)
  4. MOSI (Master Out Slave In) known as PDI (Program Data In) on the chip
  5. RST (Reset)
  6. GND

You can figure out by yourself were you should solder those signals reading the ATMEGA64 datasheet (pin n° 2,3,11,20,21/52, 22/53) but I'll give you a simpler way to solder it : Actually the designer of this board were cool guys, the little pads you can see can be easilly used as entry point to solder your own wires.2013-01-01 16.40.50+annots

Pretty easy, isn't it ? I strongly recommend you to make an interface to the outside of the radio because there are several softwares that allow you to customize your model on your computer and then transfert the result in the radio memory, using this protocole. I personnaly used a DB9 connector. but you can use whatever you want (it must have at least 6 connections). The better place to put this connector is under the radio so your hands won't be disturbed.

2013-01-01 17.08.29

2013-01-01 16.41.06

Ok you can now close your radio (don't forget to plug the 12 wires connector). Try to turn on your radio. If it works, lets go to the next step!

Turn your arduino into a AVR programmer

From here, you can use every AVR programmer you want that is compatible with AVRDude (that is, almost every programmer, actually). But I hadn't one and I knew that the Arduino could be used as one. Here is basically the schematics you want (leds are optionnal but strongly recommended. Also, the PCB should not be really hard to design and make).

Untitled Sketch_bb_corr_1.01

Note that the reset is tied to Vcc to prevent reset when connecting the Arduino.

Double-check your connections between the ISP and the ATMEGA64, if you don't want to buy another 9X 🙂

The Scketch to upload to the Arduino is located under the examples as "ArduinoISP". This is actually an implementation of a subset of the "STK500" protocole  (learn more here), and therefore you'll be able to use it with Avrdude (which is nice because that's what we need to easilly flash our 9x !).

Pin assigment is given in the sketch :

// pin name:     not-mega : mega(1280 and 2560)</div>
// slave reset: 10        : 53</div>
// MOSI:        11        : 51</div>
// MISO:        12        : 50</div>
// SCK:         13        : 52</div>

[notice]

Because of the ATMEGA64 EEPROM address managment, you have to make 2 modifications : when reading the EEPROM and writing the EEPROM : the code looks like it :


uint8_t write_eeprom(int length) {
// here is a word address, get the byte address
int start = here * 2;

and


char eeprom_read_page(int length) {
// here again we have a word address
int start = here * 2;

You have to delete the "*2" since the address is already a byte in the ATMEGA64.

[/notice]

The Firmware

Just install the Companion9X software that will do everything for you. Just change your programmer option under Burn/Configure... and enter the following :

conf_avrdude

(The Port is the port representing your Arduino)

Ok, time to flash ! You can download whatever version you want and try all those wonderfull firmwares !

2013-01-02 15.49.34

2013-01-02 15.51.34

I hope this little tutorial has been usefull for you 🙂 Stay tuned !

A max7456 library for Arduino

It's been a while since we published the last article.. Well we've been pretty busy those days but as a gift in this article I'll present you some of our lattest work : A library for the well known max7456 chip by Maxim.

As famous as it is, a little reminder won't be too much. max7456 is basically used to insert customized information in a given analogic video stream. This manip is called "OSD" (for On-Screen Display). A little picture to explain it :

explainationOSD

We recently bought a wireless video system in order to do FPV (First Person Flying, you only look on a video send by a camera installed on the drone/plane). And the problem is that it's quite hard to pilot this way without additional informations about the flight. So we decided to make our own OSD system.

We decided to make a library for the max7456 because we didn't found one that fitted our needs. This library is pretty simple to use and comes with a complete documentation and example programs. This has been used with a PAL system, but the differences with NTSC are not really big (you have to init it an other way, refer to the datasheed of max7456 if you need to).

Here is the Hello World ! code :

#include "SPI.h"
#include "max7456.h"

Max7456 osd;

void setup()
{
  SPI.begin(); //to be called before osd.init
  osd.init(10); //CS on port 10
  osd.setDisplayOffsets(60,18);
  osd.setBlinkParams(_8fields, _BT_BT);

  osd.activateOSD();
  osd.print("Hello world : )",1,3);
}

void loop()
{
}

In order to make easier the process of entering new characters in the NVM (non-volatile memory) of the OSD, I made an program used to transform a bmp picture representing the OSD characters table into a single array you can use with the library (there is an example that shows the use of this array). Just lauch the executable with the options :

[source lang="shell"]convertOSD.exe -i ".bmp picture" -head ".h containing array"[/source]

The bmp picture looks like this :

tableOSD

This represents the 256 characters to be insered into the NVM. So here's the deal : when you want to put your customized characters table into the NVM, you must write on a register in the max7456. The values to write on this special register are directly related to the character. To be quick, each pixel of a character is 2-bits coded, and the character is 12x18 pixels you'll need 54 bytes of data. There are 256 characters in the table so the array returned by the program is 13824 bytes long (approx. 13.5k) . This is much more than the Arduino's flash memory can handle (2k). But the program memory is sufficient to store such an array. Then we used a little trick to program the max7456 in one single operation : we simple store the array in the program memory with the instruction :

const prog_uchar tableOfAllCharacters[13824] PROGMEM = {0x55,0x55,0x55,0 // ....

Nothing really hard here : character at address 0x00  is represented by the 54 first bytes, character at address i is represented by the (54*i) next 54 characters. Note that all the 0xFF value has been replaced by "0x55". This is because af a tricky bug in the Arduino bootloader that causes the Arduino to be corrupted if too many 0xFF are sent on a row to the program memory. Therefore, this is the method to get the character i in the table "table" (we fill a special type "charact" which is in fact a 54 bytes array.


//-----------------------------------------------------------------------------
// Implements Max7456::getCARACFromProgMem
//-----------------------------------------------------------------------------
void Max7456::getCARACFromProgMem(const prog_uchar *table, byte i, charact car)
{
	unsigned long index;
	byte read;
	index = i*54;
	for(unsigned long j = 0 ; j < 54 ; j++)
	{
		read = pgm_read_byte_near(table +index+j );
		car[j] = read;
		if (car[j] == 0x55)
			car[j] = 0xff;
	}
}

Note that we experienced problems with the sparkfun max7456 package. This was caused by a chip overheat dued to insuficient copper pad under it. We solved the problem by adding a tiny RAM heat dissipator on it.

Ok, most important part now : the sources !

Character array generator

Max7456 Library

The quadcopter : how to compute the pitch, roll and yaw

 The stick IMU from sparkfun
The stick IMU from sparkfun: ADXL345 accelerometer, ITG3200 gyroscope, HMC5883L compass.

After having introduced here the basics of an aircraft orientation and how to control it, this article is about actually computing the orientation of the quadcopter in space with sensors and with the Arduino.

 Which sensors to use?

3 axis accelerometer + compass for yaw

To get easily the orientation of a non-moving object (pitch and roll), a 3-axis accelerometer (how does it work?) can be used. For a static object, it gives the value of the gravity field on 3 axes, therefore its direction. And since it always points to the center of the earth, we can therefore know how the accelerometer is inclined with the help of man's best friend, trigonometry.

This method has been used in a lot of smartphones and gives pretty accurate results, if you are not moving. Indeed, if you start translating the phone in space, you are creating a force on it, therefore you are changing its acceleration. The assumption we made previously to compute the  orientation is not valid anymore, so the calculated orientation won't be accurate.

Another problem of accelerometers is their sensitivity to vibrations.(it is actually not a "problem"  per say, it is just a consequence of the forces created by vibrations, which are essentially shocks). If you want a stable quadcopter, you absolutely need a smooth angle! I think it is by far the most important thing about a quadcopter. If you're stuck with your PID tuning and that all the settings you try are not efficient, it probably means that your angles are not smooth/ accurate enough.

As you can see, using only an accelerometer is not a valid option. You can of course try to filter the signal and reduce the amount of vibrations received by the sensor( using some foam or anything to free the accelerometer from the motors vibrations can really change a lot the output of the sensor) but it will never be precise/ fast enough to satisfy the needs of this application.

Gyroscope

The most common used sensor in quadcopter control boards is the gyroscope sensor. It  gives the angular rate around the 3 axes of space in deg/s, so, as for the accelerometer, some simple maths are needed to compute the actual angle by integration. But using only a gyroscope raises problems:

  • The first problem raised is caused by the nature of the sensor. It just gives an angular rate, not an absolute measure. So if you start up the quadcopter on a crooked floor, the initials pitch/ roll angles shouldn't be 0, but they will be in your program since the gyroscope will just output null angular rates!
  • All the common MEMS gyroscopes used with Arduinos have a drift. It means that even if you stay steady and don't move, the sensor will output values different than zero. The drift can be pretty big for some sensors (it can go up 2 deg/s on the z axis of our L3G4200d !), therefore ruining the accuracy of the measurement when you integrate the values ! But it's not as bad as it could sound, most of the gyro drift can be subtracted from the measurement since it's a constant value (given a certain temperature).

So, both accelerometers and gyros are bad? The answer is no!

There is actually many different ways of getting the most accurate orientation from a combination of sensors and they all have their good and bad sides. The simplest  approach we've taken so far for our quadcopter, and which turns out doing pretty good, is a complementary filter.

The idea of the complementary filter is the following : the filtered accelerometer value of the angle  is not subject to drift, so we use it to "correct" the value given by the gyroscope(more precise and less subject to vibrations noises). How do we do that? We combine the two values like so:

 Angle_{accurate} = (GyroPercentage) * Angle_{Gyro} +(1-GyroPercentage)* Angle_{Accel}

GyroPercentage is just a floating value between 0 and 1. It is typically ranged from 0.9 to almost 1, depending on how much you can trust your gyroscope and accelerometer.

The angle given by this very simple method is actually pretty accurate and isn't too much time consuming for the Arduino. So if you don't want to go too deep into  the maths, I would suggest you to use this method, it is very satisfactory and easy to understand 😉

On the yaw axis, the same complementary filter is used  with a compass (which gives the direction of the earth's magnetic field), giving us the 3D orientation of the quadcopter like so:

 Yaw_{accurate} = (GyroPercentage) * Yaw_{Gyro} +(1-GyroPercentage)* Yaw_{Compass}

Last, but not least, filter your signals!!  It is fundamental to reduce the impact of the frame vibrations on the angle computation, if your computed angles are not accurate, your quadcopter will never fly. It is really the most important thing to do. And filtering the signals means both in software and in the conception of the frame. Use strong materials (such as carbon fiber), try to protect your IMU( Inertial Measurement Unit = Accelerometer + gyroscope + compass) from the vibrations. On the software side, if your sensors have a built in low pass filter (like on the ITG3200 and the L3G4200D ), activate them by writing in the good registers.  If you want to program  your own software low pass filter for you sensors, a simple method is to smooth the values given by the sensor like it is done in this pseudo  C code:

/* This code shows an easy way to smooth readings from a sensor subject to
 high frequency noise.
It uses a low pass filter on a circular buffer.
This circular buffer always contains the last BUFFER_SIZE-1 readings from
the sensor.
The new reading is then added to this buffer, from which wecompute the
mean value by simply dividing the sum of the readings in the buffer by the
number of readings in the buffer.
*/

int indexBuffer;
float circularBuffer[BUFFER_SIZE];
float sensorDataCircularSum;
int BUFFER_SIZE; // Number of samples you want to filter on.
float filteredOutput;
float sensorRawData; // typically the value you read from your sensor
 //in your loop() function

void smoothSensorReadings(){
 // We remove the oldest value from the buffer
 sensorDataCircularSum= sensorDataCircularSum - circularBuffer[indexBuffer];
  // The new input from the sensor is placed in the buffer
 circularBuffer[indexBuffer]=sensorRawData;
// It is also added to the total sum of the last  BUFFER_SIZE readings
// This method avoids to sum all the elements every time this function is called.
 sensorDataCircularSum+=sensorRawData;
// We increment the cursor
 indexBuffer++;

 if (indexBuffer>=BUFFER_SIZE) indexBuffer=0;// We test if we arrived to the end
//of the buffer, in which case we start again from index 0
 filteredOutput =(SensorDataCircularSum/BUFFER_SIZE); // The output is the the mean
//value of the circular buffer.
}

What is basically done here is just an average value of the BUFFER_SIZE last inputs from the sensor. This is a simple way to get rid of high frequency noise and can also be used to smooth PWM inputs from a RC control, for example 🙂

If you made it until here, I hope you are now able to implement by yourself your own implementation of orientation computing. It's actually a big area of research and much more complex solutions are still developed ( I invite you to look at Sebastian Madgwick  fusion filter algorithm 🙂 ).

The quadcopter : first video !

Our quadcopter

After having been through many, many hardware problems, the quadcopter is finally flying! We still have troubles with the ITG3200 on the stick IMU from Sparkfun which is causing some stability problems, but it's pretty cool to fly, and to watch ! 🙂

The hardware features :

  • A 50 centimeters wide full carbon frame that we built using Benoits CNC mill
  • 4 Turnigy Aerodrive SK3 2826 1130 kv motors
  • 4 Turnigy Plush ESCs 30 A
  • 4 9x4.7 or 8x4.5 propellers
  • A homemade flight controller shield mounted on an Arduino Uno
  • A 2200 mAh battery for regular flights, and a 5000 mAH battery when the GoPro is mounted
  • Possibility to fly in X or + configuration (we only use X now )

Here is the first video we release on Youtube, we will try to add more, especially from the GoPro 🙂

[youtube]http://www.youtube.com/watch?v=hWE15DqSTSU&feature=player_detailpage[/youtube]

Pretty cool, isn't it? 🙂 We will post soon more articles about the details of the quadcopter, with more pictures and even more videos. Stay tuned 😉