Status of Wii MotionPlus Support for WiimoteLib

Posted June 19, 2009 1:43 PM Categories: .NET | Coding4Fun | Wiimote | Hardware

Update: See this post for a beta release

wii-motionplus Ok, I get about 10 emails a day on this, so I figure a status update is in order.

The Wii MotionPlus extension for the Wiimote was released last week.  Since then, I and others have been working to figure out how the device works.  Unfortunately, it does NOT work as every other extension controller has worked up until this point, mostly due to the fact that the Wii MotionPlus accessory has an expansion port of its own so all of the other extension controllers can plug into it.

In the past few days, some progress has been made thanks to the folks over at wiibrew.org, although functionality is nowhere near complete.  For example, it’s currently impossible to have the Wiimote notify you when the Wii MotionPlus is inserted into the bottom of the Wiimote, like all of the other extension controllers do.

I have been working with the information at wiibrew.org and am trying to get things working reliably with my library so that developers can actually get some degree of functionality out of it.

So, all that said, expect to see a new (likely beta) version of WiimoteLib “soon” that has some bare-bones Wii MotionPlus functionality included.  It won’t be perfect, complete, or bug free, but it will allow you to tinker with the device a bit.  I will update my blog when the new version is available.  Thanks!

Comments (35) -

thattolleyguy
thattolleyguy
6/19/2009 2:16:06 PM #

Thanks for your work. I've tried modifying your code to recognize the motion plus and I got it to work and send the motion plus data across. One problem I ran into is that when I had a nunchuk plugged in to the motion plus, sometimes the pc would say the extension was a nunchuk, but the data coming in was from the motion plus. I'm not sure if you'll see the same thing, but that's one thing I ran into.

Brian Peek
Brian Peek
6/19/2009 2:21:59 PM #

I'm not sure I've seen that one specifically, but I've had a few problems with pass-through extensions with the Wii MotionPlus attached.  None of it is very reliable it seems...

old man Earl
old man Earl
6/24/2009 9:19:39 PM #

A few of us over at the Parallax Propeller website have written several programs, including a 6DOF using the nunchuck and motion plus. We primarily use it via the i2c bus rather than bluetooth. Here is a link.
forums.parallax.com/.../default.aspx

vats
vats
6/27/2009 10:45:09 PM #

Great work!!! looking forward for wiimoteplus library....

Benjamin Gmeiner
6/29/2009 11:26:45 AM #

Any news on this? Got the motion plus today and can't wait to see what all the fuzz is about ;)

Thx!

Kerry Snyder
7/1/2009 12:07:47 PM #

Well, I'm going to shamelessly promote myself, and say that you should check out my blog. I cover Complementary Filtering for combining Gyro and Accel data to get a solid angle signal. Though I could help.
http://www.ohscope.com/2009/06/getting-angle.html

IraqiGeek
7/14/2009 1:50:16 PM #

Any updates on the support of the motion plus in Wiimotelib?

thattolleyguy
7/15/2009 1:00:59 PM #

Any progress or anything we can do to help out? Still "patiently" waiting for this. Smile

Brian Peek
Brian Peek
7/15/2009 2:47:42 PM #

It seems the community has stalled...while we can detect and enable the MotionPlus, and the data can be pulled, doing something useful with that data is the sticking point.

I'll maybe do an "unstable" release in the short term, but it likely won't be of much value to anyone...

anon
anon
7/16/2009 12:18:00 AM #

I'd like to see an unstable release with the ability to at least see the data.  Might get some more eyes on the problem too.

Bogac Guven
Bogac Guven
7/16/2009 3:09:49 PM #

As we can see in Iwata Asks interview, uk.wii.com/.../...ks_motionplus_volume_1_2162.html  I guess reverse engineering the hardware and data it returns is not enough. It seems Nintendo did some algorithm works on software side, which needs to be understood.

Rex
Rex
7/17/2009 1:09:17 PM #

I think the community currently has the data format wrong.  From my own data analysis, I've found 4 distinct sensitivity levels (3 in slow mode, 1 in fast) for each of the 3 gyros.  My Slow/Fast bits are also different (same location, but some values are flipped).  It doesn't make any sense.  There might be multiple versions of the motion plus floating around.  I got mine with Tiger Woods 2010.  It may be that the data is somehow encrypted, although the community not seem to think so.    

Kyle Thomson
Kyle Thomson
7/17/2009 2:09:52 PM #

I'm somewhat confused - It appears from wiibrew.org that the 'data output format' is well understood. Is it understanding the trigonometry that is causing the problem?

Also, is the major stability issue caused by having an additional attachment?

Thank you for writing the library!

Brian Peek
Brian Peek
7/17/2009 2:36:20 PM #

@Rex, for me, the data has been spot-on to what's at wiibrew.org .

@Kyle, precisely.  We've got 3 axes of speed data from the gyro, but using it to determine orientation reliably over time isn't really figured out.

All that said, everyone has convinced me to release a version of WiimoteLib "as is" with MotionPlus support.  Look for it very soon...like this weekend soon.  Smile

