DSLR Camera stabilization

Good evening and sorry ahead of time for my lengthy post! I have been "trolling" and reading as much as I can so far!

I am relatively new to Arduino and C programming. I have worked with SQL and VBA before, though have never had any official training/education on anything programming. I have always been a tinkerer and also into woodworking and such. One of my hobbies/side income is photography, more specifically automotive photography. The basis of this contraption is to use it to take "rolling shots" of friends/clients cars while driving. Usually, people have another person drive them and then hang out the window or whatever to then take a shot of the car next to you. That requires a third person to be free and available. With my camera rig, I can take pictures via a remote trigger while I am driving myself. I made a first version that does not have any motors/servos and relies solely on physics and the weight of the camera and rig with RC shocks for dampening. It worked pretty darn well, though I wanted to see if I could get better stabilization via a servo and Arduino.

I know basically every project I have come across for camera stabilization relates to gyro and rotational stabilization for shooting video, but I am looking for vertical stabilization of the camera in order to get a long enough shutter speed to get the motion blur of the environment while the car is crisp and sharp. I will post pictures of the first rig, example photos from that rig and then the current version 2 with a panning motor and high torque servo for the vertical stabilization. This rig is currently mounting right to my trailer hitch.

I wanted to give all that background in order to try and give as much info as I can ahead of time. I am sure there will still be other questions you guys will have though. Currently, I am using the Uno board with the Adafruit Motor Shield and a GY-521 6DOF (MPU-6050). I have wired up a remote for the panning of the top "plate" that holds the camera. That is working perfectly! I have tried using a mix-mash of a few things I have read and code I have stumbled across. A good portion of my sketch consists of code from the MPU6050_DMP example in the MPU6050 library, as well as IC2dev library.

My current issues are that the camera is to jittery and is not able to get clear shots. I have tried using the Accel Z values but have a ripple effect (not sure if that is a good way to describe it) going on due to the readings. I have tried using the gyro values thinking that if the back of the car hits a bump there would be a slight rotate on the horizontal plane. That however does not seem to be sensitive enough. So I am seemingly too sensitive, or not sensitive enough in my values. I was thinking about trying to add some sort of Easing code to try and make things a little less jittery, but am not sure if that will work.

I will post my code too, but I have just commented out a lot of things that are not neccesary or that I have not fully implemented yet (easing), so please be nice for its un-clean presentation. I guess I am trying to see in what direction I should be heading with the code. I feel like it should be doable and my testing today with it on the car and taking some pictures it isnt horribly far off what I was hoping for, just not there yet.

Thanks ahead of time for any help, pointers, tidbits, and just for taking the time to read this!

Version 1 Rig (made a few more changes after this pic, but good enough for here)

Example photos taken with Version 1

Version 2 Rig (at this point)

The Uno, GY-521 and all the needed voltage regulators to get the appropriate volts from the 14.4V of the car while running. I am dropping to 12V for the motor and 7.2V for the Futaba S9352HV servo.

CODE Part I
(too big for one post and I know there are many commented out lines taking up the character space, sorry)

#include "I2Cdev.h"                         // I2Connection library (communication to serial port)
#include "MPU6050_6Axis_MotionApps20.h"     // IMU library
#include "Servo.h"                          // servo control library
#include "Wire.h"                           // allows communication to i2c devices connected to arduino
#include "AFMotor.h"
//#include "QuarticEase.h"
//#include <Easing.h>

MPU6050 mpu; //defines the chip as a MPU so it can be called in the future

#define LED_PIN 13
#define SERVO1_PWM 10
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

// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '

, 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };
int buffersize=1000;

//QuarticEase ease;
AF_DCMotor motor(1, MOTOR12_64KHZ); // create motor #1, 64KHz pwm
int rotateL;
int rotateR;
int moveMotor;
Servo myServo;
float servoVal;
float prevServoVal;
float finalYaw;
float finalPitch;
float finalRoll;
int x;
int pos = 0;    // variable to store the servo position
int16_t ax, ay, az;  // x y z orientation values from accelerometer
int16_t gx, gy, gz;

// ================================================================
// ===              INTERRUPT DETECTION ROUTINE                ===
// ================================================================

volatile bool mpuInterrupt = false;    // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}

// ================================================================
// ===                      INITIAL SETUP                      ===
// ================================================================

