Go Down

Topic: Kalman Filtered Nunchuck & Wii Motion Plus (Read 32395 times) previous topic - next topic

DogP

Quote
I don't understand the details, but would it be possible to sacrifice the button and joystick data on the nunchuck in order to increase the resolution of the accelerometer reporting?


Unfortunately, I don't think so... when I was initially figuring out the controller remapping for the Nunchuck and Classic Controller, I thought maybe we could use the Classic Controller mapping, which moves the last two bits of byte 5 into the last bit of byte 0 and 1, but for some odd reason even though a 1 is hardcoded into the Classic Controller byte 4 bit 0, it seems that the MotionPlus manually hardcodes that bit as well rather than just passing it through.

Because of that, when you use a Nunchuck in Classic Controller mode, you lose the LSBit of each joystick axis (good), but then also the LSBit of byte 4, which is the Z-Axis bit 2... which really screws things up.  The X and Y axes have full resolution, but unless you want a 2 axis accelerometer, that's probably not very helpful.

DogP

ardvark

Quote
The X and Y axes have full resolution, but unless you want a 2 axis accelerometer, that's probably not very helpful.

Actually I would like to look into that  :) (I'm interested to see the performance limits of these accelerometers). Could you point me in the direction of what I need to learn to implement the classic controller mapping on the nunchuck? I am assuming it is possible to combine this with the passthrough method?

DogP

Yeah, sure... download my object from: http://obex.parallax.com/objects/471/ , and read the top of the MotionPlus.spin file... that has the mapping for the Nunchuck and Classic Controller in Passthrough mode.  Of course the non-passthrough mappings are available here: http://wiibrew.org/wiki/Wiimote/Extension_Controllers .  When you initialize the MotionPlus, just initialize with 0x07 rather than 0x04 (MP by itself) or 0x05 (MP w/ Nunchuck).

If you compare the mapping for the Classic Controller passthrough w/ the regular Classic Controller mapping, you'll see the difference is just the two bits, except the hardcoded 1 in byte 4 bit 0 seems to be actually hardcoded in the MotionPlus as well :/ .  The MotionPlus doesn't know which controller is actually connected... it just acts differently depending on which initialization was used.

Oh... and to make sure I was clear... I don't mean it gives you the full resolution of the sensor... I mean the full original resolution as it was before the dropped bit from the passthrough.

DogP

Dimitris

I tried to use MP+ on standalone mode yesterday, but I was getting all 0 readings... hmmm
Does the reading address change when you change the mode?

auto11

@duckhead: "do you have working DCM code that you can share?  I've read the theory but I guess I don't interpret it the same as you.  I'd like to learn more about it and for me working code is more intuitive than theory."

No I don't  -  I spent few hours over the weekend working on it but it's not done yet - need more time ( I am first trying to get yaw-pitch to work before tackling yaw....and for yaw you need either GPS or mag.).
You can find links to documentation and code at:
http://diydrones.ning.com/page/uav-devboard

(look for roll-pitch  or roll-pitch-yaw). There are links to code for Bill P.'s implementation on another chip. Bill P. is the one who developed this approach based on Mahony's papers.
As far as I know Jordi ( who's Kalman filter approach was referenced at the beginning of this thread) worked on implementing DCM on Arduino and should release the code soon (apparently he worked on this for 6 months with help from Bill P. - and six months included not just code but board development and testing for ArduPilot shield, etc. if I understood things correctly...)



As far as loss of bit data in pass through mode

- this is just a though and I haven't tested this (will do if I get some time next week) - separate Nunchuck and WM+ and run them (address them) separately. Run one using wire lib and connecting data and clock to Analog 4 and Analog 5 pins, and run the other in the manner DogP (and krulkip) showed, connected to Digital 4 and Analog 0 pin,  and using Ports lib. Just a thought....

Xevel

#155
Sep 14, 2009, 03:50 pm Last Edit: Sep 14, 2009, 03:51 pm by xevel Reason: 1
Hi,

As a follow up of my previous statement about some recent WMP having different gyros : it is not the case. I opened it and it's the same old IDG-600 in the C6VF100 as it was in the C4GF500.
What strikes me is that i get clearly better results using 4.5 instead of 4 or 5 as the coefficient between slow and fast (which is why I first thought it was an IDG-650 in the first place). Could it be a change in the WMP firmware?

Adr1an

#156
Sep 14, 2009, 03:55 pm Last Edit: Sep 14, 2009, 03:58 pm by adr1an Reason: 1
Quote
- this is just a though and I haven't tested this (will do if I get some time next week) - separate Nunchuck and WM+ and run them (address them) separately. Run one using wire lib and connecting data and clock to Analog 4 and Analog 5 pins, and run the other in the manner DogP (and krulkip) showed, connected to Digital 4 and Analog 0 pin,  and using Ports lib. Just a thought....


Whilst from an engineering perspective, its a good idea.. I think thats slipping down the other side of the bellcurve in terms of 'effort-for-gain-for-cost'... You have then 2 libraries to compile in, extra ram used, a more complicated program etc etc... You also blow 2 extra pins on the 'duino.

Allin all seems a bit off effort to get not really much more.. if its all that important, isn't it probably better at that stage to just switch to a 'proper' gyro/accelerometer combo...
*shrug*.. just my thoughts.. :)
Checkout my projects development blog @ SLiDA

ardvark

#157
Sep 14, 2009, 04:48 pm Last Edit: Sep 14, 2009, 06:03 pm by ardvark Reason: 1
Duckhead's original code scaled the raw x and y axis accelerometer values into radians via normalisation by a value of 1023. I think a value of ~430 is possibly more appropriate:

    Example of the accelerometer rotation values for y axis on my nunchuk.
   
    Exact values differ between x and y axis, and probably between nunchuks, but the range value may be constant:
   
                 298 ayMIN
                       _|_
                     /      \
  ayMID 513 - |        | - 513 ayMID
                     \ _ _ /
                         |
                 728 ayMAX
             
     ayRange = (ayMID - ayMIN)*2 = ayMAX - ayMIN = 430

Scaling:
Code: [Select]

       //Zero the values on a#MID.
       ax_m -= axMID;
       ay_m -= ayMID;
       az_m -= azMID;
     
       // Convert to radians by mapping 180 deg of rotation to PI
       x = angleInRadians(ayRange, ax_m);
       y = angleInRadians(ayRange, ay_m);
       z = angleInRadians(azRange, az_m);


Scaling:
Code: [Select]

//Nunchuk accelerometer value to radian conversion.
float angleInRadians(int range, int measured) {
 float x = range;
 return (float)(measured/x) * PI;
}


Constants:
Code: [Select]
// Exact values differ between x and y axis, and probably between nunchuks, but the range value may be constant:
static const int axMIN = 290;
static const int axMAX = 720;
static const int axMID = (axMAX - axMIN)/2 + axMIN;
static const int axRange = (axMID - axMIN)*2;

static const int ayMIN = 298;
static const int ayMAX = 728;
static const int ayMID = (ayMAX - ayMIN)/2 + ayMIN;
static const int ayRange = (ayMID - ayMIN)*2;

// Not sure what a meaningful scale is for the z accelerometer axis so:

static const int azMID = ayMID;
static const int azRange = ayRange;

Any thoughts?

ardvark

@ DogP: thanks very much for the mapping info, I will give it a try :-)

