Step 11: Predator cannon

Example 7- Predator cannon

Using a modified Wii nunchuck board we can make a "head tracking" system to control an animatronic Predator cannon. This system was designed to look like the cannon mechanism in the first Predator movie.

The nunchuck board is removed from its case, the joystick is removed and the board is placed level in the top of the Predator Bio helmet. The wires are extended for the buttons so they can be used as fingertip buttons to activate the cannon and trigger the firing sequence.

To remove the circuit board from the Wii nunchuck case you'll need a tri-wing screwdriver-

The sound effect is handled just like the Iron Man repulsor in example 4 using the Adafruit Wave Shield. Since the Wave Shield code used can support six individual sounds you can add five other Predator sounds and activate them using fingertip switches- neat!

There is one servo that is geared 4:1 that raises the cannon arm- in the code you can see this as the servo rotating 180 degrees, thereby raising the cannon arm 45 degrees. The other two servos aim the cannon using the accelerometer inputs. There are transistors that turn on the aiming servos and laser sight when one button is pressed. If the aiming servos were always on then the cannon would rotate even when it was in the lowered position, so they need a way of being turned off when the cannon is lowered.

So push one one button and the cannon raises up, the aiming servos turn on and the laser sight turns on. Push the second button and the cannon fires- two transistors turn on the cannon LED and activate the firing sound. Three red LEDs can be used in place of the laser sight. The cannon LED can be anything from several small LEDs to a high power Luxeon LED. When using a high power Luxeon LED be sure to use a constant current driver to power it.

Servos can draw a fair bit of power so I use a TIP 120 transistor to turn on the aiming servos.

The prototype cannon mechanism was built using Delrin plastic scraps and timing belts and gears from old desktop printers and photocopiers I found in the trash. When I build the final version for the Predator costume it will probably be entirely gear driven to make it more compact and cleaner.

For Predator costuming info check out http://www.thehunterslair.com

Those individuals interested in obtaining a resin cannon casting should contact my friend Carl here- http://www.accurizedhunterparts.com/

Carl's work is absolutely brilliant- check out the photos below of the Predator backpack clay sculpt that he created for this project. That's a lot of clay! When contacting Carl please be patient as he's extremely busy and he has a large backlog of work.

Here's the code-

 * Example 7
 * Predator Cannon
 * This uses a modified Wii nunchuck as a head tracking input device to control an animatronic Predator cannon
 * Adafruit Wave shield is used for sound effects
 * Honus 2007, updated 2010
 * Wii nunchuck reading code modified/extended from nunchuck code by Tod E. Kurt and Windmeadow Labs
 * 2007 Tod E. Kurt, http://todbot.com/blog/
 * The Wii Nunchuck reading code is taken from Windmeadow Labs, http://www.windmeadow.com/node/42

#include  "Wire.h" // include the Wire library
#include   "Servo.h" // include the servo library

Servo servo3;  // creates an instance of the servo object to control a servo

int controlPin1 = 6; // Control pin for sound effects board using z button
int transistorPin1 = 13; // Control pin for LED using z button
int transistorPin2 = 12; // Control pin for laser sight using c button
int transistorPin3 = 11; // Control pin for servo 1 using c button
int transistorPin4 = 10; // Control pin for servo 2 using c button
int servoPin1 = 7; // Control pin for servo 1 using accelerometer x axis
int servoPin2 = 8; // Control pin for servo 2 using accelerometer y axis
int servoPin3 = 9;  // control pin for arm servo

int pulseWidth1 = 0; // Amount to pulse the servo 1
int pulseWidth2 = 0; // Amount to pulse the servo 2

int refreshTime = 20; // the time in millisecs needed in between servo pulses
long lastPulse1;
long lastPulse2;

int minPulse = 700; // minimum servo pulse width
int loop_cnt=0;

boolean button_down = false;
unsigned long start;

void setup()

servo3.attach(servoPin3);  // attaches the servo on pin 9 to the servo object
pinMode(controlPin1, OUTPUT); // Set control pin 1 as output
pinMode(transistorPin1, OUTPUT); // Set transistor pin 1 as output
pinMode(transistorPin2, OUTPUT); // Set transistor pin 2 as output
pinMode(transistorPin3, OUTPUT); // Set transistor pin 3 as output
pinMode(transistorPin4, OUTPUT); // Set transistor pin 4 as output
pinMode(servoPin1, OUTPUT); // Set servo pin 1 as output
pinMode(servoPin2, OUTPUT); // Set servo pin 2 as output