void setup() {
    // 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

// initialize serial communication
    // (115200 chosen because it is required for Teapot Demo output, but it's
    // really up to you depending on your project)
    Serial.begin(19200);
    while (!Serial); // wait for Leonardo enumeration, others continue immediately

// NOTE: 8MHz or slower host processors, like the Teensy @ 3.3v or Ardunio
    // Pro Mini running at 3.3v, cannot handle this baud rate reliably due to
    // the baud timing being too misaligned with processor ticks. You must use
    // 38400 or slower in these cases, or use some kind of external separate
    // crystal solution for the UART timer.

// 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"));

// wait for ready
    /*
    Serial.println(F("\nSend any character to begin DMP programming and demo: "));
    while (Serial.available() && Serial.read()); // empty buffer
    while (!Serial.available());                // wait for data
    while (Serial.available() && Serial.read()); // empty buffer again
*/
    // 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(83);// (was 220)
    mpu.setYGyroOffset(22);// (was 76)
    mpu.setZGyroOffset(49);// (was -85)
    mpu.setZAccelOffset(4088); // 1688 factory default for my test chip

// 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(")"));
    }
    meansensors();
   
    // configure LED for output
    pinMode(LED_PIN, OUTPUT);
    motor.setSpeed(255);    // set the speed to 200/255
    myServo.attach(SERVO1_PWM);
    for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees
    {                                  // in steps of 1 degree
      myServo.write(pos);              // tell servo to go to position in variable 'pos'
      delay(15);                      // waits 15ms for the servo to reach the position
    }
    for(pos = 180; pos>=1; pos-=1)    // goes from 180 degrees to 0 degrees
    {                               
      myServo.write(pos);              // tell servo to go to position in variable 'pos'
      delay(15);                      // waits 15ms for the servo to reach the position
    }
    myServo.write(90);
    //ease.setDuration(2);
    //ease.setTotalChangeInPosition(255);
}

CODE Post II

// ================================================================
// ===                    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) {

    }

    // 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;



            rotateL = analogRead(0);
            rotateR = analogRead(1)*-1;
            moveMotor = rotateL + rotateR;
  
            switch (moveMotor) {
              case -1023:
                motor.run(FORWARD);
                break;
              case 1023:
                motor.run(BACKWARD);
                break;
              default:
                motor.run(RELEASE);
            }
            
            mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); 
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            finalYaw = ypr[0] * 180/M_PI;
            finalPitch = ypr[1] * 180/M_PI;
            finalRoll = ypr[2] * 180/M_PI;
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetAccel(&aa, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
            mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
            
            servoVal = map(aaWorld.z, 0, 8500, 0, 179);     // scale it to use it with the servo (value between 0 and 180) 
            constrain(servoVal, 0, 179);
            if (servoVal != prevServoVal)
              {
                if(servoVal >= 0 && servoVal <= 179 )
                {
                  myServo.write(servoVal);              // sets the servo position according to the scaled value
                }
                else if(servoVal < 0)
                {
                  myServo.write(0);              // sets the servo position according to the scaled value
                }
                else if(servoVal > 179)
                {
                  myServo.write(179);              // sets the servo position according to the scaled value
                }
                prevServoVal = servoVal;
              }
            Serial.print("ypr\t");
            Serial.print(finalYaw);
            Serial.print("\t");
            Serial.print(finalPitch);
            Serial.print("\t");
            Serial.print(finalRoll);
            Serial.print("\t aworld\t");
            Serial.print(aaWorld.x);
            Serial.print("\t");
            Serial.print(aaWorld.y);
            Serial.print("\t");
            Serial.print(aaWorld.z);
            Serial.print("\t");
            Serial.print(az);
            Serial.print("\t");
            Serial.print(aaWorld.z);
            Serial.print("\t");
            Serial.println(servoVal);
            


        // blink LED to indicate activity
        blinkState = !blinkState;
        digitalWrite(LED_PIN, blinkState);
    }
}

