2 servo control with wii motion plus

Hello,
i am trying to control at least 2 servos (yaw and pitch) with wiiMPlus. i read hundreds of threads in these forums and managed to read usable yaw, pitch, roll data from wiiMPlus thanks to many brilliant programmers here.
my code manages to read yaw, pitch,roll data in degrees between 0-180 but when i try to use these degree data as servo.write the program stops reading data from wiiMPlus. better to phrase, the code stops working when i add #include <servo.h> to the beginning... :frowning: the code works when i uncomment the servo entries... pls help... below is my code:

// .......................................................................
// Code for reading data from a Wii Motion plus device connected to a Nunchuck
// Links to other sites 
// http://www.windmeadow.com/node/42   .... first time i saw arduino nunchuk interface
// http://www.kako.com/neta/2009-017/2009-017.html# .....Japanese site with lots of Wii info
// http://wiibrew.org/wiki/Wiimote/Extension_Controllers#Wii_Motion_Plus    .... the one and only
// http://randomhacksofboredom.blogspot.com/2009/06/wii-motion-plus-arduino-love.html 
// ....original motion plus but not passthrough
// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1248889032/35   .... great Kalman filter code
// thanks to duckhead and knuckles904. I will be using that code for sure.
// http://obex.parallax.com/objects/471/   .... ideas for passthrough
// by Krulkip
// Here is the bitmapping which is changed from the standard nunchuk mapping
// In Nunchuk mode:
//          Bit
// Byte     7       6       5       4       3       2       1       0
// 0       SX<7-----------------------------------------------------0>
// 1       SY<7-----------------------------------------------------0>
// 2       AX<9-----------------------------------------------------2>
// 3       AY<9-----------------------------------------------------2>
// 4       AZ<9---------------------------------------------3>      1
// 5       AZ<2-----1>     AY<1>   AX<1>   BC      BZ       0       0
// Please note also the loss of the bit0 resolution. 
// Byte 5 Bit 0 and 1 is used for nunchuk (0 0) = nunchuk or motion plus  (1 0) is motion plus detection.
// Byte 4 Bit 0 which is the extention controller detection bit. (1 = extension present)
// Hardware Arduino with ATMega 168
// Connections SDA to AD4 (Analog4) and SCL to AD5 (Analog5)
//........................................................................
#include <Wire.h>
//#include <Servo.h>
#include <String.h>
//#include <stdio.h>
//Servo yawServo;
//Servo pitchServo;

