Bare bones head tracking shoulder cannon circuitry.

Discussion in 'Predator Props' started by PredatoRay31, Aug 15, 2017.

  1. PredatoRay31

    PredatoRay31 Blooded

    Trophy Points:
    110
    I like to do everything on a cheap budget with things I can find in bulk or find easily. I tried for years to get this right and think I have a pretty stable version of a Shoulder cannon that tracks head movement in both Y and Z axis, and for cheap as I think I can get it with COTS items (Common Off The Shelf).
    Here's the video:


    It's not your typical caster cannon, but I feel the shoulder cannon is like the Jedi knight's light saber. It is built individually....and I liked the look of the 80/20 Aluminum bracketing.

    I used an Arduino Uno, 2ea - 5vdc servos, an MPU6050 Arduino module (6 axis), a project box from Amazon, RJ45 (Ethernet) connectors with panel mounts, a panel mounted audio jack, a few things I had around my shop, and a 2000 maH rechargeable battery bank (the ones used for charging your phones...I will upgrade to 4000+ maH for more hours of use). I'll put the code I used in my next comment.
     
    Vebo1, Shogun, Isubomo and 1 other person like this.
  2. PredatoRay31

    PredatoRay31 Blooded

    Trophy Points:
    110
    Here is the Arduino Code: FYI....you MUST install both the "I2CDEV" and "MPU6050" libraries into the Arduino IDE. Ensure you do the Zero Sketch from the MPU6050 examples first and input those zeroing numbers (look for gyro offset comment) into the Arduino code below. Each MPU6050 will be slightly different.

    It is set up to scan the servos when walking around. Pressing the fire laser button will lock the servos on the last known position, make an LED increase in intensity over a short duration, fire the laser pointer for 0.5s, then dim the LED down fast to off. I did this to simulate it charging up, firing, then powering down. It will only fire once per button push. You could code in a small recoil of the Y Axis servo if you wanted when fired. If you have any questions...please ask. the servos will automatically go to whatever position the MPU sensor is at once the firing function is complete. I can try to add any additional functions that could make it even more awesome. Just need some time to code it in and make sure it works.

    Code:
    /*
       Predator Shoulder Ca
       nnon v2
       by: Raymond Willis 8/1/17
       r.willis_pi@yahoo.com
    
       I edited serveral different pre-existing programs to
       create this one. Too many to list all sources. If you
       see your code, thank you.
     
       This program uses 2 servos, 1 MPU6050 3 AXIS Module, 1 LED,
       and 1 Laser Diode to have the servo mounted shoulder cannon
       track your head position like in the Predator movies and
       when a button is pressed the LED birghtens, fires the laser
       diode for 0.5s, and then dims the LED (simulate a build up
       of energy, firing, and then energy dissipation).
     
       The I2CDev and MPU6050 libraries are required for this program.
    
       The Servos follow the Y and Z axis of the MPU6050. The
       module should be placed at the top-center of your head
       or mask/helmet. When walking around, the Z axis will drift.
       So at certain degrees for an extended period I assume the user
       is walking around and go into scan mode, then when not walking
       around I reset the MPU to re-zero the Z Axis.
    
       I commented as much as I can to help anyone else use this.
    */
    
    #include <Servo.h>
    #include <string.h>
    #include <stdio.h>
    #include "I2Cdev.h"
    #include "MPU6050_6Axis_MotionApps20.h"
    
    Servo myservoY; // Roll
    Servo myservoX; // Pitch
    Servo myservoZ; // Yaw
    int countA = 0;
    int countB = 0;
    int posY;
    int posZ;
    int rstZ;
    int buttonState = LOW;
    int oneFlash = 1; // variable to flash the LED Laser once per each button press.
    const int buttonPin = 7; // Mom switch pin, fires laser diode
    const int ledPin = 3;  // LED
    const int laserPin = 4; // Laser Diode
    
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
    #endif
    MPU6050 mpu;
    
    #define OUTPUT_READABLE_YAWPITCHROLL    //Comment or uncomment to output data
    
    #define LED_PIN 13
    bool blinkState = false;
    
    // MPU control/status vars
    bool dmpReady = false;  // set true if DMP init was successful
    uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
    uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
    uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
    uint16_t fifoCount;     // count of all bytes currently in FIFO
    uint8_t fifoBuffer[64]; // FIFO storage buffer
    
    // orientation/motion vars
    Quaternion q;           // [w, x, y, z]         quaternion container
    VectorInt16 aa;         // [x, y, z]            accel sensor measurements
    VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
    VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
    VectorFloat gravity;    // [x, y, z]            gravity vector
    float euler[3];         // [psi, theta, phi]    Euler angle container
    float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector
    
    // INTERRUPT DETECTION ROUTINE
    volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
    void dmpDataReady() {
      mpuInterrupt = true;
    }
    
    void setup() {
      pinMode(ledPin, OUTPUT);
      pinMode(laserPin, OUTPUT);
      pinMode(buttonPin, INPUT);
    
      // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
      Wire.begin();
      TWBR = 24;
    // 400kHz I2C clock (200kHz if CPU is 8MHz)
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
      Fastwire::setup(400, true);
    #endif
    
      myservoY.attach(9); // Attach Y servo to pin 9
      //myservoX.attach(10);// Attach X servo to pin 10, not used
      myservoZ.attach(11); // Attach Z servo to pin 11
    
    
      Serial.begin(115200);
      while (!Serial); // wait for enumeration, others continue immediately
    
      // initialize device
      Serial.println(F("Initializing I2C devices..."));
      mpu.initialize();
    
      // verify connection
      Serial.println(F("Testing device connections..."));
      Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
    
      // load and configure the DMP
      Serial.println(F("Initializing DMP..."));
      devStatus = mpu.dmpInitialize();
    
      // supply your own gyro offsets here, scaled for min sensitivity
      mpu.setXGyroOffset(2); //was 49
      mpu.setYGyroOffset(-29); //was -26
      mpu.setZGyroOffset(36);  // was 13
      mpu.setZAccelOffset(923); // 1688 factory default for my test chip 1459
    
      // make sure it worked (returns 0 if so)
      if (devStatus == 0) {
        // turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);
    
        // enable Arduino interrupt detection
        Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
        attachInterrupt(0, dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();
    
        // set our DMP Ready flag so the main loop() function knows it's okay to use it
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        dmpReady = true;
    
        // get expected DMP packet size for later comparison
        packetSize = mpu.dmpGetFIFOPacketSize();
      } else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print(F("DMP Initialization failed (code "));
        Serial.print(devStatus);
        Serial.println(F(")"));
      }
    
      // configure LED for output
      pinMode(LED_PIN, OUTPUT);
    }
    
    // Main Program Loop
    void loop() {
      // if programming failed, don't try to do anything
      if (!dmpReady) return;
    
      // wait for MPU interrupt or extra packet(s) available
      while (!mpuInterrupt && fifoCount < packetSize) {
        // other program behavior stuff here if oyu want
    
      }
    
      // reset interrupt flag and get INT_STATUS byte
      mpuInterrupt = false;
      mpuIntStatus = mpu.getIntStatus();
    
      // get current FIFO count
      fifoCount = mpu.getFIFOCount();
    
      // check for overflow (this should never happen unless our code is too inefficient)
      if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        Serial.println(F("FIFO overflow!"));
    
        // otherwise, check for DMP data ready interrupt (this should happen frequently)
      } else if (mpuIntStatus & 0x02) {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
    
        // read a packet from FIFO
        mpu.getFIFOBytes(fifoBuffer, packetSize);
    
        // track FIFO count here in case there is > 1 packet available
        // (this lets us immediately read more without waiting for an interrupt)
        fifoCount -= packetSize;
    
    #ifdef OUTPUT_READABLE_YAWPITCHROLL
        // display Euler angles in degrees
        mpu.dmpGetQuaternion(&q, fifoBuffer);
        mpu.dmpGetGravity(&gravity, &q);
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
        Serial.print("ypr\t");
        Serial.print(ypr[0] * 180 / M_PI);
        myservoZ.write(int(ypr[0] * 180 / M_PI) + 90); // Rotation around Z
        rstZ = (ypr[0] * 180 / M_PI); // Z axis into a variable to test
        Serial.print("\t");
        Serial.print(ypr[1] * 180 / M_PI);
        myservoY.write(int(ypr[1] * 180 / M_PI) + 90); // Rotation around Y
        Serial.print("\t");
        Serial.println(ypr[2] * 180 / M_PI);
        myservoX.write(int(ypr[2] * 180 / M_PI) + 90); // Rotation around X
    #endif
    
        /* If the Z axis servo is max left or right for so many seconds,
           you are probably walking around and we need to re-orient the
           Z Axis gyro's earth reference point to maintain correct orientation
           for tracking head movement.
        */
        if (rstZ > 100 || rstZ < (-100)) { // test if Z Axis is at max L or R
          countA++; // count each time too far L or R
          if (countA >= 3) { //if max L or R, 3 consecutive times..reset MPU
            resetMode();
          }
        }
    
        if (rstZ < 99 && rstZ > (-99)) { // when outside L or R max
          countA = 0; // reset count to 0, you are likely stationary
        }
    
        buttonState = digitalRead(buttonPin); //read the firing button state
        if (buttonState == HIGH) { // if the button reads High, the button is pressed
          posY = (ypr[1] * 180 / M_PI); //read Y position
          posZ = (ypr[0] * 180 / M_PI); //read Z position
          myservoY.write(posY + 90); //stop moving and stay at last know positions
          myservoZ.write(posZ + 90);
          laserFire(); //perform the laser firing function
        }
    
        else if (buttonState == LOW) {
          // If Im not holding the button, turn everything off:
          analogWrite(ledPin, 0);
          digitalWrite(laserPin, LOW);
          oneFlash = 1;
        }
      }
      Serial.print("Reset Count: ");
      Serial.println(countA);
      Serial.print("Laser Fire Button: ");
      Serial.println(buttonState);
    }
    
    void resetMode() { // reset function
      Serial.println("You must be walking around so let's reset Z Axis reference point!");
      countA = 0;
      mpu.reset();        // reset the Gyros to reset Z axis reference point
      setup();            // re-initialize everything for new gyro data
    }
    
    void scanMode() { // scan mode function
      Serial.println("We are in Auto Scan Mode.");
      posY = 90;                                      // set Y servo to 90 degrees
      for (posZ = 45; posZ <= 115; posZ += 1)         // start scanning Z servo L to R
      {
        myservoZ.write(posZ);
        delay(60);
      }
      for (posZ = 115; posZ >= 45; posZ -= 1)
      {
        myservoZ.write(posZ);
        delay(60);
      }
    }
    
    void laserFire() { //Led & laser diode firing function
      if (oneFlash >= 1) {
    
        for (int fadeValue = 10 ; fadeValue <= 255; fadeValue += 5) {
          delay(10);
          analogWrite(ledPin, fadeValue); // LED glows bright, charging up
        }
        analogWrite(ledPin, 255); // after ramp up, keep on
         //recreate mini recoil
        digitalWrite(laserPin, HIGH); //energize laser diode
        delay (500); // Laser Pointer ON time in millisecs after LED ramp up is done.
        digitalWrite(laserPin, LOW); //laser diode off
        for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 10) {
          delay(5);
          analogWrite(ledPin, fadeValue); // LED dims down.
        }
        analogWrite(ledPin, 0); //led off
        oneFlash = 0; //set button count to ensure it only fires once per button press
      }
    }
    
     
    Last edited: Aug 15, 2017
    Shogun, agh12 and Wreav like this.
  3. agh12

    agh12 Blooded

    Trophy Points:
    155
    What a great work, my friend, that is incredible.I am learning to program with arduino to also mount the computer bomb
     
  4. PredatoRay31

    PredatoRay31 Blooded

    Trophy Points:
    110
    I cannot express enough how incorporating Arduino Uno, Nano, or any other pre-built microcontroller is cheap and easy. Arduino IDE is free and provides a huge list of examples to get you going in no time.... and an quick Google search can yield even more examples and pre-built libraries to code from. You can get Arduino Nanos or Minis for like 5ea for $15 on Amazon (I even bought the Arduino rip offs and they are great for prop building). Seriously...an Arduino Nano, a few switches, flat LEDs, and you can code some cool wrist gauntlets in no time.
    I've been toying with the idea of using Arduino to power a linear actuator to have real in/out gauntlet blades, but even the small linear actuators (or solenoids) are over $100. I would think a movement of 6" or more would be enough for the effect. I'll keep searching.
    I have made several things with Arduino and it inspires me to make more. I created a wizard staff that lights up depending on how to tap it on the ground and has a secret reed switch to activate a LED sparkle mode. I have another idea (which I have already made schematics for) in which a real temperature sensor will make the 3 LED lights on Vader's chest box vary in pattern and pattern speed based on actual outside temperature.
     
    Shogun likes this.
  5. PredatoRay31

    PredatoRay31 Blooded

    Trophy Points:
    110
    An Arduino Nano, some switches, and flat LEDS on a breadboard. Just randomize the LED sequencing using random function and a switch case for ON/OFF (HIGH/LOW) state.

    Random Function:
    Arduino - Random
     
    Last edited: Aug 15, 2017
    agh12 likes this.
  6. agh12

    agh12 Blooded

    Trophy Points:
    155
    Estaba pensando en usar una matriz led 8x8 para cada pantalla y activarla individualmente
     
  7. PredatoRay31

    PredatoRay31 Blooded

    Trophy Points:
    110
    Sorry, I don't understand Spanish very well... I wish I did.

    I think I got you are using an LED 8x8 matrix for the display. Me personally I would just use the flat LEDs in the pattern used for gauntlets. Many people in the forums have them in the right pattern. From my understanding, in the movie they did not just use the old LED 7 segment displays...they made their own display pattern in LEDs not manufactured normally like this:
    Amazon.com: 10 pcs Plastic Metal Common Anode 1 Bit 7 Segment Red LED Display Digital Tube: Home Audio & Theater

    Maybe a 16 segmented display would be close:
    0.39" (9.9mm) Single Digit Alpha-Numeric Blue LED Display, Black Face, Common Anode (Pack of 3) - - Amazon.com
     
  8. agh12

    agh12 Blooded

    Trophy Points:
    155
    I was thinking of using an 8x8 led matrix for each screen and activating it individually
     
  9. agh12

    agh12 Blooded

    Trophy Points:
    155
    An example of the number 9 using the language yautja

    20170816_023730.jpg
     
    Aurellius and Jmen like this.
  10. Mille2ej

    Mille2ej Blooded

    Trophy Points:
    120
    Wow, what a great strategy. The movement seems to be very smooth. Definitely going to look into this as a future upgrade! Great Work!!:D
     
    Shogun likes this.
  11. Isubomo

    Isubomo Hunter

    Trophy Points:
    335
    wow....
     
    Jmen likes this.
  12. Jmen

    Jmen Hunter

    Trophy Points:
    235
    Really, wow...
     
  13. Shogun

    Shogun Hunter

    Trophy Points:
    245
    This is truly an awesome WORK..... :love:
     
  14. Pestvic

    Pestvic Blooded

    Trophy Points:
    130
    This is amazing. Whats the sensor called that feels the movement?
     
  15. Shogun

    Shogun Hunter

    Trophy Points:
    245
  16. Pestvic

    Pestvic Blooded

    Trophy Points:
    130
    Shogun likes this.
  17. PredatoRay31

    PredatoRay31 Blooded

    Trophy Points:
    110
    As long as it uses the MPU6050, any add on module should work.
    But, there is still the issue of mapping rotation around the z axis to properly rotate the servo when turning your head. Reason is it defines a center point when first powered up. You have to redefine a center point after walking around. You can't track while walking around. What I did in the code was knowing I can only rotate my head, in degrees, so far with a mask on. When I go over those points, I assume I must be walking around because when you do the z servo will begin to turn thinking you are rotating on the z centerline but you are actually walking away from it, so I tell the servos to default to make the cannon go straight ahead and check that reading every loop. When it gets back under the limits, I must be stationary so reset the center point and start tracking head movement again. When stationary, this works great.
    I may be updating the code. The nice thing about the MPU 6050 is it has 2 accelerometers also incorporated. What I may do is read those to see of I'm walking around to default the servos....not using the limits of my head rotation.
     
    Shogun likes this.
  18. bpatneaude

    bpatneaude Unblooded

    Trophy Points:
    3
    holy crap.....great work that is amazing you guys on here are incredible with the practical work effects you create...bravo!
     
  19. Aurellius

    Aurellius Unblooded

    Trophy Points:
    3
    Wow where can I find a reference like this for the full language
     
  20. Aurellius

    Aurellius Unblooded

    Trophy Points:
    3
    Wow. I hope one day to achieve something like this but I am new to electronics and programming but am eager to learn. Hopefully your guides will help me achieve my goals or a working wrist computer and plasma caster
     
  21. ksj

    ksj Young Blood

    Trophy Points:
    60
    I did something similar of Honus original Build:
    wii nunchuck 4 servo control

    I may have to switch to undercode's implementation:
    Arduino + Wii Nunchuck [Servo Motores] - Underc0de Blog

    I will try adding Honus' transister board and see if that helps, but his setup is one of the best ones I have seen.

    The undercode setup saves on motor drive times and only runs the motors when you press the c or z buttons.

    I was thinking with either code base you could run dual canons, however, you would need about 6 servos to do that properly. Using the third to lift the main arm to 45 degrees and then use the pan/tilt unit servos to control up/down and left/right on the cannon.
     
  22. Venandipredator

    Venandipredator Unblooded

    Trophy Points:
    5
    This is absolutely awesome!
     
  23. ksj

    ksj Young Blood

    Trophy Points:
    60
    I got the setup working and have posted the code in one of my other threads here.

    Geez posting from a mobile sucks.
     
    Last edited: Dec 26, 2017
    Shogun likes this.
  24. Grimaldus

    Grimaldus Unblooded

    Trophy Points:
    3
    Do you do commissions ? I sent you a message but no reply
     
  25. ksj

    ksj Young Blood

    Trophy Points:
    60
    I am still working out the bugs on mine. I have several write ups over at aliens legacy and a couple here. Anywho. What holds you up from doing it yourself?
     

Share This Page