void meansensors(){
  long i=0;
  int16_t ax, ay, az,gx, gy, gz;
  
  while (i<(buffersize+401)){
    // read raw accel/gyro measurements from device
    mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
    
    if (i>400 && i<=(buffersize+400)){ //First 400 measures are discarded
      ypr[0] * 180/M_PI;
      ypr[1] * 180/M_PI;
      ypr[2] * 180/M_PI;
    }
    if (i==(buffersize+400)){
      ypr[0] * 180/M_PI;
      ypr[1] * 180/M_PI;
      ypr[2] * 180/M_PI;
    }
    i++;
    delay(2); //Needed so we don't get repeated measures
  }
  
}
/*
void moveServo(int val, int prevVal){
  int dur = 100; //duration is 100 loops
  for (int pos=0; pos<dur; pos++){
    //move servo from 5 and 160 degrees forward
    myServo.write(easeInOutQuint(pos, prevVal, val, dur));
    delay(15); //wait for the servo to move
  }
  
  double easedPosition,t=0;
   
  for(int i=0;i<=100;i++) {   
    easedPosition=ease.easeIn(t);
    analogWrite(9,(unsigned char)easedPosition);
    t+=0.02;
    delay(5);
  }
}
float easeInOutQuint (float t, float b, float c, float d) {
	if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
	return c/2*((t-=2)*t*t*t*t + 2) + b;
}

float easeInOutExpo (float t, float b, float c, float d) {
	if (t==0) return b;
	if (t==d) return b+c;
	if ((t/=d/2) < 1) return c/2 * pow(2, 10 * (t - 1)) + b;
	return c/2 * (-pow(2, -10 * --t) + 2) + b;
}
*/

picknik123:
I will post my code too,

Can you post your code as an attachment so it is all in one piece.

Also, since it is a long piece of code can you provide a description of what the different parts are supposed to do.

It is also pretty much essential for you to describe how the actual behaviour of the code differs from the intended or desired behaviour.

How much of the stabilization is provided by the springs?

And how much extra do you expect to get with the computer control?
Are you just using the computer to give better damping?

...R

Robin2:

picknik123:
I will post my code too,

Can you post your code as an attachment so it is all in one piece.

Also, since it is a long piece of code can you provide a description of what the different parts are supposed to do.

It is also pretty much essential for you to describe how the actual behaviour of the code differs from the intended or desired behaviour.

Can do! I can have that up a little later today after I go through and comment and such.

Robin2:
How much of the stabilization is provided by the springs?

And how much extra do you expect to get with the computer control?
Are you just using the computer to give better damping?

...R

Version 1 only has springs. Version 2 only has the high torque servo for the damping. It should be rated high enough to handle the weight of the camera via simple lever/fulcrum math. The idea was to have one or the other and not both. But if that cannot be the case, then I will need to do some more thinking and redesigning...

Thank you for taking the time to read through it all Robin2! Much appreciated, and I am sorry that my code was not up to standard when posting. I will try my best to convey everything in comments now!

Ok, here is a link to the code! I tried my best to describe everything I could. All comments were kept from the original sketch I started with. Anything that I changed or added to the sketch, I put "(picknik123)" at the end of the comment.

https://drive.google.com/folderview?id=0BxHkYlzv7kH-NFprQUZsZnRnaXc&usp=sharing

Thanks again to anyone who takes the time to look it over!

I've been out all day and I'm not going to look at the code tonight. I'll try to do so tomorrow - but don'e expect much from me.

Your comments may be very good but, in case you read this before I look at your stuff, what I would really like is a few sentences (or paragraphs) that say something like "The general approach is to detect X with Y and when Z happens to do A, B or C. The code is organized into X functions. This function does this based on that input etc etc"

...R

Take a look at PID in the playground/examples area this should help with keeping the cam steady.

Mark

Robin2:
I've been out all day and I'm not going to look at the code tonight. I'll try to do so tomorrow - but don'e expect much from me.

Your comments may be very good but, in case you read this before I look at your stuff, what I would really like is a few sentences (or paragraphs) that say something like "The general approach is to detect X with Y and when Z happens to do A, B or C. The code is organized into X functions. This function does this based on that input etc etc"

...R

Well I guess, I should say that you not need to waste any more of your time at this point. I really do not know what values I should be using in order to best get the results I am looking for. I am beginning to think that I am using far too much code that I dont need. I mean, I know what I want as the end result in the physical world, but like I said I am new to Arduino and am not 100% sure of what values I need to turn into what in order to achieve that. So until I figure out how to answer all of that and write you a informative paragraph, I will keep reading random tutorials and maybe another book or two or Arduino coding. :~ :cold_sweat: Sorry, but thank you Robin2!

holmes4:
Take a look at PID in the playground/examples area this should help with keeping the cam steady.

Mark

Thanks Mark! I will check out the PID stuff later tonight!

picknik123:
Well I guess, I should say that you not need to waste any more of your time at this point.

I have had a quick look at your code but, as I suspected, there is a whole lot of stuff that doesn't make any sense without a general explanation of what is supposed to be happening.

