Arduino / Wii Controlled Lego Star Wars Rocket Turret

8,379

28

9

About: Science museum exhibit design and fabrication manager, stagehand, ballet shoe maker, theatre production manager, project manager and art director of the Beijing Aquarium rainforest exhibit, film extra, archi...

An Arduino board receives data from a Wii Nunchuck and sends it to hree servos: x, y and trigger. An independent laser has been added for targeting. Currently very wobbly because of the cheap servos used.



Step 1: Construction

The rocket turret was built using available Lego pieces around a "trigger" servo. A twitch of the servo when the Z button is pressed on the Wii nunchuck pushes the rocket trigger back, firing it. The base of the trigger servo is attached to x and y servos in a pan/tilt mechanism from Lynxmotion: http://www.lynxmotion.com/images/html/build153.htm

Step 2: Circuit

x axis servo on pin 6, y axis on pin 7, trigger servo on pin 8.
From the Wii nunchuck the yellow clock wire goes to analog in pin 5. Green data wire to analog in pin 4. red wire to 5v power via the breadboard with all the other power jumpers from the servos and white to ground.
9v battery to "vin" pin via an on/off switch.
The laser is not controlled by the Arduino. It is simply a laser attached to  3v battery pack via an on/off switch.


Step 3: Arduino Sketch

// Based on code from http://www.ideavirus.it/ adapted with help from Oliver at London Hackspace. Includes are: wire.h, string.h, stdio.h and Servo.h - for some reason Instructables drops them when I paste my code.

 #include  
 #include  
 #include   
 #include   // controls the trigger servo only
 
 Servo myservo;  // create servo object to control trigger servo

int pos = 90;    // variable to store the trigger servo position

 uint8_t outbuf[6]; 
  
 int cnt = 0; 
 int ledPin = 13; 
 
 int servoPin = 7; 
 int servoPin2 = 6;  
 
 int pulseWidth = 0; 
