Pages: [1] 2 3 ... 11   Go Down
Author Topic: Read wireless Wii Nunchuck with Arduino  (Read 24610 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am trying to use an Arduino to read a wireless Wii Nunchuck.

I have already used the code at the top of this page....
(As this is my first post I am not allowed embed links so Google “read wireless nunchuck into arduino” and it is the first hit)

..... to read a WIRED Nunchuck, which I am using as a hand-controller for my self-balancing skateboard.
(again, Google “one wheeled self balancing skateboard project” and I am the second hit)

Clearly it would be excellent if I could make this wireless.
Some have used a pair of Arduinos with Xbee transmitters to create the wireless link. This seems clumsy when there is at least one person out there who has interfaced the receiver of a wireless Nunchuck to the Arduino directly.

I have been using the code version of Michael Dreher (see his code halfway down the first webpage I mentioned above) with a wireless Nunchuck and Arduino17 with ATMega328 based board. He seems to be only person on net who has made this work.

When I power up the board I get one set of good readings and then everything stops. If I move the chuck and reset the Arduino board I get another set of different and believable data then it stops again after one line of data.

This is very frustrating as obviously this is very nearly working. I know others have described this problem, has anyone ever figured out how to fix it?

I have even bought a Blazepro wireless Nunchuck from Hong Kong as this was the exact model Michael Dreher got to work (there are several manufacturers – none are made by Nintendo). This has exactly the same problem, one data set in serial view window then it stops. Incidentally it works like this whether you set TWI speed to 100K, 200K or the recommended 400K. I note that MD was using an older Arduino board and older version of software.

Can anyone help?
I would have thought a cheap stylish ergonomic short range wireless hand controller like this would be so great for many Arduino projects apart from mine.

John
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 186
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi XenonJohn,

I tried the sketch I posted on http://www.windmeadow.com/node/42#comment-28 today with Arduino 17 and the Arduino-BT (115200 baud) and my wireless BlazePro nunchuck. For connecting the transceiver, I used the wiichuck adapter (the BlazePro Logo and LED must face upwards).

Everything works fine and I get the following output:
Code:
Ident=0 0 A4 20 0 0
Finished setup
128     119     695     537     515     1       1
128     119     693     539     515     1       1
128     119     693     537     513     1       1
128     119     695     539     512     1       1
128     119     693     539     513     1       1
128     119     695     537     513     1       1
128     119     695     539     513     1       1
...

When I change then function send_zero(), especially the loop count "i < 3" to "i < 1", it doesn't work at all and I don't know why.

How do your nunchuck LEDs look like? To start press the Z-button of the controller to turn it on, then the LED of the controller should blink. After powering up and starting the sketch,  the LED of the transceiver should also start to blink. After the two have connected, they should both light steadily.

Are you using the unmodified posted sketch?

Could you try this slightly changed version which only reads one value every three seconds and outputs some debugging information in between?

The output should look like this:
Code:
Ident=0 0 A4 20 0 0
Finished setup
avail=0  cnt=6
128     127     424     413     368     1       1
avail=0  cnt=6
128     127     561     296     531     1       1
avail=0  cnt=6
128     127     472     550     706     1       1
avail=0  cnt=6

Code:
// read out a Wii Nunchuck controller
// adapted to work with wireless Nunchuck controllers of third party vendors by Michael Dreher <michael@5dot1.de>

// adapt to your hardware config
#define POWER_VIA_PORT_C2_C3 1    // use port pins port C2 and C3 as power supply of the Nunchuck (direct plug using wiichuck adapter)
#define DEBUG_RCV_TEL 1

#define USE_NEW_WAY_INIT 1        // use "The New Way" of initialization <http://wiibrew.org/wiki/Wiimote#The_New_Way>
#define WII_IDENT_LEN ((byte)6)
#define WII_TELEGRAM_LEN ((byte)6)
#define WII_NUNCHUCK_TWI_ADR ((byte)0x52)

#include <Wire.h>
#include <string.h>
#include <utility\twi.h>
#undef int
#include <stdio.h>

uint8_t outbuf[WII_TELEGRAM_LEN];            // array to store arduino output
int cnt = 0;
int ledPin = 13;

void setup ()
{
  Serial.begin (115200);

#ifdef POWER_VIA_PORT_C2_C3    // power supply of the Nunchuck via port C2 and C3
  PORTC &=~ _BV(PORTC2);
  PORTC |=  _BV(PORTC3);
  DDRC |= _BV(PORTC2) | _BV(PORTC3);  // make outputs
  delay(100);  // wait for things to stabilize
#endif

  Wire.begin(); // initialize i2c
  // we need to switch the TWI speed, because the nunchuck uses Fast-TWI
  // normally set in hardware\libraries\Wire\utility\twi.c twi_init()
  // this is the way of doing it without modifying the original files
#define TWI_FREQ_NUNCHUCK 400000L
  TWBR = ((CPU_FREQ / TWI_FREQ_NUNCHUCK) - 16) / 2;

  nunchuck_init(0); // send the initialization handshake

  // display the identification bytes, must be "00 00 A4 20 00 00" for the Nunchuck
  byte i;
  if(readControllerIdent(outbuf) == 0)
  {
    Serial.print("Ident=");
    for (i = 0; i < WII_TELEGRAM_LEN; i++)
    {
      Serial.print(outbuf[i], HEX);
      Serial.print(' ');
    }
    Serial.println();
  }

  Serial.println("Finished setup");
}

// params:
//   timeout: abort when timeout (in ms) expires, 0 for unlimited timeout
//   return:  0 == ok, 1 == timeout
byte nunchuck_init (unsigned short timeout)
{
  byte rc = 1;

#ifndef USE_NEW_WAY_INIT
  // look at <http://wiibrew.org/wiki/Wiimote#The_Old_Way> at "The Old Way"
  Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR);      // transmit to device 0x52
  Wire.send (0x40);            // sends memory address
  Wire.send (0x00);            // sends sent a zero.  
  Wire.endTransmission ();      // stop transmitting
#else
  // disable encryption
  // look at <http://wiibrew.org/wiki/Wiimote#The_New_Way> at "The New Way"

  unsigned long time = millis();
  do
  {
    Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR);      // transmit to device 0x52
    Wire.send (0xF0);            // sends memory address
    Wire.send (0x55);            // sends data.  
    if(Wire.endTransmission() == 0) // stop transmitting
    {
      Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR);      // transmit to device 0x52
      Wire.send (0xFB);            // sends memory address
      Wire.send (0x00);            // sends sent a zero.  
      if(Wire.endTransmission () == 0)      // stop transmitting
      {
        rc = 0;
      }
    }
  }
  while (rc != 0 && (!timeout || ((millis() - time) < timeout)));