uint8_t outbuf[6];            // array to store arduino output
int cnt = 0;
int ledPin = 13;
int xID;
void
setup ()
{
  Serial.begin (19200);
  Wire.begin();
  Serial.print ("Finished setup\n");
  Serial.print ("Now detecting WM+\n");
  delay(100);
  //yawServo.attach(2);
  //pitchServo.attach(3);
// now make Wii Motion plus the active extension
// nunchuk mode = 05, wm+ only = 04, classic controller = 07
   Serial.print ("Making Wii Motion plus the active extension in nunchuk mode = 05 ........");
   Wire.beginTransmission(0x53);
   Wire.write(0xFE);
   Wire.write(0x05);// nunchuk
   Wire.endTransmission();
   Serial.print (" OK done");
   Serial.print ("\r\n");
   delay (100);
// now innitiate Wii Motion plus  
    Serial.print ("Innitialising Wii Motion plus ........");
    Wire.beginTransmission(0x53);
    Wire.write(0xF0);
    Wire.write(0x55);
    Wire.endTransmission();
    Serial.print (" OK done");
    Serial.print ("\r\n");
    delay (100);
    Serial.print ("Set reading address at 0xFA .......");
    Wire.beginTransmission(0x52);
    Wire.write(0xFA);
    Wire.endTransmission();
   Serial.print(" OK done");
   Serial.print ("\r\n");
   delay (100);
   Wire.requestFrom (0x52,6);
   outbuf[0] = Wire.read();Serial.print(outbuf[0],HEX);Serial.print(" ");
   outbuf[1] = Wire.read();Serial.print(outbuf[1],HEX);Serial.print(" ");
   outbuf[2] = Wire.read();Serial.print(outbuf[2],HEX);Serial.print(" ");
   outbuf[3] = Wire.read();Serial.print(outbuf[3],HEX);Serial.print(" ");
   outbuf[4] = Wire.read();Serial.print(outbuf[4],HEX);Serial.print(" ");
   outbuf[5] = Wire.read();Serial.print(outbuf[5],HEX);Serial.print(" ");
   Serial.print ("\r\n");
   xID= outbuf[0] + outbuf[1] + outbuf[2] + outbuf[3] + outbuf[4] + outbuf[5];
   Serial.print("Extension controller xID = 0x");
   Serial.print(xID,HEX); 
   if (xID == 0xCB) { Serial.print (" Wii Motion plus connected but not activated"); }
   if (xID == 0xCE) { Serial.print (" Wii Motion plus connected and activated"); }
   if (xID == 0x00) { Serial.print (" Wii Motion plus not connected"); }
   Serial.print ("\r\n");
   delay (100);
   // Now we want to point the read adress to 0xa40008 where the 6 byte data is stored 
    Serial.print ("Set reading address at 0x08 .........");
    Wire.beginTransmission(0x52);
    Wire.write(0x08);
    Wire.endTransmission();
    Serial.print(" OK done");
    Serial.print ("\r\n");
}
void
send_zero ()
{
    Wire.beginTransmission(0x52);
    Wire.write(0x00);
    Wire.endTransmission();
}
void loop ()
{
// now follows conversion command instructing extension controller to get
// all sensor data and put them into 6 byte register within the extension controller
  send_zero (); // send the request for next bytes
  delay (100);
  Wire.requestFrom (0x52,6);
  outbuf[0] = Wire.read();
  outbuf[1] = Wire.read();
  outbuf[2] = Wire.read();
  outbuf[3] = Wire.read();
  outbuf[4] = Wire.read();
  outbuf[5] = Wire.read();
  print ();
  cnt = 0;

}
void
print ()
{
// check if nunchuk is really connected
  if ((outbuf[4]&0x01)==0x01) {
  Serial.print("Ext con: ");
  }   
if ((outbuf[5]&0x03)==0x00) { 
 int joy_x_axis = outbuf[0];
 int joy_y_axis = outbuf[1];
 int accel_x_axis = (outbuf[2] << 2) + ((outbuf[5] >> 3) & 2);
 int accel_y_axis = (outbuf[3] << 2) + ((outbuf[5] >> 4) & 2);
 int accel_z_axis = (outbuf[4] << 2) + ((outbuf[5] >> 5) & 6);
 int z_button = (outbuf[5]>>2) & 1;
 int c_button = (outbuf[5]>>3) & 1;
  Serial.print ("joyx= ");
  Serial.print (joy_x_axis, HEX);
  Serial.print ("  joyy=");
  Serial.print (joy_y_axis, HEX);
  Serial.print ("  accx= ");
  Serial.print (accel_x_axis, HEX);
  Serial.print ("  accy= ");
  Serial.print (accel_y_axis, HEX);
  Serial.print (" accz= ");
  Serial.print (accel_z_axis, HEX);
  Serial.print ("  ");
  if (z_button == 0) { Serial.print ("z_button "); }
  if (c_button == 0) { Serial.print ("c_button "); }
  Serial.print ("\r\n");
 } 
else
if  ((outbuf[5]&0x03)==0x02) {
  int yaw = (((outbuf[5]&0xFC)<<6) + outbuf[0]);
  int pitch = (((outbuf[4]&0xFC)<<6) + outbuf[1]);
  int roll = (((outbuf[3]&0xFC)<<6) + outbuf[2]);
  
  int yaw_deg = map(roll, 3000, 13000, 0, 179);
  if (yaw_deg < 0){yaw_deg = 0;};
  if (yaw_deg > 179){yaw_deg = 179;};
  //yawServo.write(yaw_deg);
  delay(10);
  int pitch_deg = map(yaw, 3000, 13000, 0, 179);
  if (pitch_deg < 0){pitch_deg = 0;};
  if (pitch_deg > 179){pitch_deg = 179;};
  //pitchServo.write(pitch_deg);
  delay(10);
  int roll_deg = map(pitch, 3000, 13000, 0, 179);
  if (roll_deg < 0){roll_deg = 0;};
  if (roll_deg > 179){roll_deg = 179;};
  //rollServo.write(roll_deg);
  delay(10);
  
  Serial.print ("yaw= ");
  Serial.print (yaw_deg);
  Serial.print ("  pitch= ");
  Serial.print (pitch_deg);
  Serial.print ("  roll= ");
  Serial.print (roll_deg);
  Serial.print ("\r\n");
}
}
outbuf[0] = Wire.read();Serial.print(outbuf[0],HEX);Serial.print(" ");
   outbuf[1] = Wire.read();Serial.print(outbuf[1],HEX);Serial.print(" ");
   outbuf[2] = Wire.read();Serial.print(outbuf[2],HEX);Serial.print(" ");
   outbuf[3] = Wire.read();Serial.print(outbuf[3],HEX);Serial.print(" ");
   outbuf[4] = Wire.read();Serial.print(outbuf[4],HEX);Serial.print(" ");
   outbuf[5] = Wire.read();Serial.print(outbuf[5],HEX);Serial.print(" ");

