This project started life as a challenge.
The local Robot Club (who spend time on everything except robots) was looking to get back into robots since they had a sumo ring.
We talked about making something small and decided on the 300g class.
It allowed for new and younger members to make something which could compete, and wouldn't cost a fortune, or require lifting gear.
Nintendo Wii
Since our bots were not intended to be autonomous, a method of controlling the bot was required.
As many people know the Nintendo company make a very good gaming platform.
One of the spin-offs was their Nunchuck, and as expected third party suppliers developed a wireless version of the Nunchuck.
The interface to the Wiimote is I2C which is ideal to interface to a microcontroller..
Using one of these provided all the control necessary in a very cheap package.
Chassis
The chassis is a lightweight wedge design.
The idea was to lift the competitor rendering them immobile and therefore securing a victory.
I made it oversized and then flipped it upside down and scribed the finished height with a small taper towards the rear.
It is configured as a "tail drager" which is a term used on planes where the tail is supported by a piece of metal and is dragged across the surface, rather than having a proper wheel.
In this case I used a plastic bolt and rounded and smoothed it using a battery drill.
Electronics
The black box houses an Arduino Nano, and some Mosfet driver IC's.
The pictures show an 11.1 volt Lithium battery, but it works on a 7.2 volt battery which is lighter and allowed it to weigh 305grams.
The higher voltage battery was an attempt to eliminate a glitch that caused the loss of connection between the Nunchuck joystick and the receiver.
Sadly it also overtaxed the original mosfet drivers which emitted the magic smoke and stopped working.
Software
The controller is an Arduino, and the biggest part is the motor control.
The joystick provides a value between 0 and 255 in the x direction and a 0 to 255 in the y direction. This is converted and provides proportional control.
The C button allows the behaviour to be modified.
For movement at full lock, the default is to just power the applicable motor, while leaving the other wheel stopped.
But by operating the button, the software will drive the opposite motor in the other direction, meaning it will rotate on the other wheel.
There is a glitch that I've never got to the bottom of, where the Joystick (transmitter) and the receiver lose connection.
The connection is manual and when it occurs there is no method of detecting it in the software, so consequently it can take off when you least expect it.
I managed to tame it by improving the power supply to the receiver, but I suspect more work is needed before I can tick it off the list.
/* ....................................................................... Code to control a robot using a Wii Nunchuk most of the Wii code was from the Arduino forum ..thanks to the many contributors. Here is the bitmapping for the standard nunchuk mapping 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-----------------------------------------------------2> 5 AZ<1----0> AY<1-------0> AX<1-------0> BC BZ The Arduino I2C uses 7 bits, therefore the MP address (0xA6) becomes 0x53, and the (0xA4) becomes 0x52 Hardware Arduino with ATMega 328 Connections Pin assignments Analog4 SCA with pullup of 2k7 to 3.3 volts Analog5 SCL with pullup of 2k7 to 3.3 volts Pin 3 (pwm) Right Motor enable Pin 4 In1 Stepper Pin 5 In2 Stepper Pin 6 In3 Stepper Pin 7 In4 Stepper Pin 11 (pwm)Left Motor enable Pin 12 Forward motor control Pin 13 Reverse motor control Nunchuk gets 3.3v There isn't much else as it was designed for a 300g robot, and I wanted some protection. Modified by Mark Beckett July 2010 References: _ _ _ | |__ | |_| |_ _ __ | '_ \| __| __| '_ \ | | | | |_| |_| |_) | |_| |_|\__|\__| .__/ |_| http://www.network-science.de/ascii/ for font (standard, no, left, no, 80) Nunchuk plug details are at http://voidbot.net/wii-addapter.html (thanks very much) ************************************ To Do: Detect if the interface has disconnected and don't go full speed. Tidy the code around the seering area ...(hey it was late Sunday night and complex equations hurt my head) Allow for instances where all four motor control pins are PWM capable. (allows for spinning on the spot) Include controls for a lifting weapon using the Z button and the joystick. ************************************ The Serial.print lines have been commented out, as they are unecessary when in use. Feel free to uncomment them during debugging. MCB */ //setup the variables, etc //int ledPin = 13; int xID; #define STEPS 64 //Number of steps per revolution //Nunchuck uint8_t outbuf[6]; //nunchuck buffer for data //int cnt = 0; //nunchuck buffer counter int joy_x_axis; //Joystick x (8 bits) int joy_y_axis; //Joystick y (8 bits) int z_button; int c_button; // Motor Movement I used the pins that match some of the common motor shields. int RightEn = 3; //Pin 3 Right Enable int LeftEn = 11; //Pin 11 Left Enable int Forward = 12; //Pin 12 Forward int Reverse = 13; //Pin 13 Reverse int Speed; // This is the amount of forward/reverse applied int RightAmount; // This is the PWM amount sent to the RightEn pin int LeftAmount; // This is the PWM amount sent to the LeftEn pin int RightCorrection; // Right reduction to match left motor (0 to 100) int LeftCorrection; // Left reduction to match right motor (0 to 100) int Steps2Take; Stepper small_stepper(STEPS, 4, 6, 5, 7); //Wii Nunchuk byte data[6]; //buffer for WM+ data /* ____ _ / ___| ___| |_ _ _ _ __ \___ \ / _ \ __| | | | '_ \ ___) | __/ |_| |_| | |_) | |____/ \___|\__|\__,_| .__/ |_| */ void setup (){ Serial.begin (19200); pinMode(Forward, OUTPUT); pinMode(Reverse, OUTPUT); RightCorrection = 100; // Reduce if right motor is faster than left motor LeftCorrection = 100; // Reduce if left motor is faster than right motor // use this after ensuring that joy_x_axis at centre is 128 by uncommenting the first line in motor control. Wire.begin(); //Serial.print ("Finished setup\n"); //Serial.print ("Now detecting WM+\n"); delay(100); // initiate Wii Nunchuk //Serial.print ("Initialising Wii Nunchuk ........"); Wire.beginTransmission(0x52); //0xA4 Wire.send(0xF0); Wire.send(0x55); Wire.endTransmission(); //Serial.print (" OK done"); //Serial.print ("\r\n"); delay (100); //Serial.print ("Set reading address at 0xFA ......."); Wire.beginTransmission(0x52); //0xA4 Wire.send(0xFA); Wire.endTransmission(); //Serial.print(" OK done"); //Serial.print ("\r\n"); delay (100); Wire.requestFrom (0x52,6); //0xA4 outbuf[0] = Wire.receive();//Serial.print(outbuf[0],HEX);Serial.print(" "); outbuf[1] = Wire.receive();//Serial.print(outbuf[1],HEX);Serial.print(" "); outbuf[2] = Wire.receive();//Serial.print(outbuf[2],HEX);Serial.print(" "); outbuf[3] = Wire.receive();//Serial.print(outbuf[3],HEX);Serial.print(" "); outbuf[4] = Wire.receive();//Serial.print(outbuf[4],HEX);Serial.print(" "); outbuf[5] = Wire.receive();//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); //delay (200); //if (xID == 0xCB) { Serial.print (" Wii Motion plus connected but not activated"); } // 00 00 A6 20 00 05 //if (xID == 0xCE) { Serial.print (" Wii Motion plus connected and NC activated"); } // 00 00 A4 20 00 05 //if (xID == 0x00) { Serial.print (" Wii Motion plus not connected"); } // 00 00 00 00 00 00 //Serial.print ("\r\n"); delay (500); // 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.send(0x08); Wire.endTransmission(); //Serial.print(" OK done"); // Serial.print ("\r\n"); //lcd.clear(); } void send_zero (){ Wire.beginTransmission(0x52); Wire.send(0x00); Wire.endTransmission(); } /* _ | | ___ ___ _ __ | | / _ \ / _ \| '_ \ | |__| (_) | (_) | |_) | |_____\___/ \___/| .__/ |_| */ void loop (){ send_zero (); // send the request for next bytes delay (100); Wire.requestFrom (0x52,6); // Collect all 5 Bytes of data. outbuf[0] = Wire.receive(); outbuf[1] = Wire.receive(); outbuf[2] = Wire.receive(); outbuf[3] = Wire.receive(); outbuf[4] = Wire.receive(); outbuf[5] = Wire.receive(); joy_x_axis = outbuf[0]; // Left or Right joy_y_axis = outbuf[1]; // Forward or Reverse z_button = (outbuf[5]>>0) & 1; // Byte 5 Bit 0 c_button = (outbuf[5]>>1) & 1; // Byte 5 Bit 1 (shift it 1 place so its either a 1 or 0, rather than 2 or 0) ButtonDetect(); //if (z_button ==0) // If we push the Z button is weapon time motorcontrol (); // call the process to do something with the data //print (); //cnt = 0; } /* __ __ _ ____ _ _ | \/ | ___ | |_ ___ _ __ / ___|___ _ __ | |_ _ __ ___ | | | |\/| |/ _ \| __/ _ \| '__| | | / _ \| '_ \| __| '__/ _ \| | | | | | (_) | || (_) | | | |__| (_) | | | | |_| | | (_) | | |_| |_|\___/ \__\___/|_| \____\___/|_| |_|\__|_| \___/|_| */ void motorcontrol(){ /* This process decides which direction and by how much */ if ((joy_y_axis) == 128 && (joy_x_axis) == 128){ //stopped Speed = 0; digitalWrite(Forward, LOW); digitalWrite(Reverse, LOW); } if ((joy_y_axis) > 128){ //forward digitalWrite(Forward, HIGH); digitalWrite(Reverse, LOW); /* map takes the number and changes it to the desired range In the case below it maps a 128 to 0, and a 255 to 255. The joystick at centre should be 128. Fully back is 0, while fully forward is 255. We treat centre as 0, and fully forward or fully back as 255. */ Speed = map(joy_y_axis, 128, 255, 0, 255); } if ((joy_y_axis) < 128){ //reverse digitalWrite(Reverse, HIGH); digitalWrite(Forward, LOW); Speed = map(joy_y_axis, 128, 0, 0, 255); } /* ____ _ _ / ___|| |_ ___ ___ _ __(_)_ __ __ _ \___ \| __/ _ \/ _ \ '__| | '_ \ / _` | ___) | || __/ __/ | | | | | | (_| | |____/ \__\___|\___|_| |_|_| |_|\__, | |___/ Forward and Right means the left motor goes faster Backwards and Right means the left motor goes faster For the spin, most motor controls have a single direction for both motors. They use only two PWM pins so the others are available for other things. Effectively we can't make one motor go forward, and the other backwards. A normal spin will see the BOT move forward heading in the direction of turn. If the C Button is pressed, it will move backwards in the direction of turn. The joystick at centre should be 128. Fully left is 0, while fully right is 255. We treat centre as 0, and fully Left or fully Right as 100. We then apportion that to the appropriate motor based on the speed value */ //Serial.println(joy_x_axis, DEC); // uncomment before attempting motor correction if (joy_x_axis == 128){ // centre analogWrite(RightEn,(abs(Speed*RightCorrection/100))); analogWrite(LeftEn, (abs(Speed*LeftCorrection/100))); } if ((joy_x_axis) > 128 && (joy_y_axis) != 128){ // Right with some fwd/rev RightAmount = map(joy_x_axis, 128, 255, 100, 0); analogWrite(RightEn,((Speed * RightAmount)/100)); analogWrite(LeftEn,Speed); } else if ((joy_x_axis) > 128 && (joy_y_axis) == 128){ // Spin to the right with no fwd/rev LeftAmount = map(joy_x_axis, 128, 255, 0, 255); // right axis reading fed into Left motor if (c_button == 1) { digitalWrite(Reverse, LOW); digitalWrite(Forward, HIGH); } else // reverse spin { digitalWrite(Reverse, HIGH); digitalWrite(Forward, LOW); } analogWrite(LeftEn, LeftAmount); // Left motor forward } if ((joy_x_axis) < 128 && (joy_y_axis) != 128){ // Left with fwd/rev LeftAmount = map(joy_x_axis, 128, 0, 100, 0); analogWrite(LeftEn,((Speed * LeftAmount)/100)); analogWrite(RightEn, Speed); } else if ((joy_x_axis) < 128 && (joy_y_axis) == 128){ // Spin to the left with NO fwd/rev RightAmount = map(joy_x_axis, 128, 0, 0, 255); // left axis reading fed into Right motor if (c_button == 1) { digitalWrite(Reverse, LOW); digitalWrite(Forward, HIGH); } else // Spin turning in a reverse motion { digitalWrite(Reverse, HIGH); digitalWrite(Forward, LOW); } analogWrite(RightEn,RightAmount); //Left motor forward } } void ButtonDetect() { // this process checks to see what is pressed. if ((z_button == 0)&&(c_button ==0)) { small_stepper.setSpeed(200); Steps2Take = -16; // Rotate CW small_stepper.step(Steps2Take); } else if (z_button ==0) { //Serial.println ("Z Button"); small_stepper.setSpeed(200); Steps2Take = 16; // Rotate CW small_stepper.step(Steps2Take); } else if (c_button == 0) { //Serial.println ("C Button"); } // small_stepper.setSpeed(200); // Steps2Take = 2; // Rotate CW // small_stepper.step(Steps2Take); // //delay(2000); // // small_stepper.setSpeed(200); // 200 a good max speed?? // Steps2Take = -2; // Rotate CCW // small_stepper.step(Steps2Take); // //delay(2000); } /* ____ _ _ | _ \ _ __(_)_ __ | |_ | |_) | '__| | '_ \| __| | __/| | | | | | | |_ |_| |_| |_|_| |_|\__| You can uncomment the call to print() if you want debugging data You may wish to comment out some and shift where the print() is located. Each char printed takes an amount of time, and hence leaving it in slows down the loop time. For testing it is not noticeable, but may be when operating. */ void print(){ delay (100); //slow down the printing int joy_x_axis = outbuf[0]; int joy_y_axis = outbuf[1]; int z_button = (outbuf[5]>>0) & 1; int c_button = (outbuf[5]>>1) & 1; Serial.print ("joyx= "); Serial.print (joy_x_axis, DEC); Serial.print (" joyy="); Serial.print (joy_y_axis, DEC); Serial.print (" "); if (z_button == 0) { Serial.print ("z_button "); } if (c_button == 0) { Serial.print ("c_button "); } Serial.print ("\r\n"); Serial.print("joyy= " ); Serial.print (joy_y_axis, DEC); Serial.print(" Fwd Speed= "); Serial.print (Speed); Serial.println(); Serial.print("joyx= " ); Serial.print (joy_x_axis, DEC); Serial.print(" Left pwm= "); Serial.print((Speed * LeftAmount)/100); Serial.print(" Right pwm= "); Serial.print((Speed * RightAmount)/100); Serial.println(); }
This was the first version of software, and includes some of the features along with various print statements for debugging.
The button() routine was originally or a stepper motor and hasn't been removed.
/* ....................................................................... Code to control a robot using a Wii Nunchuk most of the Wii code was from the Arduino forum ..thanks to the many contributors. Here is the bitmapping for the standard nunchuk mapping 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-----------------------------------------------------2> 5 AZ<1----0> AY<1-------0> AX<1-------0> BC BZ Hardware Arduino with ATMega 328 Connections SCA to AD4 (Analog4) with pullup of 2k7 to 3.3 volts SCL to AD5 (Analog5) with pullup of 2k7 to 3.3 volts Connections to IR4427P chips are :- Pin 3 to 2 (Left Motor)Left2 Pin 5 to 4 (Left Motor)Left1 Pin 6 to 2 (Right Motor)Right2 Pin 9 to 4 (Rigtht Motor)Right1 There isn't anything else as it was designed for a 300g robot, and I wanted some protection The Arduino I2C uses 7 bits, therefore the MP address (0xA6) becomes 0x53, and the (0xA4) becomes 0x52 Modified by Mark Beckett jun 2010 ************************************ To Do Detect if the interface has disconnected and don't go full speed. Use something other than a Rugged Circuit driver which needs 8v to run. Reduce weight to enable a lifting motor on the front */ #include #include #include //setup the variables, etc //int ledPin = 13; int xID; //Nunchuck uint8_t outbuf[6]; //nunchuck buffer for data int cnt = 0; //nunchuck buffer counter int joy_x_axis; //Joystick x (8 bits) int joy_y_axis; //Joystick y (8 bits) int z_button; int c_button; // Motor Movement int Left2 = 3; int Left1 = 5; int Right2 = 6; int Right1 = 9; int Speed; int RightAmount; int LeftAmount; //Wii Nunchuk byte data[6]; //buffer for WM+ data void setup (){ Serial.begin (19200); pinMode(Right1, OUTPUT); pinMode(Right2, OUTPUT); pinMode(Left1, OUTPUT); pinMode(Left2, OUTPUT); Wire.begin(); Serial.print ("Finished setup\n"); Serial.print ("Now detecting WM+\n"); delay(100); // initiate Wii Nunchuk Serial.print ("Initialising Wii Nunchuk ........"); Wire.beginTransmission(0x52); //0xA4 Wire.send(0xF0); Wire.send(0x55); Wire.endTransmission(); Serial.print (" OK done"); Serial.print ("\r\n"); delay (100); Serial.print ("Set reading address at 0xFA ......."); Wire.beginTransmission(0x52); //0xA4 Wire.send(0xFA); Wire.endTransmission(); Serial.print(" OK done"); Serial.print ("\r\n"); delay (100); Wire.requestFrom (0x52,6); //0xA4 outbuf[0] = Wire.receive(); //Serial.print(outbuf[0],HEX);Serial.print(" "); outbuf[1] = Wire.receive(); //Serial.print(outbuf[1],HEX);Serial.print(" "); outbuf[2] = Wire.receive(); //Serial.print(outbuf[2],HEX);Serial.print(" "); outbuf[3] = Wire.receive(); //Serial.print(outbuf[3],HEX);Serial.print(" "); outbuf[4] = Wire.receive(); //Serial.print(outbuf[4],HEX);Serial.print(" "); outbuf[5] = Wire.receive(); //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); //delay (200); //if (xID == 0xCB) { Serial.print (" Wii Motion plus connected but not activated"); } // 00 00 A6 20 00 05 //if (xID == 0xCE) { Serial.print (" Wii Motion plus connected and NC activated"); } // 00 00 A4 20 00 05 //if (xID == 0x00) { Serial.print (" Wii Motion plus not connected"); } // 00 00 00 00 00 00 //Serial.print ("\r\n"); delay (500); // 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.send(0x08); Wire.endTransmission(); //Serial.print(" OK done"); //Serial.print ("\r\n"); //lcd.clear(); } void send_zero (){ Wire.beginTransmission(0x52); Wire.send(0x00); Wire.endTransmission(); } void loop (){ // 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.receive(); outbuf[1] = Wire.receive(); outbuf[2] = Wire.receive(); outbuf[3] = Wire.receive(); outbuf[4] = Wire.receive(); outbuf[5] = Wire.receive(); joy_x_axis = outbuf[0]; joy_y_axis = outbuf[1]; z_button = (outbuf[5]>>0) & 1; c_button = (outbuf[5]>>1) & 1; motorcontrol(); cnt = 0; } void motorcontrol(){ // this bit decides which direction and by how much //Steering //Forward and right means the left motor goes faster //Backwards and right means the left motor goes faster //if (joy_x_axis == 128) //centre // { RightAmount = map(joy_x_axis, 128, 255, 100, 0); LeftAmount = map(joy_x_axis, 0, 128, 0, 100); // } if ((joy_y_axis) == 128 && (joy_x_axis) == 128) //stopped { //Speed = 0; digitalWrite(Right1, LOW); digitalWrite(Right2, LOW); digitalWrite(Left1, LOW); digitalWrite(Left2, LOW); } if ((joy_y_axis) > 128) //forward { digitalWrite(Right2, LOW); digitalWrite(Left2, LOW); Speed = map(joy_y_axis, 128, 255, 0, 255); analogWrite(Right1,((Speed * RightAmount)/100)); analogWrite(Left1,((Speed * LeftAmount)/100)); } if ((joy_y_axis) < 128) //reverse { digitalWrite(Right1, LOW); digitalWrite(Left1, LOW); Speed = map(joy_y_axis, 0, 128, 255, 0); analogWrite(Right2,((Speed * RightAmount)/100)); analogWrite(Left2,((Speed * LeftAmount)/100)); } /* //Steering //Forward and right means the left motor goes faster //Backwards and right means the left motor goes faster if (joy_x_axis == 128) //centre { analogWrite(Right2,Speed); analogWrite(Left2, Speed); } if ((joy_x_axis) > 128 && (joy_y_axis) != 128) //right with fwd/rev { RightAmount = map(joy_x_axis, 128, 255, 100, 0); analogWrite(Right2,((Speed * RightAmount)/100)); analogWrite(Left2,Speed); } else if ((joy_x_axis) > 128 && (joy_y_axis) == 128) //spin to the right with no fwd/rev { LeftAmount = map(joy_x_axis, 128, 255, 0, 255); // right axis reading fed into left motor if (c_button == 1) { digitalWrite(Right1, LOW); digitalWrite(Left1, HIGH); } else //reverse { digitalWrite(Right1, HIGH); digitalWrite(Left1, LOW); } analogWrite(Left2, LeftAmount); //Left motor forward } if ((joy_x_axis) < 128 && (joy_y_axis) != 128){ // left with fwd/rev LeftAmount = map(joy_x_axis, 128, 0, 100, 0); analogWrite(Left2,((Speed * LeftAmount)/100)); analogWrite(Right2, Speed); } else if ((joy_x_axis) < 128 && (joy_y_axis) == 128){ // left with no fwd/rev RightAmount = map(joy_x_axis, 128, 0, 0, 255); // left axis reading fed into right motor if (c_button == 1) { digitalWrite(Right1, LOW); digitalWrite(Left1, HIGH); } else //reverse { digitalWrite(Right1, HIGH); digitalWrite(Left1, LOW); } analogWrite(Right2,RightAmount); //Left motor forward } */ }
The software I've included is not polished and is a WIP.
However this should provide a starting point for anyone wanting to make a bot using the Nintendo Wii Nunchuck as the controller.
Performance.
When we first discussed this idea, there were three others keen to develop something, but they never progressed to a working model.
We did have a token battle against a Lego based bot that weighed 2kg, had 8 wheels and covered a large amount of the ring. My 305 gram tiny bot didn't really disgrace itself.
The control mechanism used a smartphone which compromised the ability to move quickly, so I had better speed and maneuverability, but I was very much outgunned in the weight department, so couldn't move it out the ring.
In one battle I did manage to make it very hard to move, however hanging around while the operator changed his approach wasn't a good idea.
We decided to try the push test and while the tyres remained gripping the surface, it lacked the energy needed to move the other.
My software hadn't allowed for dynamic braking, as consequently if it was being pushed you needed to apply some forward control.
Enhancements
There is a few more grams required to be removed to meet the 300g class.
I haven't removed any of the wireless case or the connector as I was still testing it.
The connector allowed a corded version Nunchuck to be used, and was intended to be removed eventually.
The software needs dynamic braking and could use one of the buttons.
I'm sure the glitch that sees the receiver drop-out is related to power, but needs further investigation.
I haven't even put an oscilloscope near it to see how bad it is.
The battery mounting needs something to help competitors to slide over the top, rather than having a surface to push against.
This could also be applied to the wheels to make them less of a target.
Video
Taking video while operating controls and trying to drive in the confines of an A4 paper box lid ... is a challenge.
I couldn't manage to include the controller as well ... but you can guess it was getting moved.
Cheers
Mark
Top Comments