#endif

  return rc;
}


// params:
//   ident [out]: pointer to buffer where 6 bytes of identification is stored. Buffer must be at least 6 bytes long.
//                A list of possible identifications can be found here: <http://wiibrew.org/wiki/Wiimote#The_New_Way>
//   return:  0 == ok, 1 == error
byte readControllerIdent(byte* pIdent)
{
  byte rc = 1;

  // read identification
  Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR);      // transmit to device 0x52
  Wire.send (0xFA);            // sends memory address of ident in controller
  if(Wire.endTransmission () == 0)      // stop transmitting
  {
    byte i;
    Wire.requestFrom (WII_NUNCHUCK_TWI_ADR, WII_TELEGRAM_LEN);      // request data from nunchuck
    for (i = 0; (i < WII_TELEGRAM_LEN) && Wire.available (); i++)
    {
      pIdent[i] = Wire.receive();      // receive byte as an integer
    }
    if(i == WII_TELEGRAM_LEN)
    {
      rc = 0;
    }
  }
  return rc;
}

void clearTwiInputBuffer(void)
{
  // clear the receive buffer from any partial data
  while( Wire.available ())
    Wire.receive ();
}


void send_zero ()
{
  // I don't know why, but it only works correct when doing this exactly 3 times
  // otherwise only each 3rd call reads data from the controller (cnt will be 0 the other times)
  for(byte i = 0; i < 3; i++)
  {
    Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR);      // transmit to device 0x52
    Wire.send (0x00);            // sends one byte
    Wire.endTransmission ();      // stop transmitting
    //delay(1);
  }
}