Is your enter key broken? Along with your space key? Make this mess readable.

And, there was a sticky at the top of the forum about how to post code. You clearly failed to read that.

sorry about formatting, i am a newbie here... i am dealing with Arduinos for 5 years... i usually do a search and read forums to solve my problems.. but this time urged to post.. the new Arduino 1.0.4 software has changed many things... old sketches donot work properly... the code above is a combined work of many programmers and i added some lines too... most part of it is at least 2 years old.. to clarify few more things. the code is working on a Boardino 168, Arduino 1.0.4 used, input pins are A0 and A5 sda and sck respectively... 2 servos at D2 and D3... As you can see stdio.h and string.h doest compile... the problem is i cannot include Servo.h too, it stucks the program... :frowning:

the code is working on a Boardino 168

With Servo commented out? If that is the case, and uncommenting the Servo code causes problems, I'd guess that you were borderline on memory before upgrading to 1.0.4, and that doing so pushed you over the edge.

There are ways to reduce SRAM usage. Shorten literal strings, like in:

  Serial.print ("Finished setup\n");
  Serial.print ("Now detecting WM+\n");

or wrap them in the F() macro to keep them out of SRAM.

Serial.print (F("Finished setup\n"));
Serial.print (F("Now detecting WM+\n"));

thank you for your assistance but mem is sufficient, binary code is about 7000 bytes. i commented out all servo entries because otherwise program halts... the program continues to work and read and display all 3 angles correctly when servo entries are commented out... today i worked on the code a little bit and run it on Arduino 022, this time servo entries doesnt create problems and the code is working, but servos donot update... seems like the prog doesnt execute updateServos(); routine in void loop... the new code is as follows:

#include <Wire.h>
#include <Servo.h>
Servo yawServo;
Servo pitchServo;
byte data[6]; //six data bytes
int yaw, pitch, roll; //three axes
int yaw0, pitch0, roll0; //calibration zeroes
int yaw_deg,pitch_deg,roll_deg; //servo angles

void wmpOn(){
Wire.beginTransmission(0x53); //WM+ starts out deactivated at address 0x53
Wire.write(0xfe); //send 0x04 to address 0xFE to activate WM+
Wire.write(0x04);
Wire.endTransmission(); //WM+ jumps to address 0x52 and is now active
}

void wmpSendZero(){
Wire.beginTransmission(0x52); //now at address 0x52
Wire.write(0x00); //send zero to signal we want info
Wire.endTransmission();
}

