help with averaging sensor readings

Back story:

i am building a balancing bot using the Wii Nunchuck and WMP (currently only the nunchuck). using the nunchuck_funcs.h and wire.h library i can read the sensor fine, and get it to change the direction of the motors based on it’s posistion with:

if(accx > 132){
reverse(244, 244); //subroutine to control h-bridges
}
if(accx < 130){
forward(244, 244); //subroutine to control h-bridges
}


Issue:

My problem occurs when i try and set some calibration data, ideally i would read the sensor a few times and average the results as the starting position. the code i came up with (partly borrowed) is:

void average(){
int avg[5];
int i;
for (i=0; i<5; i++){
nunchuck_get_data();
avg = nunchuck_accelx();

  • delay (10);*
  • }*
  • accx_cal = (avg[0] + avg[1] + avg[2] + avg[3] + avg[4])/5;*
    }
    then i change my motion detect if statements to:
    if(accx < accx_cal)
    and i get no response, the motors turn forward, and never change.
    i then tried something as simple as:
    int runonce = 0;
    void loop(){
  • if (runonce == 0){*
  • accx_cal = nunchuck_accelx();*
  • runonce = 1;*
  • }*
    }
    and the same thing occurs. i can put a “blink ledpin” line in the runonce if statement, and it does blink the ledpin only once, so that part is working correctly.
    Any help would be appreciated, and i will be happy to post all my code if it will help. This is obviously just the problem areas.
    Thanks in advance!
    - James.

This is obviously just the problem areas.

No it's not, it's just bits that call functions that do stuff. It is the doing of the stuff that is going wrong.

i will be happy to post all my code if it will help.

It's the only way we are going to get anywhere.

Please use the # when posting code. (if you don't know what that means then look it up)

Or, more sensibly in a memory-limited environment:

void average(){
     unsigned long sum = 0;  // or "unsigned int" if 'n' is small enough
     for (int i=0; i<5; i++){
           nunchuck_get_data();
           sum += nunchuck_accelx();
           delay (10);
     }
     accx_cal = sum /  5;
}

just for the hell of it: http://www.arduino.cc/playground/Code/AverageList :)

Here is all my code.

thanks for taking a look!

#include <Wire.h>
#include "nunchuck_funcs.h"

int motorA1Pin = 2;    // A H-bridge leg 1
int servoPin = 3;      // Servo control
int motorA2Pin = 4;    // A H-bridge leg 2
int motorB1Pin = 7;    // B H-bridge leg 1
int motorB2Pin = 8;    // B H-bridge leg 2
int enableAPin = 9;    // A H-bridge enable pin
int enableBPin = 10;   // B H-bridge enable pin
int ledPin = 13;       // Status LED 

int loop_cnt = 0;
int accx_cal;
int accy_cal;
int accz_cal;
int runonce = 0;

byte accx,accy,accz,joyx,joyy,zbut,cbut;

void setup() {
      // set motor pins and led pin as output
      pinMode(motorA1Pin, OUTPUT);
      pinMode(motorA2Pin, OUTPUT); 
      pinMode(enableAPin, OUTPUT);
      pinMode(motorB1Pin, OUTPUT); 
      pinMode(motorB2Pin, OUTPUT); 
      pinMode(enableBPin, OUTPUT);
      pinMode(ledPin, OUTPUT);
      //Runs at start; for error reoprting
      blink(3, 500); 
      delay(500);
      // send the initilization handshake   
      nunchuck_init(); 
}

void loop() {
      // looks at loop_cnt for delay before it gets new data
      if( loop_cnt > 10 ) {
            loop_cnt = 0;
            nunchuck_get_data();
            accx  = nunchuck_accelx();
            accy  = nunchuck_accely();
            accz  = nunchuck_accelz();
            joyx  = nunchuck_joyx();
            joyy  = nunchuck_joyy(); 
            zbut = nunchuck_zbutton();
            cbut = nunchuck_cbutton();
            //runs a calobration; once at startup - or on cbut press
            if (runonce == 0){
                  accx_cal = nunchuck_accelx();
                  runonce = 1;
                  blink(4, 400);
                  delay (500);
            } 
            //Forward accelerometer detect
            if(accx >= accx_cal){
                  reverse(244, 244);
            }
            //Reverse accelerometer detect
            if(accx <= accx_cal){
                  forward(244, 244);
            }
            //Level detect
            if(accx > 121 && accx < 123){
                  stop;
            }
      }
      loop_cnt++;
      delay(1);
}