void loop ()
{
  delay (1000);
  send_zero (); // send the request for next bytes
  Wire.requestFrom (WII_NUNCHUCK_TWI_ADR, WII_TELEGRAM_LEN);      // request data from nunchuck

  for (cnt = 0; (cnt < WII_TELEGRAM_LEN) && Wire.available (); cnt++)
  {
    outbuf[cnt] = nunchuk_decode_byte (Wire.receive ());      // receive byte as an integer
    digitalWrite (ledPin, HIGH);      // sets the LED on
  }

  // debugging
#ifdef DEBUG_RCV_TEL
  Serial.print("avail=");
  Serial.print(Wire.available(), DEC);
  Serial.print("  cnt=");
  Serial.println(cnt, DEC);
#endif

  clearTwiInputBuffer();

  // If we recieved the 6 bytes, then go print them
  if (cnt >= WII_TELEGRAM_LEN)
  {
    print ();
  }

}

// Print the input data we have recieved
// accel data is 10 bits long
// so we read 8 bits, then we have to add
// on the last 2 bits.  That is why I
// multiply them by 2 * 2
void print ()
{
  int joy_x_axis = outbuf[0];
  int joy_y_axis = outbuf[1];
  int accel_x_axis = outbuf[2] * 2 * 2;
  int accel_y_axis = outbuf[3] * 2 * 2;
  int accel_z_axis = outbuf[4] * 2 * 2;

  int z_button = 0;
  int c_button = 0;

  // byte outbuf[5] contains bits for z and c buttons
  // it also contains the least significant bits for the accelerometer data
  // so we have to check each bit of byte outbuf[5]
  if ((outbuf[5] >> 0) & 1)
  {
    z_button = 1;
  }
  if ((outbuf[5] >> 1) & 1)
  {
    c_button = 1;
  }

  if ((outbuf[5] >> 2) & 1)
  {
    accel_x_axis += 2;
  }
  if ((outbuf[5] >> 3) & 1)
  {
    accel_x_axis += 1;
  }

  if ((outbuf[5] >> 4) & 1)
  {
    accel_y_axis += 2;
  }
  if ((outbuf[5] >> 5) & 1)
  {
    accel_y_axis += 1;
  }

  if ((outbuf[5] >> 6) & 1)
  {
    accel_z_axis += 2;
  }
  if ((outbuf[5] >> 7) & 1)
  {
    accel_z_axis += 1;
  }

  Serial.print (joy_x_axis, DEC);
  Serial.print ("\t");

  Serial.print (joy_y_axis, DEC);
  Serial.print ("\t");

  Serial.print (accel_x_axis, DEC);
  Serial.print ("\t");

  Serial.print (accel_y_axis, DEC);
  Serial.print ("\t");

  Serial.print (accel_z_axis, DEC);
  Serial.print ("\t");

  Serial.print (z_button, DEC);
  Serial.print ("\t");

  Serial.print (c_button, DEC);
  Serial.print ("\t");

  Serial.print ("\r\n");
}

// Decode data format that original Nunchuck uses with old init sequence. This never worked with
// other controllers (e.g. wireless Nunchuck from other vendors)
char nunchuk_decode_byte (char x)
{
#ifndef USE_NEW_WAY_INIT
  x = (x ^ 0x17) + 0x17;
#endif
  return x;
}

  MikeT
« Last Edit: November 25, 2009, 06:10:57 pm by nospam2000 » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Dear Mike,

Thanks very much for trying to help me:

Slight progress, sort of....
The problem seems to be with:
void send_zero

Wherever I put this in the void_loop, it stops the program sending anything more to serial view window at that point.

In your original code on windmeadow, the first time send_zero ();  appeared was at the end of the void loop ()

Therefore after setup, the very first time the void loop runs no send_zero command is sent to nunchuck and you do get one row of good data as in your example. However everything then stops.

In your latest code example you have just sent, the send_zero (); has been moved to the beginning of the void loop() and when I run this it is actually worse, I get as far as "Finished Setup", then not even one row of data - it just stops.

If I move send_zero back to the end of the void loop and instead of making it send zero 3 times, I change it back to one time, I do then get a series of rows of data down the serial window, i.e. the void loop is now at least running without locking up.
The problem now though is that only the very first row of data means anything, the subsequent rows are all rubbish data  (0, 255 or 1023).

During all these variations the Nunchuck connects quite easily.
My other wireless nunchuck performs exactly the same way incidentally.

