Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 15:12 25 Nov 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : (*M) Wii Nunchuck Demo

Author Message
crackerjack

Senior Member

Joined: 11/07/2011
Location: Australia
Posts: 164
Posted: 11:26am 22 Feb 2012
Copy link to clipboard 
Print this post

Hi all,

After playing about with the Wii Nunchuck and Maximite for some time, I have put together a program which I believe demonstrates most of the capabilities of the Wii Nunchuck and the ease with which the device can be used as an interface to the Maximite. I expect that this code could be used with a Duinomite, but I have not tried it. My DM is currently a MM in disguise of 3.1; also the demo code assumes VGA use.

The code listing is included at the end of this post (for your reading pleasure) and also in an attached ZIP file should you want to try it out at home. A screengrab follows with some explanatory notes. The usual "this is free; and I accept no liability for anything you may do to yourself or anybody else, what you may break, or set on fire as a result of your use or abuse of this code, etc." clause applies.



2012-02-22_204336_wii_demo.zip

The code is necessarily a bit heavy on the Trigonometry side. This is because unlike previous code seen for the Maximite using the Wii, the values coming back from the accelerometer are not just displayed as raw values, but actually degrees of Roll and Pitch. A full 360 degrees of Roll is provided, and almost 180 degrees of Pitch. The Wii Nunchuck does not really have a useable Yaw axis, but the other two axes, the button states and the joystick values and position are shown visually in the demo. Also, the direction of the Joystick (rather than position, and which may be useful for some implementations such as games, etc.) is shown by arrows at the top and right edges of the Joystick "zone". Using dedicated fonts for these arrows instead of < > ^ and v ASCII characters would have been nice, but you get the idea....

Since the Maximite does not have a full suite of Inverse Trig. functions, two of these (ACOS and ATAN2) are implemented as Sub's. ATAN2 is of particular interest in this application because it is used to find direction (ATAN cannot be used for this purpose).

There are some constants used in the code which may vary between Nunchucks. I have three and there was little variation between them, but you may want to experiment.

To calibrate the Joystick, push both the C and Z buttons at once while leaving the Joystick in it's neutral position.

I believe a number of new and useful features of MMBasic 3.1 have been used: Call-able subroutines, the Print @ statement with modes, and so on...
Some immediate optimisation opportunites exist - for example the many Pi/180 and Pi*180 usages could be replaced by constants; there are others too.

There is an area of useless decorative display at the bottom of the screen to take up some space which was free (and who doesn't like taking something that's free?)

Lastly, parts of the code were based on an Arduino library for the Wii Nunchuck. Credits are given in the code and a reference to the original website is given. For the adventurous, you may want to try interfacing the Maxi via Serial to a PC running the Processing "RGB Cube" code which the Arduino library references. The appropriate code is in the demo, but commented out. I tried it out and it was pretty cool to spin a colourful cube image on my PC using a Nunchuck via my beloved Maximite.

There are posts elsewhere on this forum explaining how to wire up a Wii Nunchuck to a Maximite and where to obtain the devices for a pittance, etc.

Enjoy, improve and share.

crackerjack.


' Maximite Wii Nunchuck Demo - crackerjack 02/2012
'
' Credit to Tim Hirzel, Tod E. Kurt & Windmeadow Labs
' ...and the many others upon whose shoulders we stand.
'
' Based on, and adapted for MMBasic 3.1 from code at:
' http://arduino.cc/playground/Main/WiiChuckClass
' ------------------------------------------------------

' Constants - mainly for display
pdy=70 ' Pitch Dial Y
pdx=380 ' Pitch Dial X
rdy=170 ' Roll Dial Y
rdx=380 ' Roll Dial X
dr=49 ' Dial Radius
th=-55 ' Joystick Direction Threshold

Dim RDBuff(6) ' Wii Read Buffer

Cls
GoSub ScreenSetup

' Use the Serial output if using with the RGB Cube display as per above website
'Open "COM2:19200" As #1