ardvark

As an alternative to the Kalman approach, I implemented a complementary filter in the pass-through code. It combines the accel and gyro as inputs and outputs drift-free orientation angles and strongly suppresses the movement artifacts coming from the accel input. This filter approach is simple to understand and tweak, quite effective, and only takes a couple of lines of code. Anyway, if it is of interest I can clean it up and post it.

BTW, have people lost interest in this thread? Or is it just too hard to access? If you think a smaller thread might perform better we could start another as a sequel.

Adr1an

Well I'm certainly interested still! :)

Post up the complementary filter by all means... it can only help! :)

Does it handle yaw well ??
Checkout my projects development blog @ SLiDA

ardvark

At the moment I am still testing it for the x axis (pairing the corresponding gyro and accel axes) and I am not using trig to combine the axis data yet (which I guess is necessary for yaw). I will annotate a bit and post it.

Dimitris

#162
Sep 17, 2009, 04:22 pm Last Edit: Sep 17, 2009, 04:24 pm by dimkasta Reason: 1
I haven t been able to access the thread for a few days now. Plus I haven t worked on my code either since I m waiting for my new sensors, magnetometer, gps etc.
The nunchuck's 10bits (9 in pass-through) proved to be too few for my project, although I love the 16bit gyros from mp+ :D.

However, I am still working on refactoring the code to be able to accommodate input from any angle metering sensor, so I will be able to post some more stuff as soon as I get some testing on the magnetometer and gps stuff.

I have also incorporated a scheme to save zeroing calibration data to the eeprom and reading it back when arduino executes setup.
Calibration and saving the data should be triggered either through software choice, or using an interrupt.

I would surely love to see your implementation of the complementary filter. I am running low on program space and I still haven t worked on the UI stuff....
And I agree, it might be better/clearer to put it on a separate thread.

Adr1an

Quote
I have also incorporated a scheme to save zeroing calibration data to the eeprom and reading it back when arduino executes setup.
Calibration and saving the data should be triggered either through software choice, or using an interrupt.


Can you share this ? I've been thinking about doing exactly that :)
Checkout my projects development blog @ SLiDA

Dimitris

#164
Sep 17, 2009, 06:43 pm Last Edit: Sep 17, 2009, 11:47 pm by dimkasta Reason: 1
@And1an

Well it is part of some bigger refactoring changes I have made to the code which include keeping variables in structs to better help identify how and where I manipulate them.

The actual storing thing was implemented using the epprom save anything code from playground.

The code is not complete yet, so I cannot post it, but that is the main idea.

Go Up