int pulseWidth2 = 0; 

 long lastPulse = 0; 
 long lastPulse2 = 0; 
 
 int z_button = 0; 
 int c_button = 0; 
  
 int refreshTime = 70;  //tweaked for FutabaS3003 servos
  
 int minPulse = 600;  //tweaked for FutabaS3003 servos
 int minPulse2 = 600;  //tweaked for FutabaS3003 servos
 int maxPulse     =  2400; // maximum servo position
 int maxPuls2e     =  2400; // maximum servo position
 
 int dtime=10; 
  
 #define pwbuffsize 10 
 long pwbuff[pwbuffsize]; 
 long pwbuffpos = 0; 
 long pwbuff2[pwbuffsize]; 
 long pwbuffpos2 = 0; 
  
 void setup() 
 { 
    myservo.attach(8);  // attaches the trigger servo on pin 8 to the servo object
   
     Serial.begin (9600); 
     Wire.begin (); 
     nunchuck_init (); 
     pinMode(servoPin, OUTPUT); 
     pinMode(servoPin2, OUTPUT); 

     pulseWidth = minPulse; 
    pulseWidth2 = minPulse2; 

     Serial.print ("Finished setup\n"); 
 } 
  
 void nunchuck_init() 
 { 
     Wire.beginTransmission (0x52); 
     Wire.send (0x40); 
     Wire.send (0x00);   
     Wire.endTransmission (); 
 } 
  
 void send_zero() 
 { 
     Wire.beginTransmission (0x52); 
     Wire.send (0x00); 
     Wire.endTransmission (); 
 } 
  
 int t = 0; 
  
 void loop() 
 { 
  
     t++; 
     long last = millis(); 
  
     if( t == 1) { 
  
         t = 0; 
  
         Wire.requestFrom (0x52, 6); 
  
         while (Wire.available ()) { 
             outbuf[cnt] = nunchuk_decode_byte (Wire.receive ()); 
             digitalWrite (ledPin, HIGH); 
             cnt++; 
         } 
  
         if (cnt >= 5) { 
  
             int z_button = 0; 
             int c_button = 0; 
  
             if ((outbuf[5] >> 0) & 1)  
                 z_button = 1; 
             if ((outbuf[5] >> 1) & 1) 
                 c_button = 1; 
  
             switch (c_button) { 
             case 1: 
          
             muovi( outbuf[3] ,outbuf[2] ); 
                 break; 
             case 0: 
             muovi( outbuf[1]/2+0x3E ,outbuf[0]/2+0x3E );
                 break; 
             }
          
            switch (z_button) { 
                case 0: 
               
     for(pos = 90; pos >= 120; pos += 1)  // fires trigger when Z button pressed
  {                                 
    myservo.write(pos);             
    delay(15);                       
  }
  for(pos = 120; pos >= 90; pos -= 2)     // returns trigger to center
  {                               
    myservo.write(pos);             
    delay(15);                        
   } 
 
                    break; 
                 case 1: 
                     break; 
       } 
          
       } 
  
         cnt = 0; 
         send_zero(); 
  
   } 
  
     updateServo(); 
  
     delay(dtime); 
 } 
 
 
 void updateServo()
 { 
  
     if (millis() - lastPulse >= refreshTime) { 
 
         digitalWrite(servoPin, HIGH); 
         delayMicroseconds(pulseWidth); 
         digitalWrite(servoPin, LOW); 
  
         digitalWrite(servoPin2, HIGH); 
         delayMicroseconds(pulseWidth2); 
         digitalWrite(servoPin2, LOW); 
 
         lastPulse = millis(); 
     } 
 } 
  
 int i=0; 
 void printNunchuckData() 
 { 
     int joy_x_axis = outbuf[0]; 
     int joy_y_axis = outbuf[1]; 
     int accel_x_axis = outbuf[2]; 
     int accel_y_axis = outbuf[3]; 
     int accel_z_axis = outbuf[4];
  
     int z_button = 0; 
     int c_button = 0; 
  
     if ((outbuf[5] >> 0) & 1)  
         z_button = 1; 
     if ((outbuf[5] >> 1) & 1) 
         c_button = 1; 
     if ((outbuf[5] >> 2) & 1)  
         accel_x_axis += 2; 
     if ((outbuf[5] >> 3) & 1) 
         accel_x_axis += 1; 
 
     if ((outbuf[5] >> 4) & 1) 
         accel_y_axis += 2; 
     if ((outbuf[5] >> 5) & 1) 
         accel_y_axis += 1; 
  
     if ((outbuf[5] >> 6) & 1) 
         accel_z_axis += 2; 
     if ((outbuf[5] >> 7) & 1) 
         accel_z_axis += 1; 
  
     Serial.print (i,DEC); 
     Serial.print ("\t"); 
  
     Serial.print ("X: "); 
     Serial.print (joy_x_axis, DEC); 
     Serial.print ("\t"); 
  
     Serial.print ("Y: "); 
     Serial.print (joy_y_axis, DEC); 
     Serial.print ("\t"); 
  
     Serial.print ("AccX: "); 
     Serial.print (accel_x_axis, DEC); 
     Serial.print ("\t"); 
  
     Serial.print ("AccY: "); 
     Serial.print (accel_y_axis, DEC); 
     Serial.print ("\t"); 
  
     Serial.print ("AccZ: "); 
     Serial.print (accel_z_axis, DEC); 
     Serial.print ("\t"); 
  
     Serial.print (z_button, DEC); 
     Serial.print (" "); 
     Serial.print (c_button, DEC); 
     Serial.print ("\r\n"); 
     i++; 
 } 
  
 char nunchuk_decode_byte (char x) 
 { 
     x = (x ^ 0x17) + 0x17; 
     return x; 
 } 
 
 void muovi ( uint8_t x, uint8_t y){ 
     float tilt = (700 - x*2*2);
     float tilt2 = (0x7E - y + 0x7E) *2*2;
  
     tilt = (tilt); 
     pulseWidth = (tilt * 5) + minPulse; 
  
     tilt2 = (tilt2-288); 
     pulseWidth2 = (tilt2 * 5) + minPulse2; 
  
     pwbuff[pwbuffpos] = pulseWidth; 
     pwbuff2[pwbuffpos2] = pulseWidth2; 
      
     if( ++pwbuffpos == pwbuffsize ) pwbuffpos = 0; 
     if( ++pwbuffpos2 == pwbuffsize ) pwbuffpos2 = 0; 
  
  
     pulseWidth=0; 
     pulseWidth2=0; 
  
     for( int p=0; p          pulseWidth += pwbuff[p]; 
         pulseWidth2 += pwbuff2[p]; 
     } 
  
     pulseWidth /= pwbuffsize; 
     pulseWidth2 /= pwbuffsize; 
  
 } 