i2cWii = &h52 ' Wii Nunchuck address
I2CEN 400, 100 ' Enable I2C
I2CSEND i2cWii, 0, 2, &hF0, &h55
I2CSEND i2cWii, 0, 2, &hFB, &h0

' Some constants (may vary for Nunchucks)
Zero_X = 510
Zero_Y = 490
Zero_Z = 500
Zero_Joy_X = 141 ' These are set by Calibration...
Zero_Joy_Y = 139 ' ...press the C & Z buttons together
Radius = 220

Timer = 0

' Main Loop
Do
timed = Timer
' Hello Nunchuck, tell me how ya doin'?
I2CSEND i2cWii, 0, 1, &h0
I2CRCV i2cWii, 0, 6, RDBuff(0)

' Calculations on the returned data
Joy_X = RDBuff(0) - Zero_Joy_X
Joy_Y = RDBuff(1) - Zero_Joy_Y
Joy_Left = (Joy_X < th)
Joy_Right = (Joy_X > Zero_Joy_X + th)
Joy_Down = (Joy_Y < th)
Joy_Up = (Joy_Y > Zero_Joy_Y + th)

' Not using full 10-bit resolution - just too noisy!
Acc_X=(RDBuff(2) * 4) - Zero_X
Acc_Y=(RDBuff(3) * 4) - Zero_Y
Acc_Z=(RDBuff(4) * 4) - Zero_Z

' Roll
If Acc_Z <> 0 Then
ATan2 (Acc_Z, Acc_X)
Roll=Fix(Atan2/Pi*180)
EndIf

' Using a Constant instead, but you may want to experiment
'Radius = Sqr(Acc_X^2 + Acc_Y^2 + Acc_Z^2)

' Pitch
Acos (Acc_Y / Radius)
Pitch = Fix((Acos)/Pi * 180)

' Buttons
Button_Z = Not((RDbuff(5) And &h01))
Button_C = Not((RDbuff(5) And &h02))

'Calibration
If Button_C And Button _Z Then
GoSub Calibrate
EndIf

' Serial data out
'Print #1 Roll "," Pitch "," ACC_X "," Acc_Y "," Acc_Z Chr$(13)

' Display all Current Values
' Buttons
Print @(rdx-18, rdy+102, Button_C*2) "C"
Print @(rdx+17, rdy+102, Button_Z*2) "Z"

' Pitch & Roll
Line(pdx,pdy)-(pdx+dr*(Cos(Pitch*(Pi/180))),pdy-dr*(Sin(Pitc h*(Pi/180)))),1
Line(rdx,rdy)-(rdx+dr*(Cos(Roll*(Pi/180))),rdy-dr*(Sin(Roll* (Pi/180)))),1
Print @(pdx-15,pdy+10) Format$(Pitch, "%4.0f")
Print @(rdx-15,rdy+dr+10) Format$(Roll, "%4.0f")

' Joystick, first show direction. Some font usage would be better...
Print @(4,275,Joy_Left*5) "<": Print @(268,275,Joy_Right*5) ">"
Print @(277,4,Joy_Up*5) "^" : Print @(277,265,Joy_Down*5) "v"
' Now show positionn and values
Print @(120,275) "X:" Format$(Joy_X, "%4.0f")
Print @(180,275) "Y:" Format$(Joy_Y, "%4.0f")
Circle(Zero_Joy_X+Joy_X+10,Zero_Joy_Y-Joy_Y-10),2,1,F

' Send Serial
'Print #1, Roll "," Pitch "," Acc_X "," Acc_Y "," Acc_Z

' Give the Wii Nunchuck some time before we go around again
Timed = Timer - timed
Max (100, timed)
Pause Max

' Cleanup
Line(pdx,pdy)-(pdx+dr*(Cos(Pitch*(Pi/180))),pdy-dr*(Sin(Pitc h*(Pi/180)))),0
Line(rdx,rdy)-(rdx+dr*(Cos(Roll*(Pi/180))),rdy-dr*(Sin(Roll* (Pi/180)))),0
Circle(Zero_Joy_X+Joy_X+10,Zero_Joy_Y-Joy_Y-10),2,0,F