pulseWidth1 = minPulse; // Set the servo position to the minimum
pulseWidth2 = minPulse; // Set the servo position to the minimum

nunchuck_init(); // send the initilization handshake
Serial.print("NunchuckServo ready\n");

void loop()
updateServo1(); // update servo 1 position
updateServo2(); // update servo 2 position

if( nunchuck_cbutton() ) {
digitalWrite(transistorPin2, HIGH); // turn on transistor pin 2 if c button is pressed
digitalWrite(transistorPin3, HIGH); // turn on transistor pin 3 if c button is pressed
digitalWrite(transistorPin4, HIGH); // turn on transistor pin 4 if c button is pressed

else {
digitalWrite(transistorPin2, LOW);
digitalWrite(transistorPin3, LOW);
digitalWrite(transistorPin4, LOW);

if ( nunchuck_zbutton() )
if (!button_down) // if button was just pressed do this
digitalWrite(controlPin1, HIGH);
button_down = true;
start = millis();
else if (millis() - start > 1200)  // if timer has elapsed do this
digitalWrite(transistorPin1, HIGH);
else // if button is up do this
button_down = false;
digitalWrite(controlPin1, LOW);
digitalWrite(transistorPin1, LOW);

delay(1); // this is here to give a known time per loop

void checkNunchuck1()
if( loop_cnt > 100 ) { // loop()s is every 1msec, this is every 100msec


float tilt = nunchuck_accelx(); // x-axis, in this case ranges from ~70 - ~185
tilt = (tilt - 70) * 1.5; // convert to angle in degrees, roughly
pulseWidth1 = (tilt * 9) + minPulse; // convert angle to microseconds

loop_cnt = 0; // reset for


// called every loop().
// uses global variables servoPin, pulsewidth, lastPulse, & refreshTime
void updateServo1()
// pulse the servo again if rhe refresh time (20 ms) have passed:
if (millis() - lastPulse1 >= refreshTime) {
digitalWrite(servoPin1, HIGH); // Turn the servo on
delayMicroseconds(pulseWidth1); // Length of the pulse sets the servo position
digitalWrite(servoPin1, LOW); // Turn the servo off
lastPulse1 = millis(); // save the time of the last pulse

void checkNunchuck2()
if( loop_cnt > 100 ) { // loop()s is every 1msec, this is every 100msec


float tilt = nunchuck_accely(); // y-axis, in this case ranges from ~70 - ~185
tilt = (tilt - 70) * 1.5; // convert to angle in degrees, roughly
pulseWidth2 = (tilt * 9) + minPulse; // convert angle to microseconds

loop_cnt = 0; // reset for


// called every loop().
// uses global variables servoPin, pulsewidth, lastPulse, & refreshTime
void updateServo2()
// pulse the servo again if rhe refresh time (20 ms) have passed:
if (millis() - lastPulse2 >= refreshTime) {
digitalWrite(servoPin2, HIGH);  // Turn the servo on
delayMicroseconds(pulseWidth2); // Length of the pulse sets the servo position
digitalWrite(servoPin2, LOW); // Turn the servo off
lastPulse2 = millis(); // save the time of the last pulse

// Nunchuck functions

static uint8_t nunchuck_buf[6]; // array to store nunchuck data,

// initialize the I2C system, join the I2C bus,
// and tell the nunchuck we're talking to it
void nunchuck_init()
Wire.begin(); // join i2c bus as master
Wire.beginTransmission(0x52); // transmit to device 0x52
Wire.send(0x40); // sends memory address
Wire.send(0x00); // sends sent a zero.
Wire.endTransmission(); // stop transmitting

// Send a request for data to the nunchuck
// was "send_zero()"
void nunchuck_send_request()
Wire.beginTransmission(0x52); // transmit to device 0x52
Wire.send(0x00); // sends one byte
Wire.endTransmission(); // stop transmitting

// Receive data back from the nunchuck,
// returns 1 on successful read. returns 0 on failure
int nunchuck_get_data()
int cnt=0;
Wire.requestFrom (0x52, 6); // request data from nunchuck
while (Wire.available ()) {
// receive byte as an integer
nunchuck_buf[cnt] = nunchuk_decode_byte(Wire.receive());
nunchuck_send_request(); // send request for next data payload
// If we recieved the 6 bytes, then go print them
if (cnt >= 5) {
return 1; // success
return 0; //failure

// Print the input data we have recieved
// accel data is 10 bits long
// so we read 8 bits, then we have to add
// on the last 2 bits. That is why I
// multiply them by 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] contains bits for z and c buttons
// it also contains the least significant bits for the accelerometer data
// so we have to check each bit of byte outbuf[5]
if ((nunchuck_buf[5] >> 0) & 1)
z_button = 1;
if ((nunchuck_buf[5] >> 1) & 1)
c_button = 1;

if ((nunchuck_buf[5] >> 2) & 1)
accel_x_axis += 2;
if ((nunchuck_buf[5] >> 3) & 1)
accel_x_axis += 1;

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

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


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

Serial.print(accel_x_axis, DEC);
Serial.print(accel_y_axis, DEC);
Serial.print(accel_z_axis, DEC);

Serial.print(z_button, DEC);
Serial.print(c_button, DEC);

Serial.print("\r\n"); // newline

// Encode data to format that most wiimote drivers except
// only needed if you use one of the regular wiimote drivers
char nunchuk_decode_byte (char x)
x = (x ^ 0x17) + 0x17;
return x;

// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_zbutton()
return ((nunchuck_buf[5] >> 0) & 1) ? 0 : 1; // voodoo

// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_cbutton()
return ((nunchuck_buf[5] >> 1) & 1) ? 0 : 1; // voodoo

// returns value of x-axis joystick
int nunchuck_joyx()
return nunchuck_buf[0];

// returns value of y-axis joystick
int nunchuck_joyy()
return nunchuck_buf[1];

// returns value of x-axis accelerometer
int nunchuck_accelx()
return nunchuck_buf[2]; // FIXME: this leaves out 2-bits of the data

// returns value of y-axis accelerometer
int nunchuck_accely()
return nunchuck_buf[3]; // FIXME: this leaves out 2-bits of the data

// returns value of z-axis accelerometer
int nunchuck_accelz()
return nunchuck_buf[4]; // FIXME: this leaves out 2-bits of the data
Snarkticon2 years ago
What would it take to adapt this setup to be used in your Horus helmet rig? I just ordered an arduino board to get started and would love to be able to track my own head movements to the bird's head.
Honus (author)  Snarkticon2 years ago
I've had a few people ask about this. The problem is that you can't really move your head that much while wearing the Horus helmet. The great bit with the Horus helmet is that your head stays still and ONLY the bird head moves. The lower part of the Horus helmet really does not move- the movie helmets only had a few degrees of rotation between the lower part of the helmet and the neck collar.
would it possible or do you know of where id get a servo pcb like yours without much trouble as im useless with soldering.
Honus (author)  vivianprendergast253 years ago
What do you mean by servo pcb? All of the bare circuit boards are available- they're listed on the tools and materials page. Do you mean you need someone to build it for you?
thepred20123 years ago
Would you be willing to do another one and sell it? I am no electrical genius, even the code confused me...I am trying to put a good predator outfit together for 2014 Comicon. Any help is appreciated. You are truely gifted!

Honus (author)  thepred20123 years ago
Once my friend gets the backpack and cannon finished kits will be offered. No idea on pricing yet but hopefully soon.
c_Dub10823 years ago
First I want to say I love your project. I have been wanting to do something similar for a very long time. Love the movie as well. I am currently doing the project for my senior project and things are going ok. We are haveing some issues with the x-axis on the accelerometer. It seems that in order to pan the x-axis we have to do a barrel role with the accelerometer. We tried all kinds of orientations but it will not work any other way. Any suggestions??
Thanks man, we finally got the orientation right. You were right that it takes a little getting used to. We appreciate it.
Honus (author)  c_Dub10823 years ago
Cool- if you have any other questions just let me know!
Honus (author)  c_Dub10823 years ago
Accelerometers only work with respect to gravity so that is why it works the way it does. There is further explanation in the FAQ section.
do you sell this mechanism? i dont understand if you control it or if it has a motion sensor. Thansk, its awesome
Honus (author)  cpaternoster3 years ago
Not yet- I'm waiting for the complete backpack to be finished. The person wearing the costume controls it. You have two fingertip buttons- one activates the cannon and the other "fires" it. When the cannon is activated it raises into the firing position and tracks your head movements.
how long did it take to build the cannon?
Honus (author)  jackjackattack4 years ago
If you mean just the cannon resin casting my friend makes them. As far as the cannon arm design goes I'm in the middle of redesigning it right now.