NXT & LeJOS & Wii Nunchuck


the NXT controller, the Wii Nunchuck and the adapter

Finally !

It’s been a while since I first thought about trying LeJOS, the JVM for NXT… I don’t recall why I didn’t do it when I first bought the NXT set, more than 2 years ago…

The thing is that, after some frustration with the URBI NXT installation (very nice project, but somehow didn’t manage to make the latest version work…) I felt that I had to do something “new” with the NXT… and I must admit that I’m so pleased with the simplicity and power of the LeJOS JVM that it feels like a pity I didn’t install it earlier !

The installation is quite straight forward, you need to install stuff on your PC and flash the NXT to replace the original firmware (no worries it can be flashed back to the initial state).

It’s also great that the bluetooth communication works “out of the box” so no more wires to program your box and communicate with it !

First project: interact with a Wii Nunchuck

This is famously easy to communicate with as it’s using the I2C protocol, but the tricky bit is that you need to slightly physically alter the nunchuck, as the NXT can’t take the I2C lines down, due to the pull-up resistors inside the nunchuck being to low (R1 and R2 are 1.8KOhms rather than the 82KOhms recommended by the NXT specifications).

Here’s a link nicely describing the hack (it’s in German, but the pictures are quite straight forward 🙂 )

Now my approach was much simpler

  1. get rid of the SMD R1 and R2
  2. put back the nunchuck without anything else
  3. add 100KOhms pull-up resistors directly on the cables (where the nunchuck interfaces with the NXT cable) – I didn’t have 33KO ones, and 100 is closer anyway to the NXT specs
  4. no diode as I didn’t have any, and was already using the nunchuck with a 5V Arduino… hope it won’t damage it too quickly 🙂

And here’s the Java module, please feel free to re-use it in your programs

import lejos.nxt.I2CPort;
import lejos.nxt.I2CSensor;

/**
* https://trandi.wordpress.com
*/

public class WiiNunchuck extends I2CSensor {

private static final int NUNCHUCK_ADDR = 0x52; // 7bit addressing.  It would be 0xA4 in 8bit
private static final int NUNCHUCK_MEM_ADDR = 0x40;

// array to store RAW nunchuck data
private byte[] _buff = new byte[6];
private byte[] _initBuff = new byte[2];
private int joy_x_axis;
private int joy_y_axis;
private int accel_x_axis;
private int accel_y_axis;
private int accel_z_axis;
private boolean z_button = false;
private boolean c_button = false;
public WiiNunchuck(I2CPort port){
super(port);
setAddress(NUNCHUCK_ADDR);
}

public boolean updateData() {
// ??? somehow it gets disabled....
getPort().i2cEnable(I2CPort.LEGO_MODE);

// INITIALIZE - tell the nunchuck we're talking to it
_initBuff[0] = 0x00;

sendData(NUNCHUCK_MEM_ADDR, _initBuff, 1);
try{ Thread.sleep(10);}catch(InterruptedException e){}

// send a request for data
sendData(0x00, (byte)0x00);

if(getData(0x00, _buff, 6) != 0) return false;

try{ Thread.sleep(10);}catch(InterruptedException e){}

for(int i = 0; i < 6; i++) _buff[i] = nunchuk_decode_byte(_buff[i]);

// transform into something meaningful
joy_x_axis = _buff[0];
joy_y_axis = _buff[1];
accel_x_axis = _buff[2];
accel_y_axis = _buff[3];
accel_z_axis = _buff[4];

// byte nunchuck_buf[5] contains bits for z and c buttons
z_button = (_buff[5] & 0x01) == 0;
c_button = (_buff[5] & 0x02) == 0;

// it also contains the least significant bits for the accelerometer data so we have to check each bit of byte outbuf[5]
if ((_buff[5] & 0x03) > 0) accel_x_axis += 2;
if ((_buff[5] & 0x04) > 0) accel_x_axis += 1;
if ((_buff[5] & 0x05) > 0) accel_y_axis += 2;
if ((_buff[5] & 0x06) > 0) accel_y_axis += 1;
if ((_buff[5] & 0x07) > 0) accel_z_axis += 2;
if ((_buff[5] & 0x08) > 0) accel_z_axis += 1;
joy_x_axis = updateRange(joy_x_axis);
joy_y_axis = updateRange(joy_y_axis);
accel_x_axis = updateRange(accel_x_axis);
accel_y_axis = updateRange(accel_y_axis);
accel_z_axis = updateRange(accel_z_axis);

return true;
}

/**
* Transforms a 0..127 -128 .. 0 range into a 128..0..-128 one
*/

private static int updateRange(int init){
int result = init;
boolean negative = result < 0;
if(negative) result = -result;
result = - result + 128;
if(negative) result = -result;
return result;
}

// Encode data to format that most wiimote drivers except only needed if you use one of the regular wiimote drivers
private static byte nunchuk_decode_byte (byte x){
return (byte)((x ^ 0x17) + 0x17);
}

public int getAccelX() {
return accel_x_axis;
}

public int getAccelY() {
return accel_y_axis;
}

public int getAccelZ() {
return accel_z_axis;
}

public int getJoyX() {
return joy_x_axis;
}

public int getJoyY() {
return joy_y_axis;
}

public boolean isC_button() {
return c_button;
}

public boolean isZ_button() {
return z_button;
}

}