The only thing left I can change so my setup is exactly as you have is to not use an Arduino with ATmega328 but use one with an ATmega168 processor as your Arduino BT has a 168 processor. At least it is good to know that it works with you with Arduino 17.

In summary:

A) send_zero() at start of the void loop:
Ident      0      A4      20      0      0
Finished setup

STOPS at this point


B) send_zero (X3) at end of void loop:
Ident      0      A4      20      0      0
Finished setup
avail=0      cnt=6
128      127      707      515      568      1      1

STOPS at this point

C) send_zero (sent just once, not 3 times) at end of void loop:
Ident      0      A4      20      0      0
Finished setup
avail=0      cnt=6
128      127      707      515      568      1      1
After first line of good data it then continues as...
avail=0      cnt=6
255      255      1023      1023      1023      1      1
avail=0      cnt=6
255      255      1023      1023      1023      1      1
And so on, at least it keeps going.



The only other person with code that works with a wireless chuck (based on your post) is B Giessler and his code is here:

http://giesler.biz/~bjoern/downloads/r2d2/R2D2.zip

This is to control his R2D2 robot however. He seems to have written his own libraries as well for many other functions of the robot, so to be honest I find his code and all the libraries it needs to work even more confusing. It might just contain some clues however that a better programmer than I might just understand.

Is there any way some of the setup routine could go into the void loop so in effect the connection is repeatedly reset to get the initial one line of "good" data each time the void loop cycles? This would avoid "send zero" altogether - unpleasant but maybe that might work?

Thanks for your help so far,

John
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 186
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi XenonJohn,

Your description means, that the i2c communication hangs. Do you have any other i2c hardware connected?

Code:
avail=0      cnt=6
This is the normal case: 6 bytes have been requested from the i2c device, 6 bytes have been received and nothing is left in the receive buffer.

Quote
The only other person with code that works with a wireless chuck (based on your post) is B Giessler

I really like his code, its cleanly written and I recommend to use it instead of the one I hacked. The intention of my code was just to demonstrate how to initialize the nunchuck using the "new way" initialization sequence.

When I finish a new sketch, based on his code, I'll post it.

   MikeT
 
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Mike,

Thanks again.

I have nothing else attached to the board.

I look forward to the new code with eager anticipation. I am sure many others would be interested in this also.

Meanwhile I have an Arduino with a 168 processor on the way - someone still sells them, and a chuck extension cable (plug one end, socket on the other) I can cut and solder to the board to totally eliminate any "connections" issues.

Best wishes

John
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 186
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi John,

I used Björn Geisslers code as base and did some improvements. The only big difference to my first try from a functional perspective is the error handling and reinitialization of the nunchuck after an error occours.

WirelessNunchuck.pde:
Code:
// adapt to your hardware config
#define POWER_VIA_PORT_C2_C3 1    // use port pins port C2 and C3 as power supply of the Nunchuck (direct plug using wiichuck adapter)

#include <Wire.h>
#include <utility/twi.h>
#include <EEPROM.h>

#include "Nunchuk.h"

Nunchuk chuk;

void setup()
{
  Serial.begin(115200);
  Wire.begin();
  
  // use 400 kHz for the nunchuck, because it doesn't work reliable with 100 kHz
  TWBR = ((CPU_FREQ / 400000L) - 16) / 2;

// power supply of the Nunchuck via port C2 and C3 (for the wiichuck adapter directly plugged on Arduino)
#ifdef POWER_VIA_PORT_C2_C3
  PORTC &=~ _BV(PORTC2);
  PORTC |=  _BV(PORTC3);
  DDRC |= _BV(PORTC2) | _BV(PORTC3);  // make outputs
  delay(100);  // wait for things to stabilize
#endif

  delay(100);
}

void loop()
{
  if(!chuk.ok())
  {
    Serial.println("Initing nunchuk, it's broken!");
    chuk.init();
  }

  if(chuk.read())
  {
    Serial.print(chuk.joyX(), DEC);
    Serial.write(' ');
    Serial.print(chuk.joyY(), DEC);
    Serial.write(' ');
    Serial.print(chuk.buttonZ(), DEC);
    Serial.write(' ');
    Serial.print(chuk.buttonC(), DEC);
    Serial.write(' ');
    Serial.print(chuk.accX(), DEC);
    Serial.write(' ');
    Serial.print(chuk.accY(), DEC);
    Serial.write(' ');
    Serial.print(chuk.accZ(), DEC);
    Serial.println();
  }
  else
  {
    Serial.println("chuck.read() failed");
  }

  // slow down printing, remove this for a real application
  delay(100);
}