Share

    Recommendations

    • PCB Contest

      PCB Contest
    • Puzzle Challenge

      Puzzle Challenge
    • Make it Glow Contest 2018

      Make it Glow Contest 2018

    9 Discussions

    0
    None
    T0BY

    2 years ago

    Awesome idea!

    0
    None
    area36

    6 years ago on Step 3

    I fixed the code issues

    #include
    #include
    #include

    uint8_t outbuf[6];

    int cnt = 0;
    int ledPin = 13;

    int servoPin = 7;
    int servoPin2 = 6;

    int pulseWidth = 0;
    int pulseWidth2 = 0;

    long lastPulse = 0;
    long lastPulse2 = 0;

    int z_button = 0;
    int c_button = 0;

    int refreshTime = 20;

    int minPulse = 1000;
    int minPulse2 = 500;

    int dtime=10;

    #define pwbuffsize 10
    long pwbuff[pwbuffsize];
    long pwbuffpos = 0;
    long pwbuff2[pwbuffsize];
    long pwbuffpos2 = 0;

    void setup()
    {
    Serial.begin (19200);
    Wire.begin ();
    nunchuck_init ();
    pinMode(servoPin, OUTPUT);
    pinMode(servoPin2, OUTPUT);

    pulseWidth = minPulse;
    pulseWidth2 = minPulse2;
    Serial.print ("Finished setup\n");
    }

    void nunchuck_init()
    {
    Wire.beginTransmission (0x52);
    Wire.send (0x40);
    Wire.send (0x00);
    Wire.endTransmission ();
    }

    void send_zero()
    {
    Wire.beginTransmission (0x52);
    Wire.send (0x00);
    Wire.endTransmission ();
    }

    int t = 0;

    void loop()
    {
    t++;
    long last = millis();

    if( t == 1) {

    t = 0;

    Wire.requestFrom (0x52, 6);

    while (Wire.available ()) {
    outbuf[cnt] = nunchuk_decode_byte (Wire.receive ());
    digitalWrite (ledPin, HIGH);
    cnt++;
    }

    if (cnt >= 5) {

    // printNunchuckData();

    int z_button = 0;
    int c_button = 0;

    if ((outbuf[5] >> 0) & 1)
    z_button = 1;
    if ((outbuf[5] >> 1) & 1)
    c_button = 1;

    switch (c_button) {
    case 1:
    switch (z_button) {
    case 0:
    break;
    case 1:
    muovi();
    break;
    }
    break;
    case 0:
    switch (z_button) {
    case 0:
    delay(10000);
    break;
    case 1:
    delay(3000);
    break;
    }
    break;
    }
    }

    cnt = 0;
    send_zero();

    } // if(t==)

    updateServo();

    delay(dtime);
    }


    void updateServo() {

    if (millis() - lastPulse >= refreshTime) {

    digitalWrite(servoPin, HIGH);
    delayMicroseconds(pulseWidth);
    digitalWrite(servoPin, LOW);

    digitalWrite(servoPin2, HIGH);
    delayMicroseconds(pulseWidth2);
    digitalWrite(servoPin2, LOW);

    lastPulse = millis();
    }
    }

    int i=0;
    void printNunchuckData()
    {
    int joy_x_axis = outbuf[0];
    int joy_y_axis = outbuf[1];
    int accel_x_axis = outbuf[2]; // * 2 * 2;
    int accel_y_axis = outbuf[3]; // * 2 * 2;
    int accel_z_axis = outbuf[4]; // * 2 * 2;

    int z_button = 0;
    int c_button = 0;

    if ((outbuf[5] >> 0) & 1)
    z_button = 1;
    if ((outbuf[5] >> 1) & 1)
    c_button = 1;
    if ((outbuf[5] >> 2) & 1)
    accel_x_axis += 2;
    if ((outbuf[5] >> 3) & 1)
    accel_x_axis += 1;

    if ((outbuf[5] >> 4) & 1)
    accel_y_axis += 2;
    if ((outbuf[5] >> 5) & 1)
    accel_y_axis += 1;

    if ((outbuf[5] >> 6) & 1)
    accel_z_axis += 2;
    if ((outbuf[5] >> 7) & 1)
    accel_z_axis += 1;

    Serial.print (i,DEC);
    Serial.print ("\t");

    Serial.print ("X: ");
    Serial.print (joy_x_axis, DEC);
    Serial.print ("\t");

    Serial.print ("Y: ");
    Serial.print (joy_y_axis, DEC);
    Serial.print ("\t");

    Serial.print ("AccX: ");
    Serial.print (accel_x_axis, DEC);
    Serial.print ("\t");

    Serial.print ("AccY: ");
    Serial.print (accel_y_axis, DEC);
    Serial.print ("\t");

    Serial.print ("AccZ: ");
    Serial.print (accel_z_axis, DEC);
    Serial.print ("\t");

    Serial.print (z_button, DEC);
    Serial.print (" ");
    Serial.print (c_button, DEC);
    Serial.print ("\r\n");
    i++;
    }

    char nunchuk_decode_byte (char x)
    {
    x = (x ^ 0x17) + 0x17;
    return x;
    }

    void muovi (){
    float tilt = (700 - outbuf[3]*2*2);
    float tilt2 = outbuf[2]*2*2;

    tilt = (tilt);
    pulseWidth = (tilt * 5) + minPulse;

    tilt2 = (tilt2-288);
    pulseWidth2 = (tilt2 * 5) + minPulse2;

    pwbuff[pwbuffpos] = pulseWidth;
    pwbuff2[pwbuffpos2] = pulseWidth2;

    if( ++pwbuffpos == pwbuffsize ) pwbuffpos = 0;
    if( ++pwbuffpos2 == pwbuffsize ) pwbuffpos2 = 0;


    pulseWidth=0;
    pulseWidth2=0;

    for( int p=0; p pulseWidth += pwbuff[p];
    pulseWidth2 += pwbuff2[p];
    }

    pulseWidth /= pwbuffsize;
    pulseWidth2 /= pwbuffsize;

    }

    0
    None
    area36

    6 years ago on Step 3

    Does anyone have code that does this but it less sensitive to movement. Mine is really hard to stabilize because its so sensitive

    0
    None
    area36

    6 years ago on Step 3

    does anyone have code for this that works?

    0
    None
    Dannne11

    7 years ago on Step 3

    im getting error


    sketch_feb14a.cpp:3:13: error: #include expects "FILENAME" or
    sketch_feb14a.cpp:4:13: error: #include expects "FILENAME" or
    sketch_feb14a.cpp:5:14: error: #include expects "FILENAME" or
    sketch_feb14a.cpp:6:47: error: #include expects "FILENAME" or
    sketch_feb14a:7: error: 'Servo' does not name a type
    sketch_feb14a.cpp: In function 'void setup()':
    sketch_feb14a:45: error: 'myservo' was not declared in this scope
    sketch_feb14a:48: error: 'Wire' was not declared in this scope
    sketch_feb14a.cpp: In function 'void nunchuck_init()':
    sketch_feb14a:61: error: 'Wire' was not declared in this scope
    sketch_feb14a.cpp: In function 'void send_zero()':
    sketch_feb14a:69: error: 'Wire' was not declared in this scope
    sketch_feb14a.cpp: In function 'void loop()':
    sketch_feb14a:86: error: 'Wire' was not declared in this scope
    sketch_feb14a:119: error: 'myservo' was not declared in this scope
    sketch_feb14a:124: error: 'myservo' was not declared in this scope
    sketch_feb14a.cpp: In function 'void muovi(uint8_t, uint8_t)':
    sketch_feb14a:250: error: expected `;' before 'pulseWidth'
    sketch_feb14a:250: error: expected `)' before ';' token
    sketch_feb14a:251: error: name lookup of 'p' changed for new ISO 'for' scoping
    sketch_feb14a:250: error: using obsolete binding at 'p'
    sketch_feb14a.cpp: At global scope:
    sketch_feb14a:254: error: expected constructor, destructor, or type conversion before '/=' token
    sketch_feb14a:255: error: expected constructor, destructor, or type conversion before '/=' token
    sketch_feb14a:257: error: expected declaration before '}' token

    1 reply
    0
    None
    Jonathan RobsonDannne11

    Reply 6 years ago on Step 3

    Please read step 3 carefully. It looks like you didn't add the includes correctly.

    0
    None
    biomech75

    6 years ago on Introduction

    2 solutions:
    1. try using version 23 for the Arduino Software.
    2. Tell the author of this tutorial to try and fix the code.

    0
    None
    lemon rind

    8 years ago on Introduction

    Thats pretty cool man. Definitely needs better servos though!