void calibrateZeroes(){
for (int i=0;i<10;i++){
wmpSendZero();
Wire.requestFrom(0x52,6);
for (int i=0;i<6;i++){
data[i]=Wire.read();
}
yaw0+=(((data[3]>>2)<<8)+data[0])/10; //average 10 readings
pitch0+=(((data[4]>>2)<<8)+data[1])/10;
roll0+=(((data[5]>>2)<<8)+data[2])/10;
}
Serial.print("Yaw0:");
Serial.print(yaw0);
Serial.print(" Pitch0:");
Serial.print(pitch0);
Serial.print(" Roll0:");
Serial.println(roll0);
}

void receiveData(){
wmpSendZero(); //send zero before each request (same as nunchuck)
Wire.requestFrom(0x52,6); //request the six bytes from the WM+
for (int i=0;i<6;i++){
data[i]=Wire.read();
}
yaw=((data[3]>>2)<<8)+data[0]-yaw0;
pitch=((data[4]>>2)<<8)+data[1]-pitch0;
roll=((data[5]>>2)<<8)+data[2]-roll0;
}
//see http://wiibrew.org/wiki/Wiimote/Extension_Controllers#Wii_Motion_Plus
//for info on what each byte represents
void updateServos(){
  yawServo.write(yaw_deg);
  delay(100);  
  pitchServo.write(pitch_deg);
  delay(100);
} 
  
void setup(){
 
Serial.begin(115200);
Serial.println("WM+ tester");
Wire.begin();
wmpOn(); //turn WM+ on
calibrateZeroes(); //calibrate zeroes
delay(1000);
 yawServo.attach(2);
 pitchServo.attach(3);  
//pinMode(4, INPUT);
//pinMode(5, INPUT);
//pinMode(2, OUTPUT);
//pinMode(3, OUTPUT);
}

void loop(){

receiveData(); //receive data and calculate yaw pitch and roll

  int yaw_deg = map(yaw, -5000, 5000, 0, 179);
  if (yaw_deg < 0){yaw_deg = 0;};
  if (yaw_deg > 179){yaw_deg = 179;};
  //yawServo.write(yaw_deg);
  //delay(10);
  int pitch_deg = map(roll, -5000, 5000, 0, 179);
  if (pitch_deg < 0){pitch_deg = 0;};
  if (pitch_deg > 179){pitch_deg = 179;};
  //pitchServo.write(pitch_deg);
  //delay(10);
  int roll_deg = map(pitch, -5000, 5000, 0, 179);
  if (roll_deg < 0){roll_deg = 0;};
  if (roll_deg > 179){roll_deg = 179;};
  //rollServo.write(roll_deg);
  //delay(10);
  
  Serial.print ("yaw= ");
  Serial.print (yaw_deg);
  Serial.print ("  pitch= ");
  Serial.print (pitch_deg);
  Serial.print ("  roll= ");
  Serial.print (roll_deg);
  Serial.print ("\r\n");
  delay(10);
   
updateServos(); //update servos with new degrees
delay(10);
}

not to mention, i am running Boardino on usb power and external 3.6v supply for wiimotplus which is original in its case and connected by nunchuck adapter properly (grounds connected)... i am suspicious about, am i using same i/o lines with servos somewhere in the code which i cannot see... servos are on d2 and d3 and i2c inputs are on a4 sda and a5 sdc...

Any chance you are using Arduino Leonardo? The wii is then connected to pins 2 and 3, which are I2C pins, and you are also using them for servos. Just checking.

thank you for your assistance but mem is sufficient, binary code is about 7000 bytes.

Sketch size is flash memory. There is no relationship between the amount of flash memory that is used and the amount of SRAM (not reported) that is used.

 yawServo.attach(2);
 pitchServo.attach(3);  

pinMode(2, OUTPUT);
pinMode(3, OUTPUT);

You told the servo instance that it owned the pin. Why are you then diddling with it?

ludr,
No i am definitely using a Boardino 168... similar to Duomillanove... thanks for your assistance anyway... Arduino 1.0.4 locks up when a servo is activated from inside the program loop ( servos lock and flow of degree data from wiimplus stops on serial monitor)...

PaulS,
saw that and later commented out those two lines... no need to define pins as output once servos are attached...