Head/canon Tracking

Update.
The part of code below is a piece of the entire code above when you initialize the delay time for the loop to run. What I found is if I delay the time from about 25 to 35 ms, the servo jitter was so small it's barley noticable. The only side effect is it slows the response a little (in microseconds), but not so much it's really noticeable until you go beyond 35 ms. I found after 35 ms the servos start to react like stepper motors as the pause between each loop becomes obvious. I hope this helps. I'm still looking to hold the last position when firing the simulated laser and then I'll post my final code.

int dtime=10;


I have mine set at 25 ms and I'm happy with it now.
 
seahunterr  where can I get the one you are talking about for $50.00. that really peaks my interest. I don't want to have to use another arduino.
 
I'm doing something similar. I'm considering swapping out the arduino for a BeagleBone and using open cv and a webcam mounted on the gun to track a 3 dot laser reticule. Any one tried this yet?
 
I have a BeagleBone Black but I haven't really played around with it much yet- it's an awesome board based on the specs. I think the only problem with using open cv and a webcam is tracking at a distance or in a non perfect environment. There is some code someone posted here-
https://bradmontgomery.net/blog/2008/01/24/tracking-a-laser-pointer-with-python-and-opencv/

Remember to be mindful of the BeagleBone input voltage- that 1.8V limit on the ADC is a bummer.

Honestly after building multiple cannon setups I'm really not convinced head tracking is the way to go. It's just too much trouble for what it's worth. If you set up a cannon with a nice programmed motion sequence it will appear just the same to an outside observer and it's simpler and more reliable with smoother motion. It appears more like what was in the film since they used R/C to control it- there's no sync problems, drift, latency or jitter.  I think if you really, really want head tracking done right you need to go with a multi IMU setup and in my mind the cost and complexity just aren't worth it.
 
So after a long time being busy with life (finished my BS-EET degree, 8 classes from finishing my BS-CS degree, and first born baby) I have finally come back to tackle this. With the new knowledge and research I found something that works very, very well for accurate head tracking for under $100 (or less).
I am using the Arduino Uno, Arduino Nano, and GY521 gyro/accelerometer circuit (find on Amazon pretty cheap).
I am very pleased with how well it tracks. Basically some MIT students created some libraries and an ino file to attach a servo to all 3 axis of the GY521 sensors. X, Y, and Z or Roll, Pitch, and Yaw. Using this info, you just use Roll or Pitch (for your head's Look up/down movement, then Yaw for your head turning left or right. The GY521 (which is not very big, maybe 1"x1") just needs to be embedded in some kind of case on your head.

So with out further adu, download the new library ZIP file here->       http://i2cdevlib.com/usage

Once downloaded, unzip then Install only the file called MPU6050 and i2cdev folders into Arduino's IDE library folder. On my computer it is C:\Program Files (86)\Arduino\Libraries.

Now copy the code on this page (new ino)-> http://pastebin.com/VQ4jrePc

Then open a  new Arduino sketch and paste the code. Make sure to save as....whatever you want to call it.

The only adjustments I made were to the servo offsets. Just play with them to see how the servos react.

Some things I noticed:
Everytime the Arduino is reset or master power cycled. The servos will zero to current positioning of the GY521. Laying it flat is how I have it whenever I reset the Uno.  If you have the GY521 sideways, the zero position of the servos will be the same. I'll demo in the video when I make it.
If you use the serial monitor (thru Arduino IDE) with this set up, it may jitter at times... it's not just controlling the servos at 115200 baud rate, it's now communicating to you what its doing..so a lot is going on.

I'm using the Nano to simulate the laser firing (as in my previous build). An LED will fade up to bright in about 30 seconds, a laser pointer then lights up for a few seconds, then the LED quickly fades out. I wanted to simulate it charging up to fire (cool effect). If I incorporate this into the Uno, then the servos will be interrupted so using a cheap Nano makes sense for this simple task.

I plan on making a video soon...so stay tuned. If anyone needs help, just ask. Enjoy.
 
Well.....Its not the awesomeness I thought it was. It seems you can't walk around and use the gyros as they set a reference point when the gy-521 is first powered up. But I'm working on a fix. Basically I'm going to make it reset after ever change in position then hold, reset, and sample. I'm not sure how this will affect the overall life of the gy-521, but for $10 or less, not too concerned.
So after I get it working correctly I'll post the code then  video.
 
So after tons of iterations, I got a decent working code. Basically when you use the GY-521 (MPU6050) to track head movement, you never really turn your head far enough to reach the max limits (as your constrained by mask and dreads). So what I did was input a reset function and recall the setup funciton when a variable counts the Z Gyro at it's max left or right limits for 3 counts of a variable (about 3 milliseconds) which really only happens when you are walking around. This only resets the GY521, so your servos don't go crazy losing the I2C connection (the issue I had doing a UNO reset). You can easily change it or make it so it just resets as soon as the limit is reached or for a different count. Look for "countA >= 3" in the code below to make changes. Don't forget you need to get the 2 new libraries from my early post (I2C.dev and MPU6050 header files). I will make a video when I get the entire thing together. I had to find a new replica cannon since I had to remove the old one, destroying it in the process.
 
Code:
//Servo 
#include 
#include 

Servo myservoY; // Roll
Servo myservoX; // Pitch
Servo myservoZ; // Yaw
int countA = 0;
int countB = 0;
int posX;
int posZ;
int rstZ;
const int scanBtn = 14;  //initialize A0 (UNO).

// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"

#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

MPU6050 mpu;
//MPU6050 mpu(0x69); //  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);  
            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


        // blink LED to indicate activity
        blinkState = !blinkState;
        digitalWrite(LED_PIN, blinkState);
        
//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)){ // if servo is close to 180 or 0 degrees then do something. Change 100/-100 as desired.
    countA += 1; // count a variable
         if (countA >=3){ // if we reach 0.03 seconds at max left or right, run reset function
           resetMode();
     }
  }
          
  if (rstZ < 99 && rstZ > (-99)){ // if you move out of max left or right
    countA = 0; // reset count to 0, you are likely stationary
  }
                   
  if (scanBtn == HIGH){ // when A0 is high, run run scanMode function
    scanMode();
  }
}
 Serial.print("Reset Count: ");
     Serial.println(countA);
}

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(){  // auto scan mode function
    Serial.println("We are in Auto Scan Mode.");    
    posX = 90;                                      // X axis servo will stay at 90 degrees position for now.
    for(posZ = 55; posZ =55; posZ-=1)     
  {                                
    myservoZ.write(posZ);               
    delay(60); 
  }    
    countB += 1;                              // add 1 to countB variable.
  Serial.print("Scan Count (Max=5): "); 
  Serial.println(countB);
    if (countB >= 5){                        // when we scan left to right 5 times, do something different.
      posZ = 90;                             // Z axis servo will stay at 90 degrees for this loop.
      myservoZ.write(posZ);
      posX = 90;      
      myservoX.write(posX);
      posX = 135;
      myservoX.write(posX);                  // quickly snap to 135 degrees and so on
      delay(1000);
      posX = 50;
      myservoX.write(posX);
      delay(1000);
      posX = 90;
      myservoX.write(posX);
      delay(200);
      for(posZ = 90; posZ
 
I would really like to see how this progressed since the last post was over a year ago. I recently been reading up about arduinos and accelerometers and the hole concept of using them to control a cannon has got my intrest
 
Back
Top