Paso 10: Control Nunchuck
Escribí este poco de código en el año 2007 con un nunchuck de Wii como un dispositivo de entrada para un animatronic cañón de depredador (ver ejemplo 7). El nunchuck de la Wii comunica con un Arduino sobre cuatro cables (alimentación, tierra, datos y reloj) usando una interfaz I²C (circuito Inter-integrado también conocido como interfaz de dos hilos o TWI).
El nunchuck de Wii tiene un acelerómetro de tres ejes, joystick y dos botones-por $20 es un impresionante dispositivo de entrada para proyectos de Arduino. El código presentado aquí es una modificación posterior del código por Tod Kurt que fue presentado en su clase de Arduino Bionic-simplemente amplié para controlar todo, pero el eje del acelerómetro Z, que encontré rara vez se utiliza.
Utilizando este código podrá controlar cuatro servos usando las funciones del acelerómetro y el joystick y utilice los dos botones para encender LEDs (o transistores o incluso un poco de código.)
/*
* Ejemplo 6
* Nunchuck control para cuatro servos y dos entradas de botón
* Honus 2007
* Esto permite el uso de un nunchuck de Wii como un dispositivo de entrada y es modificado/ampliado el código original
* por Tod E. Kurt y Windmeadow Labs
* 2007 Tod E. Kurt, http://todbot.com/blog/
* El Wii Nunchuck código de lectura se toma de los laboratorios de Windmeadow, http://www.windmeadow.com/node/42
*/
#include "Wire.h"
ledPin1 int = 13; Pin de control de LED 1
int ledPin2 = 12; Pin de control de LED 2
int servoPin1 = 9; Pin de control de motor servo
int servoPin2 = 8; Pin de control de motor servo
int servoPin3 = 7; Pin de control de motor servo
int servoPin4 = 6; Pin de control de motor servo
int pulseWidth1 = 0; Cantidad para el servo 1
int pulseWidth2 = 0; Cantidad de pulsos del servo 2
int pulseWidth3 = 0; Cantidad para el servo 3
int pulseWidth4 = 0; Cantidad de pulsos del servo 4
int refreshTime = 20; el tiempo en millisecs necesitaba entre pulsos
largo lastPulse1;
largo lastPulse2;
largo lastPulse3;
largo lastPulse4;
int minPulse = 700; anchura de pulso mínima
int loop_cnt = 0;
void setup()
{
Serial.Begin(19200);
pinMode (servoPin1, salida); Pin Set servo como un pin de salida
pinMode (servoPin2, salida); Pin Set servo como un pin de salida
pinMode (servoPin3, salida); Pin Set servo como un pin de salida
pinMode (servoPin4, salida); Pin Set servo como un pin de salida
pulseWidth1 = minPulse; Establecer la posición del motor al mínimo
pulseWidth2 = minPulse; Establecer la posición del motor al mínimo
pulseWidth3 = minPulse; Establecer la posición del motor al mínimo
pulseWidth4 = minPulse; Establecer la posición del motor al mínimo
nunchuck_init(); enviar el protocolo de inicialización
Serial.Print ("NunchuckServo ready\n");
}
void loop()
{
checkNunchuck1();
updateServo1(); actualizar posición servo 1
checkNunchuck2();
updateServo2(); actualizar posición del servo 2
checkNunchuck3();
updateServo3(); actualizar posición servo 3
checkNunchuck4();
updateServo4(); actualizar posición del servo 4
Si (nunchuck_zbutton()) / / el LED la luz si se presiona el botón z
digitalWrite (ledPin1, HIGH);
otra cosa
digitalWrite(ledPin1,LOW);
Si (nunchuck_cbutton()) / / el LED la luz si se presiona el botón c
digitalWrite (ledPin2, HIGH);
otra cosa
digitalWrite(ledPin2,LOW);
Delay(1); Esto está aquí para dar un tiempo conocido por loop
}
void checkNunchuck1()
{
Si (loop_cnt > 100) {/ / bucle () s es cada 1 mseg, cada 100msec
nunchuck_get_data();
nunchuck_print_data();
inclinación del flotador = nunchuck_accelx(); eje x, en este caso va de ~ 70 - ~ 185
inclinación = (tilt - 70) * 1.5; Convertir ángulo en grados, más o menos
pulseWidth1 = (inclinación * 9) + minPulse; Convertir ángulo a microsegundos
loop_cnt = 0; reajuste para
}
loop_cnt ++;
}
llama cada loop().
utiliza variables globales servoPin, anchura de impulso, lastPulse y refreshTime
void updateServo1()
{
pulso del servo nuevo si ha pasado el tiempo de refresco de rhe (20 ms):
Si (millis() - lastPulse1 > = refreshTime) {}
digitalWrite (servoPin1, HIGH); Encienda el motor
delayMicroseconds(pulseWidth1); Longitud del pulso ajusta la posición del motor
digitalWrite (servoPin1, bajo); Apague el motor
lastPulse1 = millis(); ahorrar el tiempo de la última pulsación
}
}
void checkNunchuck2()
{
Si (loop_cnt > 100) {/ / bucle () s es cada 1 mseg, cada 100msec
nunchuck_get_data();
nunchuck_print_data();
inclinación del flotador = nunchuck_accely(); eje y, en este caso va de ~ 70 - ~ 185
inclinación = (tilt - 70) * 1.5; Convertir ángulo en grados, más o menos
pulseWidth2 = (inclinación * 9) + minPulse; Convertir ángulo a microsegundos
loop_cnt = 0; reajuste para
}
loop_cnt ++;
}
llama cada loop().
utiliza variables globales servoPin, anchura de impulso, lastPulse y refreshTime
void updateServo2()
{
pulso del servo nuevo si ha pasado el tiempo de refresco de rhe (20 ms):
Si (millis() - lastPulse2 > = refreshTime) {}
digitalWrite (servoPin2, HIGH); Encienda el motor
delayMicroseconds(pulseWidth2); Longitud del pulso ajusta la posición del motor
digitalWrite (servoPin2, bajo); Apague el motor
lastPulse2 = millis(); ahorrar el tiempo de la última pulsación
}
}
void checkNunchuck3()
{
Si (loop_cnt > 100) {/ / bucle () s es cada 1 mseg, cada 100msec
nunchuck_get_data();
nunchuck_print_data();
inclinación del flotador = nunchuck_joyx(); eje x, en este caso va de ~ 70 - ~ 185
inclinación = (tilt - 70) * 1.5; Convertir ángulo en grados, más o menos
pulseWidth3 = (inclinación * 9) + minPulse; Convertir ángulo a microsegundos
loop_cnt = 0; reajuste para
}
loop_cnt ++;
}
llama cada loop().
utiliza variables globales servoPin, anchura de impulso, lastPulse y refreshTime
void updateServo3()
{
pulso del servo nuevo si ha pasado el tiempo de refresco de rhe (20 ms):
Si (millis() - lastPulse3 > = refreshTime) {}
digitalWrite (servoPin3, HIGH); Encienda el motor
delayMicroseconds(pulseWidth3); Longitud del pulso ajusta la posición del motor
digitalWrite (servoPin3, bajo); Apague el motor
lastPulse3 = millis(); ahorrar el tiempo de la última pulsación
}
}
void checkNunchuck4()
{
Si (loop_cnt > 100) {/ / bucle () s es cada 1 mseg, cada 100msec
nunchuck_get_data();
nunchuck_print_data();
inclinación del flotador = nunchuck_joyy(); eje y, en este caso va de ~ 70 - ~ 185
inclinación = (tilt - 70) * 1.5; Convertir ángulo en grados, más o menos
pulseWidth4 = (inclinación * 9) + minPulse; Convertir ángulo a microsegundos
loop_cnt = 0; reajuste para
}
loop_cnt ++;
}
llama cada loop().
utiliza variables globales servoPin, anchura de impulso, lastPulse y refreshTime
void updateServo4()
{
pulso del servo nuevo si ha pasado el tiempo de refresco de rhe (20 ms):
Si (millis() - lastPulse4 > = refreshTime) {}
digitalWrite (servoPin4, HIGH); Encienda el motor
delayMicroseconds(pulseWidth4); Longitud del pulso ajusta la posición del motor
digitalWrite (servoPin4, bajo); Apague el motor
lastPulse4 = millis(); ahorrar el tiempo de la última pulsación
}
}
//
Funciones del nunchuck
//
nunchuck_buf estática uint8_t [6]; array para almacenar los datos del nunchuck,
inicializar el sistema I2C, Únete al bus I2C,
y Dile el nunchuck que estamos hablando de que
void nunchuck_init()
{
Wire.Begin(); a bus i2c como maestro
Wire.beginTransmission(0x52); transmitir al dispositivo 0x52
Wire.Send(0x40); envía la dirección de memoria
Wire.Send(0x00); envía envía un cero.
Wire.endTransmission(); interrumpir la transmisión
}
Enviar una solicitud de datos para el nunchuck
fue "send_zero()"
void nunchuck_send_request()
{
Wire.beginTransmission(0x52); transmitir al dispositivo 0x52
Wire.Send(0x00); envía un byte
Wire.endTransmission(); interrumpir la transmisión
}
Recibir datos del nunchuck,
devuelve 1 lectura exitosa. devuelve 0 en caso de error
int nunchuck_get_data()
{
int cnt = 0;
Wire.requestFrom (0x52, 6); solicitud datos del nunchuck
mientras que (Wire.available ()) {}
recibe byte como un número entero
nunchuck_buf [cnt] = nunchuk_decode_byte(Wire.receive());
CNT ++;
}
nunchuck_send_request(); enviar solicitud para la siguiente carga de datos
Si hemos recibido los bytes de 6, y luego ir imprimir
Si (cnt > = 5) {}
retorno 1; éxito
}
return 0; falta
}
Imprimir los datos que hemos recibido
datos de Accel están largo 10 bits
así leemos 8 bits, entonces tenemos que añadir
en los últimos 2 bits. Es por eso
multiplicar por 2 * 2
void nunchuck_print_data()
{
Static int i = 0;
int joy_x_axis = nunchuck_buf [0];
int joy_y_axis = nunchuck_buf [1];
int accel_x_axis = nunchuck_buf [2]; // * 2 * 2;
int accel_y_axis = nunchuck_buf [3]; // * 2 * 2;
int accel_z_axis = nunchuck_buf [4]; // * 2 * 2;
int z_button = 0;
int c_button = 0;
byte nunchuck_buf [5] contiene bits de botones z y c
también contiene los bits menos significativos de los datos del acelerómetro
así que tenemos que comprobar cada bit del byte telefonía [5]
Si ((nunchuck_buf [5] >> 0) & 1)
z_button = 1;
Si ((nunchuck_buf [5] >> 1) & 1)
c_button = 1;
Si ((nunchuck_buf [5] >> 2) & 1)
accel_x_axis += 2;
Si ((nunchuck_buf [5] >> 3) & 1)
accel_x_axis += 1;
Si ((nunchuck_buf [5] >> 4) & 1)
accel_y_axis += 2;
Si ((nunchuck_buf [5] >> 5) & 1)
accel_y_axis += 1;
Si ((nunchuck_buf [5] >> 6) & 1)
accel_z_axis += 2;
Si ((nunchuck_buf [5] >> 7) & 1)
accel_z_axis += 1;
Serial.Print(i,DEC);
Serial.Print("\t");
Serial.Print("Joy:");
Serial.Print(joy_x_axis,DEC);
Serial.Print(",");
Serial.Print (joy_y_axis, DEC);
Serial.Print ("\t");
Serial.Print("ACC:");
Serial.Print (accel_x_axis, DEC);
Serial.Print(",");
Serial.Print (accel_y_axis, DEC);
Serial.Print(",");
Serial.Print (accel_z_axis, DEC);
Serial.Print("\t");
Serial.Print("but:");
Serial.Print (z_button, DEC);
Serial.Print(",");
Serial.Print (c_button, DEC);
Serial.Print("\r\n"); nueva línea
i ++;
}
Codificar los datos para el formato que la mayoría conductores de wiimote excepto
sólo es necesario si utilizas uno de los pilotos regulares de wiimote
char nunchuk_decode_byte (char x)
{
x = (x ^ 0x17) + 0x17;
return x;
}
Devuelve el estado de zbutton: 1 = pulsado, 0 = notpressed
int nunchuck_zbutton()
{
¿regresar ((nunchuck_buf [5] >> 0) & 1)? 0: 1; Voodoo
}
Devuelve el estado de zbutton: 1 = pulsado, 0 = notpressed
int nunchuck_cbutton()
{
¿regresar ((nunchuck_buf [5] >> 1) & 1)? 0: 1; Voodoo
}
Devuelve valor de palanca de mando de eje x
int nunchuck_joyx()
{
volver nunchuck_buf [0];
}
Devuelve valor de palanca de mando de eje y
int nunchuck_joyy()
{
volver nunchuck_buf [1];
}
Devuelve el valor del acelerómetro de eje x
int nunchuck_accelx()
{
volver nunchuck_buf [2]; FIXME: Esto deja fuera a 2 bits de los datos
}
Devuelve el valor del acelerómetro de eje y
int nunchuck_accely()
{
volver nunchuck_buf [3]; FIXME: Esto deja fuera a 2 bits de los datos
}
Devuelve el valor del acelerómetro z
int nunchuck_accelz()
{
volver nunchuck_buf [4]; FIXME: Esto deja fuera a 2 bits de los datos
}