Loop

Close #1 ' Code execution can never get here, but best to be neat.

' ROUTINES
' ------------------------------------------------------

' Setup the Display
' -----------------
ScreenSetup:
Font 2,1,1
Print @(0,345) " Wii Nunchuck Demo "
Font 1,1,0
v=1
For t=1 To 11
Line(0,364+v)-(MM.HRes,364+v),1
v=v * 1.5
Next t

' Buttons
Print @(rdx-17,rdy+85) "Buttons"
Line(rdx-20,rdy+100)-(rdx-11,rdy+115),1,b
Line(rdx+15,rdy+100)-(rdx+24,rdy+115),1,b

' Joystick Zone
Print @(50,275) "Joystick"
Line(3,3)-(272,272),1,b
Line(5,5)-(270,270),1,b

' Pitch Dial
Print @(pdx-15,pdy-dr-17) "Pitch"
Circle(pdx,pdy),dr+1,1
For t=Pi/2 To (Pi*2-(Pi/2)) Step Pi/6
tx=Sin(t) : ty=Cos(t)
Line(pdx+tx*(dr+1),pdy+ty*(dr+1))-(pdx+tx*(dr+5),pdy+ty*(dr+ 5))
Next t
Line(pdx-dr-1,pdy+1)-(pdx+dr+1,pdy+dr+1),0,BF
Line(pdx-dr,pdy+1)-(pdx+dr,pdy+1),1
Print @(pdx-dr-15,pdy) "B"
Print @(pdx+dr+10,pdy) "F"
Print @(pdx+10,pdy+5) "o"

' Roll Dial
Print @(rdx-11,rdy-dr-17) "Roll"
Circle(rdx,rdy),dr+1,1
For t=Pi To Pi*4 Step Pi/6
tx=Sin(t) : ty=Cos(t)
Line(rdx+tx*(dr+1),rdy+ty*(dr+1))-(rdx+tx*(dr+5),rdy+ty*(dr+ 5))
Next t
Print @(rdx-dr-15,rdy) "L"
Print @(rdx+dr+10,rdy) "R"
Print @(rdx+10,rdy+dr+5) "o"

Return

' Calibrate the Joystick
' ----------------------
Calibrate:
Zero_Joy_X = RDBuff(0)
Zero_Joy_Y = RDBuff(1)
Print @(200,407) "Calibrating..."

' Redraw the screen, in case we have messed it up with uncalibrated movements
GoSub ScreenSetup
Print @(200,407) " "

Return

' SUBS
' ====

' Calculate ACOS
' --------------
Sub Acos(y)
If Fix(y) = 1 Then
Acos = 0
ElseIf Fix(y) = -1 Or Sgn(-y * y + 1) = -1 Then
Acos = Pi
Else
Acos = Atn(-Y / Sqr(-y * y + 1)) + 2 * Atn(1)
EndIf
End Sub

' Calculate ATAN2
' ---------------
Sub Atan2(y, x)
Atan2=2*Atn(y/(Sqr(x^2+y^2)+x))
End Sub

' Max
' ---
Sub Max(a, b)
If a > b Then
Max = a
Else
Max = b
EndIf
End Sub

Edited by crackerjack 2012-02-23
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3194
Posted: 10:22am 24 Feb 2012
Copy link to clipboard 
Print this post

This is getting better and better. My Nunchuck arrived today and against wise advice I am going to hack off the connector and solder it in, just so I can try this ASAP.

BTW. 3.2 will have functions that will work very much like the way that you used subroutines.
So, with 3.2, you will be able to do:
Roll = Fix(ATan2(Acc_Z, Acc_X)/Pi*180)
...
Function Atan2(y, x)
Atan2 = 2*Atn(y/(Sqr(x^2+y^2)+x))
End Function


Thanks for a great demo,
Geoff

P.S. Does anyone know why are they called Nunchucks?
Geoff Graham - http://geoffg.net
 
Olimex
Senior Member

Joined: 02/10/2011
Location: Bulgaria
Posts: 226
Posted: 10:57am 24 Feb 2012
Copy link to clipboard 
Print this post