It feels so good now that I can leverage the power of Java to program it… no more awkward syntax or C-like string manipulation… it’s comparable to the pleasure of programming the FEZ Domino, but even better as I’m really a Java guy and feel much more comfortable with it than with C#.

16 Responses to NXT & LeJOS & Wii Nunchuck

  1. Pingback: RC Car Electronics | Robotics / Electronics / Physical Computing

  2. Benny says:

    Hi~ I made a Nunchuk Sensor for my nxt.
    And I used your class code,but it’s not work…
    I put my main.java and your WiiNunchuck.java in same folder…
    I enter nxjc Test.java nxj Test
    But it isn’t work on the nxt.
    Where is wrong?
    Request your assistance!
    My main.java
    import lejos.nxt.*;

    public class Test {

    public static void main(String args[]){
    WiiNunchuck nunchuk = new WiiNunchuck(SensorPort.S1);
    nunchuk.updateData();
    while(!Button.ESCAPE.isPressed()){
    LCD.drawInt(nunchuk.getAccelX(),0,0);
    LCD.drawInt(nunchuk.getAccelY(),0,1);
    LCD.drawInt(nunchuk.getAccelZ(),0,2);
    LCD.drawInt(nunchuk.getJoyX(),0,3);
    LCD.drawInt(nunchuk.getJoyY(),0,4);
    LCD.refresh();
    try {
    Thread.sleep(10);
    }catch (InterruptedException e) {}
    }
    }
    }

    • trandi says:

      It’s notoriously hard to find a problem like this remotely, without having more concrete details about your exact set up….

      The test code looks ok, and it’s simple enough.
      If you are using my EXACT WiiNunchuck.java class, do you have LeJOS installed properly on your NXT ? Can you run other java programs ?

      Also, have you physically altered your nunchuck to remove the 2 1.8kOhms resistors as described in the post:

      This is famously easy to communicate with as it’s using the I2C protocol, but the tricky bit is that you need to slightly physically alter the nunchuck, as the NXT can’t take the I2C lines down, due to the pull-up resistors inside the nunchuck being to low (R1 and R2 are 1.8KOhms rather than the 82KOhms recommended by the NXT specifications
      ” ?

      Hope this helps,
      dan

      • Benny says:

        Yes! I can run other java programs on nxt .
        And I change 2 1.8k resistors to 33k.
        But I use nxc of the http://www.mindstormsforum.de/viewtopic.php?t=3828 (tom123) ,it work!
        But I want to use lejos…
        (I need to change 2 1.8k resistors to 100k?? I already change these to 33k…)
        Thank!

      • trandi says:

        Ok, so you’re saying that:

        – LeJOS is installed properly, you can run other Java programs – the nunchuck works ok, as you can get data from it with the nxc example…

        That’s strange…

        I’m using 100K resistors indeed, and I think in the specs the NXT needs 82K or something like that… IF the nunchuck works with your NXC program, then it should work with Java too, regardless of what resistors you’re using… it’s the same physical stuff…

        Here’s my test class, it’s almost identical with your test example… have a look to see if there’s not some silly mistake in there:

        import lejos.nxt.*; import lejos.nxt.addon.*;

        public class WiiNunchuckTest { private final WiiNunchuck _nunchuck = new WiiNunchuck(SensorPort.S4); private final Motor _motor = new Motor(MotorPort.A);

        private void loop() throws InterruptedException{ if(! _nunchuck.updateData()) throw new IllegalStateException(“errg…”); int deg = _nunchuck.getJoyX(); int newDeg = 0; while (!Button.ESCAPE.isPressed()) { _nunchuck.updateData(); display(_nunchuck); newDeg = _nunchuck.getJoyX(); if(Math.abs(newDeg – deg) > 3){ _motor.rotate(newDeg – deg); deg = newDeg; } Thread.sleep(20); } }

        private void display(WiiNunchuck nunchuck) throws InterruptedException{ LCD.clear(); LCD.drawString(“OK”, 0, 0); LCD.drawInt(nunchuck.getJoyX(), 0, 1); LCD.drawInt(nunchuck.getJoyY(), 10, 1); LCD.drawInt(nunchuck.getAccelX(), 0, 3); LCD.drawInt(nunchuck.getAccelY(), 6, 3); LCD.drawInt(nunchuck.getAccelZ(), 12, 3); LCD.drawString(String.valueOf(nunchuck.isC_button()), 0, 5); LCD.drawString(String.valueOf(nunchuck.isZ_button()), 7, 5); LCD.refresh(); }

        public static void main(String[] args) throws Exception { new WiiNunchuckTest().loop(); } }

        dan

      • Benny says:

        I test your code,and I get this error…

        Exception:31
        errg&
        at:66(17)
        at:68(8)

        Where is wrong?
        Thank!

      • Benny says:

        And I found the java compiled your WiiNunchuck.java ,it told me…

        Note: .\WiiNunchuck.java uses or overrides a deprecated API.
        Note: Recompile with -Xlint:deprecation for details.

        Whether it is an old version of java??

        I use Java 7 (jdk7)

        Thanks!

        Benny.

      • trandi says:

        I think I remember this warning and it was still working despite it… ( I was indeed using Java 1.6 but it shouldn’t make any difference)

        But to be honest, it’s been a while since I did that test and I don’t have the computer / NXT set up right now to test it…

        Let me know if you finally find the problem, I’d be interested to know / update my post.

        dan

  3. Mac says:

    I want to get the Nunchuck value and show it on the LCD…
    like this
    “Z : RELEAZED” or “Z : PRESSED”
    “C: RELEAZED” or “C : PRESSED”
    “accel_x: “value””
    “accel_y: “value””
    “accel_z: “value””
    “joy_x: “value””
    “joy_y: “value””
    Could you post all code?? Please…

  4. Mac says:

    May I ask you a question?
    This web :
    http://lejos.sourceforge.net/forum/viewtopic.php?f=6&t=1457&p=13839&hilit=Wii+Nunchuk+Sensor&sid=a7dd4db8fe07a99e6ee83cbec6473ff4#p13839

    In the web two codes . How can I link the two codes? A+B?? A(del something) +B?? or A+B(del something)??

    How can I link?

    I just want to show the Nunchuck Button C,Z , Accel x,y,z and Joystick x,y on the LCD!!

    Please attach complete code. Please help me…

    thank lot!!!

    • trandi says:

      I’m not sure I understand your question…
      Also requests like “Please attach complete code” sound like if you had some entitlement …
      I try to answer as quickly and as accurately as I can to all the questions, but I’m not paid to be writing the exact code you are looking for !

      Dan

  5. Mac says:

    Sorry !! I mean

    (R1,R2 is 1.8k , == is 32k)
    (NXT Green)─==────┬──┬───(Nunchuck Red)
              R1 R2
    (NXT Yellow)──────-┴──┼──(Nunchuck Yellow) (33.8k)
    (NXT Blue)──────────-┴──(Nunchuck Green) (33.8k)
    (NXT Red)──────────────(Nunchuck White)

    Can I do this ???

  6. Mac says:

    A question, I real have to get rid of the SMD R1 and R2 ?

    Maybe I can put a 32K resistor on the “NXT Green -> Nunchuck Red ” this line?

    like this ↓ (R1,R2 is 1.8k , — is 32k)

    (NXT Green)──–────┬──┬───(Nunchuck Red)
    R1┤ ├ R2
    (NXT Yellow)───────┴──┼──(Nunchuck Yellow) (33.8k)
    (NXT Blue) ──────────┴──(Nunchuck Green) (33.8k)
    (NXT Red) ─────────────(Nunchuck White)

    Can I do this ???

    • trandi says:

      I’m afraid not !
      The problem with R1 and R2 are that they are too LOW. By putting resistors in parallel you can ONLY LOWER the total resitance… the only way to increase it is by putting resistors in series… which you obviously can’t do without de-soldering R1/R2.

      Dan

  7. Pingback: Android IOIO Wii Nunchuck « Robotics / Electronics / Physical Computing

  8. Pingback: Wii motion plus and Arduino « Robotics / Electronics / Physical Computing

Leave a comment