// Starts motors forward, with PWM
void forward(int pwmL, int pwmR) {
    digitalWrite (enableAPin, pwmL);
    digitalWrite (enableBPin, pwmR);
    digitalWrite(motorA1Pin, LOW);
    digitalWrite(motorA2Pin, HIGH);
    digitalWrite(motorB1Pin, LOW);
    digitalWrite(motorB2Pin, HIGH);
  }

// Starts motors reverse, with PWM
void reverse(int pwmL, int pwmR) {
    digitalWrite (enableAPin, pwmL);
    digitalWrite (enableBPin, pwmR);
    digitalWrite(motorA1Pin, HIGH);
    digitalWrite(motorA2Pin, LOW);
    digitalWrite(motorB1Pin, HIGH);
    digitalWrite(motorB2Pin, LOW);
  }
// Full stop
void stop(){
      digitalWrite (enableAPin, LOW); 
      digitalWrite (enableBPin, LOW);
}

//    blinks ledPin
void blink(int howManyTimes, int milliSecs) {
  int i = 0;
  for ( i = 0; i < howManyTimes; i++) {
    digitalWrite(ledPin, HIGH);
    delay(milliSecs/2);
    digitalWrite(ledPin, LOW);
    delay(milliSecs/2);
  }
}

void average(){
      int avg[5];
      int i;
      for (i=0; i<5; i++){
            nunchuck_get_data();
            avg[i] = nunchuck_accelx();
            delay (10);
      }
      accx_cal = (avg[0] + avg[1] + avg[2] + avg[3] + avg[4])/5;
      blink(1, 500);
      blink(4, 200);
}

Well, I had a look, and I saw this:

stop;

I'd say that doesn't do what you think it does.

As to the rest of it, I couldn't say, because you haven't said what it does, and how that differs from what you expect it to do.

That calls a sub routine,

void stop(){
      digitalWrite (enableAPin, LOW);
      digitalWrite (enableBPin, LOW);
}

the behavior is described in the first post. i will be happy to clarify anything.

then it should be stop();

Thanks for that clarification! I am new enough that i rely too much on the compile errors to check my syntax...

That was corrected, and there is no change in behavior.

is there something wrong with how i am comparing my new data with my calibration measurement?

if(accx >= accx_cal)

or how i am reading / storing the calibration measurement?

void loop() {
      if( loop_cnt > 10 ) {
            loop_cnt = 0;
            nunchuck_get_data();
            accx  = nunchuck_accelx();
            accy  = nunchuck_accely();
            accz  = nunchuck_accelz();
            joyx  = nunchuck_joyx();
            joyy  = nunchuck_joyy(); 
            zbut = nunchuck_zbutton();
            cbut = nunchuck_cbutton();
            if (runonce == 0){
                  accx_cal = nunchuck_accelx()
                  runonce = 1;
                  blink(4, 400);
                  delay (500);
            } 
      }
      loop_cnt++;
      delay(1);
}

I would be happy to post the nunchuck_funcs.h if it will help anyone.

That was corrected, and there is no change in behavior

We don't know what that behaviour was, so until you tell us and how it differs from what you expect to occur, any help we offer is just guesswork.

i am building a balancing bot using the Wii Nunchuck and WMP (currently only the nunchuck). using the nunchuck_funcs.h and wire.h library i can read the sensor fine, and get it to change the direction of the motors based on it's posistion

My problem occurs when i try and set some calibration data, ideally i would read the sensor a few times and average the results as the starting position. the code i came up with (partly borrowed) is:

and i get no response, the motors turn forward, and never change.

I want to assign the current position on startup as a reference location to compare movements too. if i compair a numeraical value to accx it works fine,

if(accx > 132){
reverse(244, 244); //subroutine to control h-bridges
}

Then i use any number of my ways to assign my calibration reading to accx_cal and

if(accx > accx_cal){
reverse(244, 244); //subroutine to control h-bridges
}

does not work.

What are your debug prints telling you?

Well... this is built into a project so i made a freeduino board for it, and my MAX232 chip is not talking with my computer yet. I am using my Arduino board to upload my new sketches, that is why there is no serial.print lines.

I have tried to use a blinking led as my feedback; for instance if i put "blink(4,200)" in my runonce if statement, it does only blink the led (4)one time...

A far cry from real prints though i know.

When i get time i am going to make a 10X2 cable -> individual pins so i can connect the arduino board to the interface that i put on the freeduino, and then i can "see" some of this data.

I did just change my

int accx_cal = 132;

and my if statent

if(accx > accx_cal){
    reverse(244, 244);
}

works. so it has to be the way i am reading the current accx value and assigning it to accx_cal.