http://en.wikipedia.org/wiki/Nunchaku

don't tell me you never have seen Bruce Lee movie

Edited by Olimex 2012-02-25
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3194
Posted: 01:50pm 24 Feb 2012
Copy link to clipboard 
Print this post

My education is obviously lacking. That is an effective weapon, by my rough count he took out 25 bad guys with it.
Geoff Graham - http://geoffg.net
 
rodent59
Newbie

Joined: 02/03/2012
Location: Australia
Posts: 7
Posted: 10:10am 03 Mar 2012
Copy link to clipboard 
Print this post

Hi Crackerjack

Thanks for the code and ideas. I'd like to understand how your Defined Subroutines work please. I refer to the ATan2 and Acos subs. You define subs by those names. When called they create a variable with the same name as the sub name, and you then assign your result to that variable.

My question is: When you then use that variable (e.g. Roll=Fix(Atan2/Pi*180)), how does the interpreter know you are referring to the variable rather than the same-named sub used without any arguements? Is it that a sub call must always be a separate line (not embedded) and Roll=Fix(Atan2/Pi*180), when parsed, simply cannot refer to anything but the variable by that name?

Many thanks,
Rod.

******************

' Roll
If Acc_Z <> 0 Then
ATan2 (Acc_Z, Acc_X)
Roll=Fix(Atan2/Pi*180)
EndIf
' Pitch
Acos (Acc_Y / Radius)
Pitch = Fix((Acos)/Pi * 180)

' Calculate ACOS
' --------------
Sub Acos(y)
If Fix(y) = 1 Then
Acos = 0
ElseIf Fix(y) = -1 Or Sgn(-y * y + 1) = -1 Then
Acos = Pi
Else
Acos = Atn(-Y / Sqr(-y * y + 1)) + 2 * Atn(1)
EndIf
End Sub

' Calculate ATAN2
' ---------------
Sub Atan2(y, x)
Atan2=2*Atn(y/(Sqr(x^2+y^2)+x))
End Sub

' Max
' ---
Sub Max(a, b)
If a > b Then
Max = a
Else
Max = b
EndIf
End Sub
 
crackerjack

Senior Member

Joined: 11/07/2011
Location: Australia
Posts: 164
Posted: 11:04am 03 Mar 2012
Copy link to clipboard 
Print this post

Hi Rod,

I guess I used a little bit if license in my usage of defined Sub's and variable names to make things more resemble what Geoff has indicated is coming in 3.2

The way it works is (using ATan2 as an example):

The variable ATan2 is first used in the Sub of the same name and is by default a Global variable. After a call is made to the sub - the interpreter identifies it as a call to a sub by the following space and left bracket - the variable now holds the value which is then used as per normal (without a space and left bracket following, so the interpreter knows it is just a variable not a Sub call). Hope that makes sense.

I suspect things will be more simple in the next version of MMBasic.

Cheers. Edited by crackerjack 2012-03-04
 
rodent59
Newbie

Joined: 02/03/2012
Location: Australia
Posts: 7
Posted: 01:29pm 03 Mar 2012
Copy link to clipboard 
Print this post

Thanks Crackerjack. All understood.
Rod.
 
Nick

Guru

Joined: 09/06/2011
Location: Australia
Posts: 512
Posted: 10:15pm 12 Mar 2012
Copy link to clipboard 
Print this post

I have my Wii Nunchuck ($4 at Cash Converters) and I've decided to chop the plug and wire it directly to the port connector.

Which of the 4 wires go where?

There is a red, yellow, white and green (+ gold for earth).

Reading Geoff's manual, I2c uses pins 12 and 13?

Anyone directly wired one of these to tell me which colours go where?
 
crackerjack

Senior Member

Joined: 11/07/2011
Location: Australia
Posts: 164
Posted: 11:53pm 12 Mar 2012
Copy link to clipboard 
Print this post

Nick - see this post: http://www.thebackshed.com/forum/forum_posts.asp?TID=4312 which has the details and links that will help you.
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024