Étape 10 : Contrôle de Nunchuck
J’ai écrit ce morceau de code en 2007 pour utiliser un nunchuck Wii comme périphérique d’entrée pour un animatronic cannon Predator (Voir l’exemple 7). Le nunchuck Wii communique à un Arduino sur quatre fils (énergie, sol, données et horloge) à l’aide d’une interface I²C (Inter Integrated Circuit aka bifilaire interface ou TWI).
Le nunchuck Wii a un accéléromètre trois axes, de joystick et de deux boutons poussoirs-pour 20 $, c’est un périphérique d’entrée impressionnant pour les projets de l’Arduino. Le code présenté ici est une nouvelle modification du code par Tod Kurt qui a été présenté dans sa classe de Bionic Arduino-j’ai agrandit simplement pour contrôler tout sauf l’axe Z d’accéléromètre, que j’ai trouvé j’ai rarement utilisé.
En utilisant ce code, vous pouvez commander quatre servos en utilisant les fonctions accéléromètre et joystick et utilisez les deux boutons poussoirs pour allumer les LEDs (ou transistors ou même courir un peu de code.)
/*
* Exemple 6
* Contrôle Nunchuck pour quatre servos et deux entrées
* Honus 2007
* Cela permet l’utilisation d’un nunchuck Wii comme périphérique d’entrée et est modifié/étendu à partir du code original
* de Tod E. Kurt et de Windmeadow Labs
* 2007 Kurt E. Tod, http://todbot.com/blog/
* Le Wii Nunchuck lisant le code est tiré de Windmeadow Labs, http://www.windmeadow.com/node/42
*/
#include « Wire.h »
int ledPin1 = 13 ; Broche de commande pour 1 LED
int ledPin2 = 12 ; Broche de commande pour 2 LED
int servoPin1 = 9 ; Broche de commande de moteur servo
int servoPin2 = 8 ; Broche de commande de moteur servo
int servoPin3 = 7 ; Broche de commande de moteur servo
int servoPin4 = 6 ; Broche de commande de moteur servo
int pulseWidth1 = 0 ; Montant à impulsion servo 1
int pulseWidth2 = 0 ; Montant à impulsion le servo 2
int pulseWidth3 = 0 ; Montant à impulsion le servo 3
int pulseWidth4 = 0 ; Montant à impulsion servo 4
int refreshTime = 20 ; le temps en millisecs nécessaire entre impulsions
long lastPulse1 ;
long lastPulse2 ;
long lastPulse3 ;
long lastPulse4 ;
int minPulse = 700 ; largeur d’impulsion minimum
int loop_cnt = 0 ;
void setup()
{
Serial.Begin(19200) ;
pinMode (servoPin1, sortie) ; Axe servo ensemble comme une broche de sortie
pinMode (servoPin2, sortie) ; Axe servo ensemble comme une broche de sortie
pinMode (servoPin3, sortie) ; Axe servo ensemble comme une broche de sortie
pinMode (servoPin4, sortie) ; Axe servo ensemble comme une broche de sortie
pulseWidth1 = minPulse ; Définir la position de moteur au minimum
pulseWidth2 = minPulse ; Définir la position de moteur au minimum
pulseWidth3 = minPulse ; Définir la position de moteur au minimum
pulseWidth4 = minPulse ; Définir la position de moteur au minimum
nunchuck_init() ; Envoyer l’initialisation du handshake
Serial.Print ("NunchuckServo ready\n") ;
}
void loop()
{
checkNunchuck1() ;
updateServo1() ; mise à jour de la position du servo 1
checkNunchuck2() ;
updateServo2() ; mise à jour de la position du servo 2
checkNunchuck3() ;
updateServo3() ; mise à jour de la position du servo 3
checkNunchuck4() ;
updateServo4() ; mise à jour de la position du servo 4
Si (nunchuck_zbutton()) / / la lumière de la LED si vous appuyez sur le bouton z
digitalWrite (ledPin1, HIGH) ;
d’autre
digitalWrite(ledPin1,LOW) ;
Si (nunchuck_cbutton()) / / la LED s’allume si la touche c
digitalWrite (ledPin2, HIGH) ;
d’autre
digitalWrite(ledPin2,LOW) ;
Delay(1) ; C’est là pour donner un temps connu par boucle
}
Sub checkNunchuck1()
{
Si (loop_cnt > 100) {/ / loop () s est tous 1msec, il s’agit de chaque 100msec
nunchuck_get_data() ;
nunchuck_print_data() ;
flotteur tilt = nunchuck_accelx() ; axe des abscisses, dans ce cas varie de 70 ~ - ~ 185
inclinaison = (tilt - 70) * 1,5 ; convertir à peu près à l’angle en degrés,
pulseWidth1 = (inclinaison * 9) + minPulse ; convertir angle en microsecondes
loop_cnt = 0 ; remise à zéro des
}
loop_cnt ++ ;
}
appelée chaque loop().
utilise refreshTime, pulsewidth, lastPulse et servoPin de variables globales
Sub updateServo1()
{
impulsions le servo à nouveau si le temps d’actualisation rhe (20 ms) se sont écoulés :
Si (millis() - lastPulse1 > = refreshTime) {}
digitalWrite (servoPin1, HIGH) ; Allumez le moteur
delayMicroseconds(pulseWidth1) ; Longueur de l’impulsion définit la position moteur
digitalWrite (servoPin1, basse) ; Arrêter le moteur
lastPulse1 = millis() ; économiser le temps de la dernière impulsion
}
}
Sub checkNunchuck2()
{
Si (loop_cnt > 100) {/ / loop () s est tous 1msec, il s’agit de chaque 100msec
nunchuck_get_data() ;
nunchuck_print_data() ;
flotteur tilt = nunchuck_accely() ; axe des y, en l’occurrence varie de 70 ~ - ~ 185
inclinaison = (tilt - 70) * 1,5 ; convertir à peu près à l’angle en degrés,
pulseWidth2 = (inclinaison * 9) + minPulse ; convertir angle en microsecondes
loop_cnt = 0 ; remise à zéro des
}
loop_cnt ++ ;
}
appelée chaque loop().
utilise refreshTime, pulsewidth, lastPulse et servoPin de variables globales
Sub updateServo2()
{
impulsions le servo à nouveau si le temps d’actualisation rhe (20 ms) se sont écoulés :
Si (millis() - lastPulse2 > = refreshTime) {}
digitalWrite (servoPin2, HIGH) ; Allumez le moteur
delayMicroseconds(pulseWidth2) ; Longueur de l’impulsion définit la position moteur
digitalWrite (servoPin2, basse) ; Arrêter le moteur
lastPulse2 = millis() ; économiser le temps de la dernière impulsion
}
}
Sub checkNunchuck3()
{
Si (loop_cnt > 100) {/ / loop () s est tous 1msec, il s’agit de chaque 100msec
nunchuck_get_data() ;
nunchuck_print_data() ;
flotteur tilt = nunchuck_joyx() ; axe des abscisses, dans ce cas varie de 70 ~ - ~ 185
inclinaison = (tilt - 70) * 1,5 ; convertir à peu près à l’angle en degrés,
pulseWidth3 = (inclinaison * 9) + minPulse ; convertir angle en microsecondes
loop_cnt = 0 ; remise à zéro des
}
loop_cnt ++ ;
}
appelée chaque loop().
utilise refreshTime, pulsewidth, lastPulse et servoPin de variables globales
Sub updateServo3()
{
impulsions le servo à nouveau si le temps d’actualisation rhe (20 ms) se sont écoulés :
Si (millis() - lastPulse3 > = refreshTime) {}
digitalWrite (servoPin3, HIGH) ; Allumez le moteur
delayMicroseconds(pulseWidth3) ; Longueur de l’impulsion définit la position moteur
digitalWrite (servoPin3, basse) ; Arrêter le moteur
lastPulse3 = millis() ; économiser le temps de la dernière impulsion
}
}
Sub checkNunchuck4()
{
Si (loop_cnt > 100) {/ / loop () s est tous 1msec, il s’agit de chaque 100msec
nunchuck_get_data() ;
nunchuck_print_data() ;
flotteur tilt = nunchuck_joyy() ; axe des y, en l’occurrence varie de 70 ~ - ~ 185
inclinaison = (tilt - 70) * 1,5 ; convertir à peu près à l’angle en degrés,
pulseWidth4 = (inclinaison * 9) + minPulse ; convertir angle en microsecondes
loop_cnt = 0 ; remise à zéro des
}
loop_cnt ++ ;
}
appelée chaque loop().
utilise refreshTime, pulsewidth, lastPulse et servoPin de variables globales
Sub updateServo4()
{
impulsions le servo à nouveau si le temps d’actualisation rhe (20 ms) se sont écoulés :
Si (millis() - lastPulse4 > = refreshTime) {}
digitalWrite (servoPin4, HIGH) ; Allumez le moteur
delayMicroseconds(pulseWidth4) ; Longueur de l’impulsion définit la position moteur
digitalWrite (servoPin4, basse) ; Arrêter le moteur
lastPulse4 = millis() ; économiser le temps de la dernière impulsion
}
}
//
Fonctions Nunchuck
//
nunchuck_buf uint8_t statique [6] ; Tableau pour stocker les données de nunchuck,
initialiser le système I2C, de rejoindre le bus I2C,
et dire le nunchuck que nous parlons d’elle
Sub nunchuck_init()
{
Wire.Begin() ; rejoindre le bus i2c maître
Wire.beginTransmission(0x52) ; transmettre à un périphérique 0 x 52
Wire.Send(0x40) ; envoie l’adresse mémoire
Wire.Send(0x00) ; envoie a envoyé un zéro.
Wire.endTransmission() ; arrêter la transmission
}
Envoyer une demande de données pour le nunchuck
a « send_zero() »
Sub nunchuck_send_request()
{
Wire.beginTransmission(0x52) ; transmettre à un périphérique 0 x 52
Wire.Send(0x00) ; envoie un octet
Wire.endTransmission() ; arrêter la transmission
}
Recevoir des données remontant le nunchuck,
Retourne 1 en lecture réussie. retourne 0 si une erreur survient
int nunchuck_get_data()
{
cnt int = 0 ;
Wire.requestFrom (0 x 52, 6) ; données de demande du nunchuck
tandis que (Wire.available ()) {}
recevoir des octets en tant qu’entier
nunchuck_buf [cnt] = nunchuk_decode_byte(Wire.receive()) ;
CNT ++ ;
}
nunchuck_send_request() ; Envoyer demande de charge utile de données suivante
Si nous avons reçu les 6 octets, puis aller les imprimer
Si (cnt > = 5) {}
Return 1 ; succès
}
return 0 ; échec
}
Imprimer les données d’entrée, que nous avons reçu
données d’Accel sont 10 bits
donc nous lisons 8 bits, puis il faut ajouter
sur les 2 derniers bits. C’est pourquoi j’ai
multiplier par 2 * 2
Sub nunchuck_print_data()
{
public 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 ;
nunchuck_buf Byte [5] contient les bits pour les touches z et c
Il contient également les bits les moins significatifs pour les données de l’accéléromètre
Il faut donc vérifier chaque bit de l’octet outbuf [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") ; saut de ligne
i ++ ;
}
Encoder des données pour mettre en forme que la plupart des pilotes wiimote sauf
nécessaire uniquement si vous utilisez un des pilotes réguliers wiimote
nunchuk_decode_byte de char (char x)
{
x = (x ^ 0 x 17) + 0 x 17 ;
Return x ;
}
retourne l’état de zbutton: 1 = pressé, 0 = notpressed
int nunchuck_zbutton()
{
Return ((nunchuck_buf [5] >> 0) & 1) ? 0: 1 ; vaudou
}
retourne l’état de zbutton: 1 = pressé, 0 = notpressed
int nunchuck_cbutton()
{
Return ((nunchuck_buf [5] >> 1) & 1) ? 0: 1 ; vaudou
}
retourne la valeur du joystick de l’axe des abscisses
int nunchuck_joyx()
{
retour nunchuck_buf [0] ;
}
retourne la valeur du joystick de l’axe y
int nunchuck_joyy()
{
retour nunchuck_buf [1] ;
}
retourne la valeur de l’accéléromètre de l’axe des abscisses
int nunchuck_accelx()
{
retour nunchuck_buf [2] ; FIXME : cela laisse de côté 2-bits de données
}
retourne la valeur de l’accéléromètre de l’axe y
int nunchuck_accely()
{
retour nunchuck_buf [3] ; FIXME : cela laisse de côté 2-bits de données
}
retourne la valeur de l’accéléromètre de l’axe z
int nunchuck_accelz()
{
retour nunchuck_buf [4] ; FIXME : cela laisse de côté 2-bits de données
}