When I start to do anything a little complicated I first write myself a short essay describing how I think the thing should work. This gives me a basis for thinking about the sort of sensors, the sort of code that will use them and how they can interact with each other. It also provides a basis for calculations to determine whether what I want is physically possible - can I read a sensor often enough, can I transmit data fast enough, or whatever.

I have a vague impression in my mind of how a steady cam works (with springs and dampers) but before I could consider making a computer controlled system without springs I would need to figure out exactly what the camera has to do relative to the car.

I suspect the logic of the system will be very different for still photography compared with movies.

For still photography you only need a short interval of steadyness - maybe 1/25 second - so should you choose to start that when the camera is at the top of the range of movement, or at the bottom, or in the middle? Or maybe you want to hold the system rigid at the bottom of the motion until the car starts moving down so that you have all the motion to play with during the exposure period.

...R

Robin2:
When I start to do anything a little complicated I first write myself a short essay describing how I think the thing should work. This gives me a basis for thinking about the sort of sensors, the sort of code that will use them and how they can interact with each other. It also provides a basis for calculations to determine whether what I want is physically possible - can I read a sensor often enough, can I transmit data fast enough, or whatever.

This is what I am having difficulty with coming up with for you... Not having any formal education on coding or hardware, I do not know how often to read sensors, how fast transmitting data, etc.

I have the understanding of how gyro sensors and accelerometers and know that I could get a reading from either that could work for what I imagine I would need for an input. The problem is, the gyro would give me an angle/degree reading when the rear axle hits a bump, but it would be so minute I dont know if I could work with that number to be sensitive enough. In addition, what if I go up or down a hill? Then that value would change as well making it hard to get a range of values to map to the servo motion.

On the opposite side, the accelerometer readings could be used directly to show the amount of movement when hitting bumps easily, but then there is a "ripple" effect that would cause the servo to bounce back and forth more than needed. That then creating more movement of the camera than of the car hitting the bump and a blurry car image.

That is all theoretical from my understandings so far, though I might be incorrect in some of that. The code I originally posted, uses the gyro/accel sensor to create a somewhat stable reading of direction and orientation, but as I said previously I am second guessing that function with my needs. Would work great if I was looking for a gimbal-style camera stabilizer.

Robin2:
I have a vague impression in my mind of how a steady cam works (with springs and dampers) but before I could consider making a computer controlled system without springs I would need to figure out exactly what the camera has to do relative to the car.

I suspect the logic of the system will be very different for still photography compared with movies.

For still photography you only need a short interval of steadyness - maybe 1/25 second - so should you choose to start that when the camera is at the top of the range of movement, or at the bottom, or in the middle? Or maybe you want to hold the system rigid at the bottom of the motion until the car starts moving down so that you have all the motion to play with during the exposure period.

...R

The way that my rig is set up, the top plate (where the camera is fastened to the rig) should ideally stay in relative position. Both versions use two beams, like that of a camera jib, to keep the camera plate as level as possible while still moving it up or down. The non-motorized first version used momentum/weight to create enough resistance of movement so that the car could move (hit a bump) and the force was not great enough to move the camera from its current plane (again, might be off on proper terminology). If I hit a large enough bump or a number of bumps in a row, then yes, the camera did move/jostle some.

Theoretically, to put fake numbers to it, if the car moves up 0.5" from a bump, I would want to camera mounting plate to move down 0.5" inches from the car temporarily and then return back to the standard "resting " position. I would plan on having the camera plate residing in the middle of its travel zone giving it ability to move up or down according to the bump that was hit. some bumps are like potholes and others like speed-bump. So either way the car moves quickly, the camera plate can respond in the opposite direction to offset the car's movement. Overall, one could say that the camera plate should remain parallel or at the same relative position from the ground on average.

With the version 1 rig, I was achieving 30-40% success rate at 1/30 second and 1/45 second, driving around 35-45mph and 65mph, respectively. The faster the cars are driving, the faster or more bumps are theoretically hit in the time-frame of the shutter being open. Luckily, the faster the cars are driving the more motion blur can be achieved, so it not necessary to get as long as of a shutter speed. As far as success rate, I deemed any shot taken where the car was in focus and sharp and the background was successfully blurred due to the motion while shutter was open.

I would like to achieve at least one of two basic goals with the servo controlled version 2. Either get slower shutter speeds (maybe 1/8 - 1/20) or better success rate of sharp pictures. Maybe that is asking too much, but at the same time, I love learning and I love tinkering and building.