Nunchuk.cpp:
Code:
#include <wiring.h>
#include <Wire.h>
#include <HardwareSerial.h>
//#include <EEPROM.h>

#include "Nunchuk.h"

#define NUNCHUK_ADR 0x52
#define INIT_TIMEOUT 100
#define NEW_WAY

#define KEY_DECRYPT_ADD (0x97)
#define KEY_DECRYPT_XOR (0x97)

Nunchuk::Nunchuk()
{
  error = true;
}

bool Nunchuk::init()
{
#if defined(NEW_WAY)
  error = true;
  unsigned long time = millis();
  do
  {
    // disable encryption
    Wire.beginTransmission (NUNCHUK_ADR);      // transmit to device 0x52
    Wire.send (0xF0);       // sends memory address
    Wire.send (0x55);
    if(Wire.endTransmission() == 0)
    {
      Wire.beginTransmission (NUNCHUK_ADR);      // transmit to device 0x52
      Wire.send (0xFB);       // sends memory address
      Wire.send (0x00);
      if(Wire.endTransmission () == 0)
      {
        error = false;
        //Serial.println("OK");
      }
    }
  }
  while (error && (millis() - time) < INIT_TIMEOUT);

  if(error) {
    return true;
  }

  read();
  return error;
#else
  //Serial.println("Init the old way!");
  Wire.beginTransmission(NUNCHUK_ADR);
  Wire.send(0x40);
  Wire.send(0x00);
  Wire.endTransmission();

  read();
  return error;
#endif
}

void Nunchuk::request()
{
  // from http://wiki.wiimoteproject.com/Extensions: When filling in a User Input report, the Wii Remote writes a
  // single byte, 0x00, and then issues 1 - 3 reads to fill the report field with all but the last read being 8 bytes.
  for(int i=0; i<2; i++)
  {
    Wire.beginTransmission(NUNCHUK_ADR);
    Wire.send(0x00);
    Wire.endTransmission();
  }

  Wire.beginTransmission(NUNCHUK_ADR);
  Wire.send(0x08); // Input Data address, see register map below
  Wire.endTransmission();
}

bool Nunchuk::read()
{
  uint8_t buf[6];
  error = true;

  request();
  Wire.requestFrom(NUNCHUK_ADR, sizeof(buf));

  // read
  int cnt;
  for(cnt = 0; Wire.available() && (cnt < sizeof(buf)); cnt++)
  {
#if defined(NEW_WAY)
    buf[cnt] = Wire.receive();
#else
    // the real key is actually 2*8 bytes, see wiimote_encrypt() below
    buf[cnt] = (Wire.receive() ^ KEY_DECRYPT_XOR) + KEY_DECRYPT_ADD;
#endif    
  }

  // less than 6 bytes read? error.
  if(cnt != sizeof(buf))
  {
    // this is tricky: the nunchuck doesn't have to be reinitialized, but the values are not ok
    //Serial.print("cnt=");
    //Serial.println(cnt, DEC);
    error = false;
    return false;
  }

  // all 0xff read? error.
  cnt = 0;
  for(int i=0; i<sizeof(buf); i++)
  {
    if(buf[i] == 0xff) cnt++;
  }
  if(cnt == sizeof(buf)) {
    return false;
  }

  error = false;
  decode(buf);

  return true;
}

void Nunchuk::decode(uint8_t* buf)
{
  joy_x = (int)(buf[0]) - calib_joy_x;
  joy_y = (int)(buf[1]) - calib_joy_y;
  acc_x =  (buf[2] << 2) | ((buf[5] >> 2) & 0x03);
  acc_y =  (buf[3] << 2) | ((buf[5] >> 4) & 0x03);
  acc_z =  (buf[4] << 2) | ((buf[5] >> 6) & 0x03);
  btn_z =  (buf[5]       & 0x01) ^ 0x01;
  btn_c = ((buf[5] >> 1) & 0x01) ^ 0x01;
}

Nunchuk.h
Code:
#if !defined(NUNCHUK_H)
#define NUNCHUK_H

class Nunchuk {
public:
  Nunchuk();

  bool init();

  // returns 'true' when values have been read successfully
  bool read();
  
  inline int joyX() const { return joy_x; }
  inline int joyY() const { return joy_y; }
  inline int accX() const { return acc_x; }
  inline int accY() const { return acc_y; }
  inline int accZ() const { return acc_z; }

  inline bool buttonZ() const { return btn_z; }
  inline bool buttonC() const { return btn_c; }

  // returns 'false', when the nunchuck needs to be initialized
  inline bool ok() const { return !error; }

private:
  void request();
  void decode(uint8_t* buf);
  
  int joy_x, joy_y, acc_x, acc_y, acc_z;

  bool btn_z, btn_c;
  bool error;

  //int calib_joy_x, calib_joy_y;
  static const int calib_joy_x = 127;
  static const int calib_joy_y = 127;
};

#endif // NUNCHUK_H

Please tell me, if it helps. I actually think you might have a hardware problem. Which power source do you use for the nunchuck? Is it 3,3V or 5V? Are there any level converters on the i2c bus?

  MikeT
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Mike,

Compiles fine, loads onto Arduino OK. Still will not read the wireless chuck though!

If I go back to earlier software and wired chuck that works OK so electrical connections and board probably are OK. Have tried 5V and 3.3V. Have changed the I2C wires around just in case they were back to front (they weren't).

I am going to stop now until my Arduino168 arrives and my chuck extender cable then I will have good connections and an exact replica of your hardware setup.

I will let you know how I get on when I do next experiment.

Best wishes

John
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mike, a quick update:

YESSS it works - at last. I can stop tearing my hair out.

I went back to your original software and noticed that at 3.3V it did not work at all but at 5V it just gave one line of data than locked up.

I read some datasheets and thought maybe I should run the board from a separate power supply instead of just via the USB port as the ideal supply to the board is a little higher, about 7V, so the onboard regulator can stabilise it down to about 5V.

When I did that I got about 4 to 10 lines of data before it locked up. Unreliable, but at least it was sort of working. Therefore the problem must be power related or due to some threshold signal voltage only intermittently being reached or noise corruption or something along those lines.

Did some more reading on I2C. The accepted wisdom with Arduino is that the I2C pins (analog in 4 and 5) do NOT require pull-up resistors as these are built in.
These if you use them are placed between SDA(pin 4) and +5V, and between SCK(pin 5) and +5V. Notwithstanding the above, some people do use them just in case.
Here is just one example:

http://www.robot-electronics.co.uk/htm/using_the_i2c_bus.htm

They certainly seem to do no harm even if not strictly required. What had I got to lose?

I put a 1800 Ohm resistor between SDA and +5V and another one between SCK and +5V.

Guess what? Both versions of your software above work perfectly.

Also, both my wireless Nunchucks work:
The BlazePro is fiddly to initialise and can be a bit temperamental to get working, fine once it is working though. It also runs on AAA batteries.

The other one (with no name) that I bought from a UK supplier is a more recent type. It has an internal battery that charges up via a USB charger. There is an initialisation procedure you carry out the first time you use it. Every time you use it after that you just turn on the receiver (i.e. in this case the Arduino board it is connected to) and press the z button on the wireless chuck - it will instantly connect with no fuss.

I have put a photo of both of them at bottom of this page on my skateboard site:
http://sites.google.com/site/onewheeledselfbalancing/Home/wii-nunchuck-arduino-interface


So in summary:

Either version of this software will work OK with latest Arduinos with the ATmega328 processor and I used Arduino 17 to compile.

Now the pull-up resistors are in, it runs just fine when just powered from the USB cable.

Moral of the tale: This is one situation where external pull-up resistors ARE needed.


I am now converting the wired-nunchuck controlled skateboard to wireless - going to be up very late methinks.

Thanks everyone.

Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 186
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi John,

Quote
This is one situation where external pull-up resistors ARE needed.

The resistors are not pull-ups, but bus terminators to avoid reflections on the bus. At a communication speed of 400k this becomes relevant. You should keep the cable as short as possible.

My Nunchuck receiver is directly coupled using the Wiichuck adapter (no cable at all), therefore it works without the resistors.

  MikeT
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi there

I use NYKO Kama wireless nunchuck and the code listed above "WirelessNunchuck.pde"
connected the 1800ohm pull up resistor.
my reciever unit will not turn on, all I see on the serial port is Zeros, I tried 3.3V, 5V from arduino and 5V from a different power source and still does not work, I'm new to all this so I don't realy understand the code to be able to modify it.
what do you think the problem with my reciever?
And how can I got more under standing of the code?
Thx
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 186
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi SamSong,

can you please use the code from my first posting in this thread ("Reply #1")?

It should print the following two lines directly after a reset:
Code:
Ident=0 0 A4 20 0 0
Finished setup


What does it print for you? What numbers do you get for "avail=??" and "cnt=??"?.

  MikeT
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 186
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi SamSong,

according to the site http://wiibrew.org/wiki/Wiimote/Extension_Controllers#Nyko_Kama this Nunchuck needs an extended init sequence.

Can you try to replace the Nunchuk.cpp file from the second solution with this one:
Code:
#include <wiring.h>
#include <Wire.h>
#include <HardwareSerial.h>
//#include <EEPROM.h>

#include "Nunchuk.h"

#define NUNCHUK_ADR 0x52
#define INIT_TIMEOUT 100
#define NEW_WAY

#define KEY_ENC_ADD (0x00)
#define KEY_ENC_XOR (0x00)
#define KEY_DECRYPT_ADD (0x97)
#define KEY_DECRYPT_XOR (0x97)

Nunchuk::Nunchuk()
{
  error = true;
}


bool GetIdent()
{
  Wire.beginTransmission(NUNCHUK_ADR);
  Wire.send(0xFA);
  if(Wire.endTransmission() == 0)
  {
    uint8_t ident[6];
    int cnt;
    Wire.requestFrom(NUNCHUK_ADR, sizeof(ident));
    for(cnt = 0; Wire.available() && (cnt < sizeof(ident)); cnt++)
    {
      ident[cnt] = Wire.receive();
    }
    if(cnt == sizeof(ident))
    {
      Serial.print("Ident=");
      for(int i = 0; i < cnt; i++)
      {
        Serial.print(ident[i], HEX);
        Serial.write(' ');
      }
      Serial.println();
      return true;
    }
  }

  return false;
}


bool SetEncKey()
{
  bool rc = false;
  // set 2*8 byte encryption key (6+6+4)
  Wire.beginTransmission (NUNCHUK_ADR);      // transmit to device 0x52
  Wire.send (0x40);       // sends memory address
  Wire.send (KEY_ENC_ADD);
  Wire.send (KEY_ENC_ADD);
  Wire.send (KEY_ENC_ADD);
  Wire.send (KEY_ENC_ADD);
  Wire.send (KEY_ENC_ADD);
  Wire.send (KEY_ENC_ADD);
  Wire.send (KEY_ENC_ADD);
  Wire.send (KEY_ENC_ADD);
  
  Wire.send (KEY_ENC_XOR);
  Wire.send (KEY_ENC_XOR);
  Wire.send (KEY_ENC_XOR);
  Wire.send (KEY_ENC_XOR);
  Wire.send (KEY_ENC_XOR);
  Wire.send (KEY_ENC_XOR);
  Wire.send (KEY_ENC_XOR);
  Wire.send (KEY_ENC_XOR);
  if(Wire.endTransmission () == 0)
  {
#if 1
    // enable encryption
    Wire.beginTransmission (NUNCHUK_ADR);      // transmit to device 0x52
    Wire.send (0xF0);       // sends memory address
    Wire.send (0xAA);       // sends data.
    if(Wire.endTransmission() == 0)
    {
      rc = true;
      //Serial.println("OK");
    }
#else
    rc = true;
#endif
  }
  
  return rc;
}


bool Nunchuk::init()
{
#if defined(NEW_WAY)
  error = true;
  unsigned long time = millis();
  do
  {
    // disable encryption
    Wire.beginTransmission (NUNCHUK_ADR);      // transmit to device 0x52
    Wire.send (0xF0);       // sends memory address
    Wire.send (0x55);
    if(Wire.endTransmission() == 0)
    {
      Wire.beginTransmission (NUNCHUK_ADR);      // transmit to device 0x52
      Wire.send (0xFB);       // sends memory address
      Wire.send (0x00);
      if(Wire.endTransmission () == 0)
      {
        error = false;
        error = !SetEncKey();
        //Serial.println("OK");
      }
    }
  }
  while (error && (millis() - time) < INIT_TIMEOUT);

  if(error) {
    return true;
  }

  read();
  return error;
#else
  //Serial.println("Init the old way!");
  Wire.beginTransmission(NUNCHUK_ADR);
  Wire.send(0x40);
  Wire.send(0x00);
  Wire.endTransmission();

  read();
  return error;
#endif
}

void Nunchuk::request()
{
  // from http://wiki.wiimoteproject.com/Extensions: When filling in a User Input report, the Wii Remote writes a
  // single byte, 0x00, and then issues 1 - 3 reads to fill the report field with all but the last read being 8 bytes.
  for(int i=0; i<2; i++)
  {
    Wire.beginTransmission(NUNCHUK_ADR);
    Wire.send(0x00);
    Wire.endTransmission();
  }

  Wire.beginTransmission(NUNCHUK_ADR);
  Wire.send(0x08); // Input Data address, see register map below
  Wire.endTransmission();
}

bool Nunchuk::read()
{
  uint8_t buf[6];
  error = true;

  request();
  Wire.requestFrom(NUNCHUK_ADR, sizeof(buf));

  // read
  int cnt;
  for(cnt = 0; Wire.available() && (cnt < sizeof(buf)); cnt++)
  {
#if defined(NEW_WAY)
    buf[cnt] = Wire.receive();
#else
    // the real key is actually 2*8 bytes, see wiimote_encrypt() below
    buf[cnt] = (Wire.receive() ^ KEY_DECRYPT_XOR) + KEY_DECRYPT_ADD;
#endif    
  }

  // less than 6 bytes read? error.
  if(cnt != sizeof(buf))
  {
    // this is tricky: the nunchuck doesn't have to be reinitialized, but the values are not ok
    //Serial.print("cnt=");
    //Serial.println(cnt, DEC);
    error = false;
    return false;
  }

  // all 0xff read? error.
  cnt = 0;
  for(int i=0; i<sizeof(buf); i++)
  {
    if(buf[i] == 0xff) cnt++;
  }
  if(cnt == sizeof(buf)) {
    return false;
  }

  error = false;
  decode(buf);

  return true;
}

void Nunchuk::decode(uint8_t* buf)
{
  joy_x = (int)(buf[0]) - calib_joy_x;
  joy_y = (int)(buf[1]) - calib_joy_y;
  acc_x =  (buf[2] << 2) | ((buf[5] >> 2) & 0x03);
  acc_y =  (buf[3] << 2) | ((buf[5] >> 4) & 0x03);
  acc_z =  (buf[4] << 2) | ((buf[5] >> 6) & 0x03);
  btn_z =  (buf[5]       & 0x01) ^ 0x01;
  btn_c = ((buf[5] >> 1) & 0x01) ^ 0x01;
}

It configures the encryption key (16 x 0x00) and activates encryption in SetEncKey().

  MikeT

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thx Mike
I tried your code, but I got this error

c:/documents and settings/administrator/my documents/atmel/arduino-0017/arduino-0017/hardware/tools/avr/lib/gcc/../../avr/include/stdlib.h:111: error: expected unqualified-id before 'int'

c:/documents and settings/administrator/my documents/atmel/arduino-0017/arduino-0017/hardware/tools/avr/lib/gcc/../../avr/include/stdlib.h:111: error: expected `)' before 'int'

Sam
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 186
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi SamSong,

the compiler error message is really hard to analyze...

Have you used the sketch from "Reply #5" and completely replace the Nunchuk.cpp file, so you have exactly the 3 files WirelessNunchuck.pde, Nunchuk.h and Nunchuk.h?

Can you try to delete all temporary Arduino files?
1. Close the Arduino-IDE
2. Delete the WirelessNunchuck/applet subdirectory
3. Delete all build.tmp directories in C:\Documents and Settings\<your_user_name>\Local Settings\Temp\build*.tmp

   MikeT
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thx Mike

I did all the steps you gave me, but know i got a new error.
"error:'CPU_FREQ'was not declared in this scope"

thx again for your help.
Logged

Pages: [1] 2 3 ... 11   Go Up
Jump to: