Namespaces

Variants
Actions

BayleAdvancedProject-p6a

From Cycling '74 Wiki
(Difference between revisions)
Jump to: navigation, search
(Created page with "== Handling fast movement for dedicated purpose == As I decided, I didn’t really need to track all 3 axis value. I tested that by prototyping. Moving the device fast in an...")
 
m (Ddg@cycling74.com moved page BayleAdvancedProject-p7 to BayleAdvancedProject-p6a: rename)

Revision as of 05:34, 12 June 2013

Handling fast movement for dedicated purpose

As I decided, I didn’t really need to track all 3 axis value. I tested that by prototyping.

Moving the device fast in any direction alters any of the axis so, I decide to test (and finally use) only the x-axis.

Why use a debouncer?

Debouncing is a common technique used with digital input initially.

Indeed, it basically involves a timer in order to filter mechanical artifacts happening when you push a button and read a digital input value with a microcontroller. Check this article about the debouncing: http://arduino.cc/en/Tutorial/Debounce and you can also find this in my book, obviously.

When you push a button, it bounces. This happens really fast, but you can have jumping (bouncing) values if you measure it continuously. This saves my protodeck in the past and even if you have very good quality buttons/switches, it occurs.

It produces that: you push it without releasiDon’t forget the whole schematic. Here it is below.

In this design, I also saved some money by not using 2 Arduino because I only needed to read data (and I could have been able to send some too) using the XBee module on the computer side. In this case, the only XBee explorer interface was enough !

I saw too much projects like that using 2 boards (and even sometimes BIG boards). Please don’t use too much components if you don’t need them!


<image here> Basic design


Continuing the firmware description, I created a function named setupAccelerometer() , this is only for a better vision of my code. I could have included the whole content of this function inside setup().

This function define and setup the whole ADXL345 behavior from the Arduino Fio’s firwmare point of view.

We define some threshold in order to track 5 events using one interrupt on the ADXL345 board:

- activity detection

- inactivity detection (which I defined as the lack of activity here)

- tap detection

- double tap detection

- freefall detection

Interrupt concept is quite well explain in my book. Basically, this is a way to interrupt the main flow of the global code and to trigger some action. These are very useful in our case. Why?

One of the best way to understand what they are is the mouse case.

The mouse on our computer (or the trackpad in my case) uses interrupt. Why would our operating system check everytime a day if I touched the track pad ? It would loose time and wouldn’t be really available for anything else (actually, it would, but it would loose time, anyway)

There is another architecture providing a way to handle what is done on the trackpad only when I’m using it. It is called interrupt.

I touch it, then release it, the operating system is informed something happens and is able to handle this then continue what he was doing.

This is a briefly and a bit simple explanation of what an interrupt provide.

In loop(), which is the main part of our firmware and is running continuously at runtime, I first grab interrupt source and put his in interrupts byte type variable.

There are then some conditional piece of code.

In our case, if no event is detected amongst those 5 described above, the main part of our firmware run by looping quietly.

If i let the accelerometer and the arduino Fio (and the battery) falling down, an interrupt is sent and the part of code testing the particular case ADXL345_FREE_FALL is suddenly verified.

If I put something special inside this case, it will only be triggered if the device freely falls.

So, I currently only have some message written to the serial port, i.e to the XBee module. This latter pushes this message to the other XBee connected to the computer and my Max6’s patch is able to grab it :)

I used this code for testing purpose only.

You probably check this part of the code, all commented.

// measuring Accelerometer on 3-axis


//int x,y,z;  
//adxl.readAccel(&x, &y, &z); //read accelerometer values store them in x,y,z
//Serial.print(x);
//Serial.print(y);
//Serial.println(z);

If we uncomment the 4 last rows, at each loop() execution, we read each value of the acceleration measured by the ADC (Indeed, an Analog to Digital Converter samples values measured by the sensor component) and we store them in some variable as integer.

Then, we are writing them to the serial for sending them, in fine, to Max6’s patch.

This is done at each turn.

Because I only wanted to track a fast movement, I decided to use only accelerometer values and put a small and cheap software filter also called debouncer.

Let’s check how I handled that.

ng it, and the value read should be 1. But it is 1, then 0, then 1 etc... several times, then 1 finally.

If you put a timer involving a right and subtly found delay time during which NO value is read, you can filter (we also used to say smooth) the value read.

Here is the pseudo code involving my filter in loop()

I read x acceleration value.

If the difference between this current value and the last one (at the previous loop) is bigger than a threshold, reset the timer and say to the program to fire a message on next time.

If the delay between the last detection and now is higher than the debouncing delay AND the program has to fire a message then fire the message AND say to the program not to send anything till the next detection occurs.

store the current value to be able to keep it to be compared to the next one.

Here is now ... the code implementing this behavior. I put the whole code and I removed all unuseful parts in order to make it ... simpler & clearer.

  1. include <Wire.h>
  1. include <ADXL345.h>

ADXL345 adxl; //variable adxl is an instance of the ADXL345 library

int currentState;

long lastDebounceTime = 0; // init the debounce

long debounceDelay = 120; // debounce delay for filtering

int accelerationThreshold = 170; // acceleration threshold to trigger a message

boolean trigger = false;

void setup(){

// init the serial communication between the Arduino Fio and XBee module
Serial.begin(57600);
// accelerometer setup
adxl.powerOn();

}

void loop(){

// measuring Accelerometer on 3-axis
int x,y,z;  
adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in x,y,z


// if a threshold is reached
if ( abs(abs(currentState) - abs(x)) > accelerationThreshold )  
{
  // reset timer
  lastDebounceTime = millis();
// notify the program to fire a message at some point    
  trigger = true;                             
}
// if the debouncer time is bigger than our delay
if ((millis() - lastDebounceTime) > debounceDelay) {


  // if the program has been notified to send something
  if (trigger) {


    // send the message to XBee and in fine to Max6
    Serial.println("movement");


    // notify the program to not send something til next detection
    trigger=false;
  }
}


// store the current state for next turn comparison
currentState = x;

}

The code is quite explicitely commented and fits with the previously written pseudo-code.

The only thing I want to explain here is the debounceDelay and accelerationThreshold.

Indeed, how I found the perfect fitting value ?

I tested. This is the only way. You can analyze, calculate, at some point you have to make.

120 ms make people able to make a big breadth movement.

For accelerationThreshold, I tried multiple values by replacing the whole loop by:

void loop(){

// measuring Accelerometer on 3-axis
int x,y,z;  
adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in x,y,z
if ( abs(abs(currentState) - abs(x)) > accelerationThreshold )  
{

Serial.println("movement");

}

currentState = x;

}

Monitoring values looking at the Max6 patch, I tried some values until, while I was still moving almost permanently the device prototype making my daughter laughing at me very lound, I had only very few triggering while moving.

Ideally, it would send only one message for each movement.

If there are 2 or 3, that is fine.

Then I found these values and I kept them.


So I achieved it.

It worked.

In the final release, I plugged my data source (coming from the device) to Openframeworks which can now react according to device’s movements.

Keep connected to my website and my blog especially, I’ll post th whole work there quite soon:

http://julienbayle.net

I’m inviting you to follow me on twitter, facebook and everywhere else.


The real big picture of everything working fine