This might not be an essay, but might be more of things you are wondering or asking. Or maybe I am just trying to bite off more than I can chew? Robin2, I truly do appreciate all the time you have spent reading and responding to my project! I know you have no reason to take the time out of your day, except to try and be helpful. I am sorry I lack so much knowledge for trying to attempt this project, but I feel I have come a long way in just a few weeks!

picknik123:
Not having any formal education on coding or hardware, I do not know how often to read sensors, how fast transmitting data, etc.

In a way you are missing the point. The concept of my essay is that you (and I) write it without needing any technical knowledge - at least to start with. It begins as a lay-person's notion of what is required.

Then, if you think that you need to do Z you can do some research on Z. Maybe you conclude that X is the right approach and that it is feasible or not. And do the same for X, C, V, B etc.

Gradually you will develop a plan that can probably be implemented - but there may not be any code at that stage. Or maybe there will have been a few experimental programs while learning how V or B might work.

Your description of stabilizing the camera platform is pretty much as I expected. Where I think we may have a difference is in the question of when and for how long you need stability. The concept I have in mind is that you press the button to take a picture and then the platform waits (a short time) for the ideal moment in the dynamics of the car to get the max stability.

Regardless of whether that idea appeals to you it would be a good idea to collect some data about the frequency and amplitude of the car's motion. It might even be an idea to be able to run the car over a section of road to collect data before deciding if that section is suitable for photography.

I presume you need to have the camera at bumper height? The towbar is probably the point on the car with the most extreme motion. The centre of the wheelbase (on the roof, obviously) should have least motion.

OR take the photos with a high shutter speed and add the blur afterwards.
OR What about having 2 cameras taking pictures at the same time - one with a high shutter speed and one with a low shutter speed. then overlay the pictures.

...R

Robin2:
In a way you are missing the point. The concept of my essay is that you (and I) write it without needing any technical knowledge - at least to start with. It begins as a lay-person's notion of what is required.

Then, if you think that you need to do Z you can do some research on Z. Maybe you conclude that X is the right approach and that it is feasible or not. And do the same for X, C, V, B etc.

Gradually you will develop a plan that can probably be implemented - but there may not be any code at that stage. Or maybe there will have been a few experimental programs while learning how V or B might work.

Your description of stabilizing the camera platform is pretty much as I expected. Where I think we may have a difference is in the question of when and for how long you need stability. The concept I have in mind is that you press the button to take a picture and then the platform waits (a short time) for the ideal moment in the dynamics of the car to get the max stability.

Regardless of whether that idea appeals to you it would be a good idea to collect some data about the frequency and amplitude of the car's motion. It might even be an idea to be able to run the car over a section of road to collect data before deciding if that section is suitable for photography.

I presume you need to have the camera at bumper height? The towbar is probably the point on the car with the most extreme motion. The centre of the wheelbase (on the roof, obviously) should have least motion.

OR take the photos with a high shutter speed and add the blur afterwards.
OR What about having 2 cameras taking pictures at the same time - one with a high shutter speed and one with a low shutter speed. then overlay the pictures.

...R

:frowning: I will keep working on the thoughts for the essay then!

I never planned on having the Arduino control the camera picture taking itself. Then again without said essay, you would not know that! I have a wireless Nikon remote that I was just going to keep using. Maybe after I get some sort of stabilization occurring (even the slightest) as a first step, I can have that be a next step to battle with.

As far as location of camera, the lower the better generally speaking. Adding blur afterwards generally does not look real and that is after you spend hours editing one picture. With the two cameras, I would still need to get a nice shot with the slow shutter speed, and if that is that case, I wouldn't need the faster shutter speed shot. :wink: From experience with the version 1 rig, even though the motion blur is creating blur, you still see the bumps and shakes in the rest of the image. Instead of a smooth line of blur it looks like jagged line.

You have given plenty of food for thought. I am getting ahead of myself with this project. I need to learn more, research more and most of all think more about what I want to truly perform!

P.S. I do have a few recordings of driving logged and have started to sift through the readings/values from the GY-521 in Excel.

picknik123:
I never planned on having the Arduino control the camera picture taking itself.

I wasn't so much thinking of the Arduino controlling the picture taking as being between the person pressing the shutter release and the actual activation of the shutter. Maybe it would be better to delay the shutter start by 100 millisecs to get a better picture.

It's an interesting project.

Have fun.

...R

PS - what about some software that can move the camera in 2 axes to keep it pointing at a particular object in the field of view? But that would be well beyond the capacity of an Arduino :slight_smile: