From the various examples (mostly from the Arduino world) and documentations read, i still have a few questions:
- Which initialization sequence do you need with your controller? (one is working for me and the other one commented out in my example)
- Which I2C bus speed can you use your nunchuk with? Other sources say 100kHz is "standard", i can use 200kHz. But what is a stable and reasonable maximum value for this? If possible I would like to use it at maximum rate with other I2C devices connected at the same time (e.g. SSD1306 based OLED display).
- What use for are those decoding examples in the other libraries (readout = (byte ^ 0x17) + 0x17)? I still get reasonable readouts without "fixing" my sensor readings this way.
- Maybe i am dumb, but how does one interpret accelerometer sensor readouts? Even with the pyboard accelerometer i do read "angels on the axis" instead of acceleration on those axis as i would assume for an accelerometer sensor
Code: Select all
import pyb
class Nunchuck(object):
"""The Nunchuk object presents the sensor readings in a polling way.
Based on the fact that the controller does communicate using I2C we
cannot make it push sensor changes by using interrupts or similar
facilities. Instead a polling mechanism is implemented, which updates
the sensor readings based on "intent-driven" regular updates.
If the "polling" way of updating the sensor readings is not sufficient
a timer interrupt could be used to poll the controller. The
corresponding update() method does not allocate memory and thereby
could directly be used as an callback method for a timer interrupt."""
def __init__(self, i2c_bus, poll=True):
"""Initialize the Nunchuk controller. If no polling is desired it
can be disabled. Only one controller is possible on one I2C bus,
because the address of the controller is fixed.
The maximum stable I2C bus rate is 100kHz (200kHz seem to work on
mine as well, 400kHz does not)."""
self.i2c = i2c_bus
self.address = 0x52
self.buffer = bytearray(b'\x00\x00\x00\x00\x00\x00')
# There are two initialization sequences documented.
#self.i2c.send(b'\x40\x00', self.address)
#self.i2c.send(b'\x00', self.address)
self.i2c.send(b'\xf0\x55', self.address)
self.i2c.send(b'\xfb\x00', self.address)
self.last_poll = 0
if poll:
# Only poll every 50 milliseconds
self.polling_threshold = 50
else:
# If no polling is desired we disable it completely
self.polling_threshold = -1
def __send(self, bytes):
"""Sends bytes to the controller."""
if self.i2c.is_ready(self.address):
self.i2c.send(bytes, self.address)
else:
raise Exception("Could not send data to Nunchuck at address %s" % str(hex(self.address)))
def update(self):
"""Requests a sensor readout from the controller and receives the
six data bits afterwards."""
if self.i2c.is_ready(self.address):
self.__send(0x00)
self.i2c.recv(self.buffer, self.address)
else:
raise Exception("Could not receive data from Nunchuck at address %s" % str(hex(self.address)))
def __poll(self):
"""Poll the sensor readouts if necessary."""
if pyb.elapsed_millis(self.last_poll) > self.polling_threshold:
self.update()
def buttons(self):
"""Returns a tuple representing the states of the button C and Z
(in this order). The values are True if the corresponding button
is being pressed and False otherwise."""
self.__poll()
return (not (self.buffer[5] & 2 == 2), not (self.buffer[5] & 1 == 1))
def joystick(self):
"""Get the X and Y positions of the thumb joystick. For both axis
a value of 0 means left, ~136 center and 255 right position."""
self.__poll()
return (self.buffer[0], self.buffer[1])
def joystick_left(self):
"""Returns True if the joystick is being held to the left side."""
self.__poll()
return self.buffer[0] < 55
def joystick_right(self):
"""Returns True if the joystick is being held to the right side."""
self.__poll()
return self.buffer[0] > 200
def joystick_up(self):
"""Returns True if the joystick is being held to the upper side."""
self.__poll()
return self.buffer[1] > 200
def joystick_down(self):
"""Returns True if the joystick is being held to the lower side."""
self.__poll()
return self.buffer[1] < 55
def joystick_center(self):
"""Returns True if the joystick is not moved away fromthe center
position."""
self.__poll()
return self.buffer[0] > 100 and self.buffer[0] < 155 and self.buffer[1] > 100 and self.buffer[1] < 155
def accel(self):
"""Retrieve the three axis of the last accelerometer reading.
Returns a tuple of three elements: The x, y and z axis"""
self.__poll()
return ((self.buffer[2] << 2) + ((self.buffer[5] << 4) >> 6),
(self.buffer[3] << 2) + ((self.buffer[5] << 2 ) >> 6),
(self.buffer[4] << 2) + (self.buffer[5] >> 6))
def decode(byte):
return (byte ^ 0x17) + 0x17
def test():
nun = Nunchuck(pyb.I2C(2, mode=pyb.I2C.MASTER, baudrate=100000))
x = 0
y = 0
while True:
if not nun.joystick_center():
if nun.joystick_up():
y += 1
elif nun.joystick_down():
y -= 1
if nun.joystick_left():
x -= 1
elif nun.joystick_right():
x += 1
print("Joy-X: %3d Joy-Y: %3d Accel-X: %3d Accel-Y: %3d Accel-Z: %3d C: %s Z: %s" % (nun.joystick()[0], nun.joystick()[1], nun.accel()[0], nun.accel()[1], nun.accel()[2], nun.buttons()[0], nun.buttons()[1]))
print(x, y)
pyb.delay(100)
Code: Select all
Micro Python v1.3.7-1-gd96e6b1 on 2014-11-29; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>> import nunchuck
>>> nunchuck.test()
...
(enjoy until you press Ctrl-C)