Rex
Rex
7/17/2009 6:17:21 PM #

Whoops, the lib I was using (WiiYourself!, based on your library) still used the legacy encryption handling, my bad.  It's working perfectly now.

Peter
Peter
7/17/2009 8:51:53 PM #

Hi Brian,

Are you aware of how games use the WM+ data? I always assumed that the Wiimote simply relays the angular rates from the gyros in the WM+ along with accelerometer data from the WiiMote and the AHRS solution is calculated by the Wii.

If this is the case, wiimotelib should only need to provide wmp.values.r/p/q (calibrated angular rates in radians about x, y and z) and wmp.rawvalues.r/p/q (raw binary from the WM+)

Let other people figure out how to calculate the correct orientation over time. My guess is that a game that uses the WM+ would need to implement direction cosine matrix and perhaps a kalman filter with the gravity vector and IR heading from the Wiimote.

Brian Peek
Brian Peek
7/18/2009 12:51:13 AM #

@Peter, nope, I don't know how games use the WM+ data.  I don't even own a WM+ game.  Smile

The beta version of the lib will hand you raw values from the WM+, but not calibrated values.  There is calibration data stored in the WM+ just like the Wiimote, but the data format hasn't been figured out yet.  That said, the raw values tend to be ~8000 per axis.

It sounds like you've got a decent handle on how this could work.  Please do check out the lib when I release it and see if you can make any further discoveries.  I'm admittedly terrible at math, so I'm hoping users like you will be able to help get it to the next step...

Rex
Rex
7/20/2009 2:52:45 AM #

I've found out how to get an orientation from the rate gyros...it's surprisingly easy, and stays pretty decent for a long time, even without a dead zone via pure integration.   The algorithm is

calculate a time step (in seconds) from the last wiimote update time
get the three angular rates (in radians/sec), yaw, pitch, roll, put them in a vector A
angle = A.magnitude()*time_step;
axis = A.normalize();
rotation = quaternion(angle,axis);
orientation_quat= orientation_quat * rotation_quat

To create the A vector, I used (pitch,roll,yaw).  This is because I started the wiimote pointing up, with the buttons facing me.  That means that these rotation corresponded to the opengl coordinate system for rotation about x, y, and z.  It would have been different if the wiimote had have been oriented differently.

Finally, I calibrated the gyros first, by taking 100 samples and finding the average for each axis, then subtracting this average value from each reading.

Correcting with the accelerometers will be a little more difficult.  The "right" way to do this is with a Kalman filter as Peter suggested, but I'll probably do it the wrong way, with just a brute force update if I detect a stationary wiimote.  How to update the global pitch and roll without updating the yaw though is slightly lost on me.  I'll post again if I figure it out.

Xander
Xander
7/20/2009 3:56:53 AM #

From what I've read on Wiibrew so far, it seems that the WM+ must be deactivated in order to access a nunchuck plugged into it.  I'm pretty certain games dont do it this way, the reinitialization of the WM+ is too long.

Has anyone been able to figure out how the games do it?

Thanks!

Kamegami
Kamegami
7/21/2009 12:40:19 AM #

The InvenSense website references two research papers that detail how to perform 6DOF with raw accelerometer and gyroscope data. The paper "Measuring orientation of human body
segments using miniature
gyroscopes and accelerometers" in particular uses Kalman filters to adjust for the inaccuracy and noise of lower-end sensors. I'm looking to implement the algorithm if I get time, which I probably won't.

www.invensense.com/.../..._sensing_accel_human.pdf

www.invensense.com/.../...e_using_sensors_IMUS.pdf

www.invensense.com/.../library.html#gamecontroller

Neil
Neil
8/1/2009 9:52:43 AM #

Hi Brian,

In WiimoteLib i noticed you were getting the raw data by doing the following:
RawValues.X = (buff[offset + 0] | (buff[offset + 3] & 0xfa) << 6);

Is there a specific reason for using 0xfa? Would it not be 0xfc to get the top 6 bits of a byte? Are you trying to integrate the slow rotation bytes into the number?

I'm just asking because I am trying to add motionPlus functionallity into wiiuse and using 0Xfa gives me odd values. My 0 values for staying still seem to be different than my 0 values for moving.

Brian Peek
Brian Peek
8/1/2009 3:30:23 PM #

@Neil, good catch.  That's why it's a beta.  Smile  I'll make the fix for the next version.  Thanks!

GCSX
GCSX
8/2/2009 12:00:19 PM #

This 'bug' is also present in CWiid. I've done the same error while trying to implement the MotionPlus in WiimoteLib. (before you release the Beta)

Brian Peek
Brian Peek
8/2/2009 3:05:13 PM #

@GCSX, you know what, I remember this now.  Going back to your site, I realized your page is linked from wiibrew.org for "more information".  I clicked through and I think I based my code on this line on your site:

"rotation about the X axis is ((XX AND 0xFA)<<6) OR xx)"

I don't think I gave it a second thought.  Smile

GCSX
GCSX
8/10/2009 7:34:24 AM #

This is not my site ^^
I don't work with CWiid.
I've first tried with FC but had some glitch.
I've then heard for CWiid implementation, they uses FA, so I've tried...

GCSX
GCSX
8/10/2009 7:36:48 AM #

The code in the new beta is almost what I've done and works simillarely : I can rotate my 3D cube in all directions but if there still some glitch.

GCSX
GCSX
8/10/2009 7:42:20 AM #

The difference between my code and yours is that I implemented the Slow/Fast in the Extension parsing : when Fast, the value is almost x5.

Xevel
9/16/2009 9:05:57 PM #

Some progress has been made concerning the use of other extensions at the same time as the WMP :

www.assembla.com/.../Using_extensions_via_the_Motion_Plus

Ben
Ben
10/9/2009 10:06:46 AM #

Hi guys,

Looking for wii motion plus support for the pc. Just wondering whether anyone cracked it yet?

Thanks,
Ben.

Jeremy
11/1/2009 12:30:34 PM #

Here is what I have been trying and I seem to be getting decent results.  Hopefully someone that is a bit smarter can refine this technique.

Vector3 A = new Vector3(0,0,0);
//Use Calibration data to set X,Y,Z components                      
                                A.X = ws.MotionPlusState.RawValues.X - XCal;
                                A.Y = ws.MotionPlusState.RawValues.Y - YCal;
                                A.Z = ws.MotionPlusState.RawValues.Z - ZCal;
//Compensate for the different sensitivities
                                if (ws.MotionPlusState.RollFast)
                                {
                                    A.X = ((ws.MotionPlusState.RawValues.X) / 4);
                                }
                                else
                                {
                                    A.X = ((ws.MotionPlusState.RawValues.X) / 20);
                                }
                                if (ws.MotionPlusState.RollFast)
                                {
                                    A.Y = ((ws.MotionPlusState.RawValues.Y) / 4);
                                }
                                else
                                {
                                    A.Y = (ws.MotionPlusState.RawValues.Y / 20);
                                }
                                if (ws.MotionPlusState.RollFast)
                                {
                                    A.Z = (ws.MotionPlusState.RawValues.Z / 4);
                                }
                                else
                                {
                                    A.Z = (ws.MotionPlusState.RawValues.Z / 20);
                                }
                                //Convert to degrees per second
                                A.X *= .0155f;
                                A.Y *= .0155f;
                                A.Z *= .0155f;

                                //Implement simple low pass filter
                                    SavedAngle.X =(SavedAngle.X * .95f) + (A.X * .5f) ;
                                    SavedAngle.Y = (SavedAngle.Y * .95f) + (A.Y * .5f);
                                    SavedAngle.Z = (SavedAngle.Z * .95f) + (A.Z * .5f);
                                //Convert to radians without changing or savedangle values
                                A.X = MathHelper.ToRadians(SavedAngle.X);
                                A.Y = MathHelper.ToRadians(SavedAngle.Y);
                                A.Z = MathHelper.ToRadians(SavedAngle.Z);
                                
//create rotation matrix
                                Rotation = Quaternion.CreateFromYawPitchRoll(A.Y, A.X, A.Z);

Frank
Frank
2/24/2010 3:28:38 PM #

if (ws.MotionPlusState.RollFast)

Are you sure it's "Roll" for all X, Y, and Z. I would think it's Yaw for X, Pitch for Y and Roll for Z.

Frank
Frank
3/3/2010 2:15:33 PM #

One more comment about the:
RawValues.X = (buff[offset + 0] | (buff[offset + 3] & 0xfc) <<  6);

Should we not shift left 6 bit before OR with lower byte. So:

RawValues.X =  buff[offset + 0] | ((buff[offset + 3] & 0xfc) <<  6);  not:

RawValues.X = (buff[offset + 0] | (buff[offset + 3] & 0xfc) <<  6);

Since we want to move buff[offset + 3] up 6 bit before ORing with lower byte. We don't want to shift after the OR.

Brian Peek
Brian Peek
3/3/2010 2:17:26 PM #

@Frank, that's why it was a beta release.  Smile

Nathan
Nathan
10/28/2010 7:47:43 AM #

Hi Brian,

I'm not getting clear results from the battery reading from the Wii Balance Board. Seems to me that the percentage is almost always too high. Did you get somewhat accurate results, 'cause if not, maybe you could change this when you update the library? The wiimote battery check works fine, maybe it has something to do with the fact that the Wii Balance Board uses 4 batteries?

Greetings,

Nathan

Brian Peek
Brian Peek
10/29/2010 5:10:23 PM #

@Nathan, can't say I've ever noticed.  I've always found the battery results to be mostly inaccurate everywhere.  Not sure I have any way to fix it, unfortunately.

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

My Info

  • View Brian Peek's profile on LinkedIn

Sponsored Ad

My Book

Sponsored Ad

Calendar

<<  February 2012  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
2728291234
567891011

View posts in large calendar