Category Archives: Smart Systems 2014 – DSLR Gimball

Everything works!

Over the course of the last few weeks, we have found a solution for focusing the camera and take pictures with the two buttons on the handle, these uses an interrupt function to not disturb the rest of the loop with delays. While working on this we found out we needed two more buttons, but we solved this by using the third button (the one on the joystick), to have 4 functions on 3 buttons. one function if we press joystick + focus button and another function if we press joystick + shutter button.

There were a few problems recently, for example when we put the arduino board in it’s 3d printed case, the programs loop suddenly stopped, this has been fixed by making a new box (better size of the box). another problem we had, were the gyro sending out wrong output, after some troubleshooting we found out it was a wire on the joystick that had broken off.

All of the components has been mounted to the gimbal, and after some tuning, we have a ready product. We shot a video of the gimbal in action. After some video editing and we have a movie ready for the presentation this Thursday. You can see the movie below.

We also made a video of the extra functions we made for the gimbal, it can be seen below.

While working on this project, we found some things that could be improved and some features we would have liked to have.

  • Replace the servos with step motors for smoother and more accurate movements
  • Send our drawings of the 3d printed bearing supports to be manufactured in metal. This is to make the camera shake less, and support higher weights/movements
  • It would also be nice to get the compass function to work properly, instead of our homemade function that works against the gyroscope buildup of yaw values.
  • The two batteries could be changed out with a battery package and a voltage devider, for easy charging.
  • A screen mounted on the gimbal, showing the liveview from the camera.

 

The final Fritzing drawing is shown below.

Fritzing rev5

The final Arduino code is shown below.

  #include "Wire.h"
    #include "I2Cdev.h"
    #include "MPU6050.h"
    #include "Servo.h"
  
  /*This code was made to function with a custom-made Gimball with an attached DSLR-camera. It's made to
     *function with a 9-axis MPU motion-sensor, equipped with a gyroscope, an accelerometer, and a compass.*/
  
  //Set up some pins.
  int joystickVerticalPin = A0;      
  int joystickHorizontalPin = A1;
  int focusButton = 2;
  int shutterButton = 3;
  int focusPin = 4;
  int shutterPin = 5;
  int joyButtonPin = 6;
  
  MPU6050 mpu;                     //The MPU6050-object is a reference to our 9-axis gyroscope.
  
  Servo servoPitch;                //This servo-object refers to the servo responsible for the pitch-angle.
  Servo servoRoll;                 //This servo-object refers to the servo responsible for the roll-angle.
  Servo servoYaw;                  //This servo-object refers to the servo responsible for the yaw-angle.
  
  int pitchPrevious;               //Stores the pitch-angle from the previous loop for reference in the next iteration.
  int rollPrevious;                //Stores the roll-angle from the previous loop for reference in the next iteration.
  int yawPrevious;                 //Stores the yaw-angle from the previous loop for reference in the next iteration.

  const int maxPitch = 140;        //Limits the maximum pitch-angle.  
  const int maxRoll = 140;         //Limits the maximum roll-angle.  
  const int maxYaw = 100;          //Limits the maximum yaw-angle.
  const int minPitch = 58;         //Limits the minimum pitch-angle. 
  const int minRoll = 63;          //Limits the minimum roll-angle. 
  const int minYaw = 10;           //Limits the minimum yaw-angle.
  const int zeroPitch = 105;       //Neutral pitch.
  const int zeroRoll = 102;        //Neutral roll.
  const int zeroYaw = 58;          //Neutral yaw.
  
  boolean yawLocked = false;       //True if the yaw-rotation is deactivated.
  
  const float percentGyro = 0.90;  //The percentage of the gyro-signal that is used in the complimentary filter computations.
  const float percentAcc = 0.10;   //The percentage of the accelerometer-signal that is used in the complimentary filter computations.
    
  float joystickVertical = 0;      //This holds the additional pitch-angle caused by joystick-tilt.
  float joystickHorizontal = 0;    //This holds the additional roll-angle caused by joystick-pan.
  
  unsigned long focusTimer;        //Timer to know when to stop the focus-signal.
  unsigned long shutterTimer;      //Timer to know when to stop the shutter-signal.
  boolean focusing;                //True if the camera is focusing.
  boolean shuttering;              //True if the camera is taking a picture.
  
  const int adjustmentCoefficient = 0.3; //Used for adjusting and tweaking the written servo-angle based on current angle.
  
  unsigned long timer;                   //The timer measures the time between each gyroscope-reading. Used in the Kalman-filter.
  
  
  void setup() 
  {
      Wire.begin();
      Serial.begin(38400);
  
      //Initialize the MPU and attach the servos to their respective pins.
      Serial.println("Initialize MPU");
      mpu.initialize();
      Serial.println(mpu.testConnection() ? "Connected" : "Connection failed");
      servoPitch.attach(9);
      servoRoll.attach(10);
      servoYaw.attach(11);
      
      attachInterrupt(0, focus, RISING);
      attachInterrupt(1, shutter, RISING);
      pinMode(focusPin, OUTPUT);
      pinMode(shutterPin, OUTPUT);
      pinMode(focusButton, INPUT);
      pinMode(shutterButton, INPUT);
      pinMode(joyButtonPin, INPUT);
      focusing = false;
      shuttering = false;
      
      //Initialize the coordinates to fit the starting position.
      reset();
  }
  
  
  void loop() 
  {
      //Create an array to store the pitch, roll, and yaw respectively, after they've been read and computed.
      int orientation[3];             
    
      //Get the motion-data, fill the array.
      readCoordinates(orientation);
      
      //Check for user-input via joystick.
      readJoystick();

       //Re-adjust the signal to make up for physical off-set.
      //A positive offset will increase the pitch and vice versa.
      int offsetPitch = orientation[0] - zeroPitch;
      int offsetRoll = orientation[1] - zeroRoll;

      //Calculate the increased value based on current angle.
      orientation[0] = orientation[0] + (offsetPitch * adjustmentCoefficient);
      orientation[1] = orientation[1] + (offsetRoll * adjustmentCoefficient);
      
      //Keep the signals for the servos within the angles we have set.
      //We can use constrain() here instead, most likely.
      orientation[0] = constrain(orientation[0], minPitch, maxPitch);
      orientation[1] = constrain(orientation[1], minRoll, maxRoll);
      orientation[2] = constrain(orientation[2], minYaw, maxYaw);
      
      //Store the current angles for reference in the next loop.
      pitchPrevious = orientation[0];
      rollPrevious = orientation[1];
      
      //Add together the gyroscpoe data and the user-input from the joystick.
      int pitchFinal = orientation[0] + joystickVertical;
      int rollFinal = orientation[1];
      int yawFinal = yawPrevious;
      
      if (yawLocked == false)
      {
        yawPrevious = orientation[2];
      }
      
      yawFinal =+ joystickHorizontal;
      
      //Write the final angles to the servos.
      servoPitch.write(pitchFinal);
      servoRoll.write(rollFinal);
      servoYaw.write(yawFinal);
      
      //Print the values to the monitor (for testing).
      printToMonitor();
      
      //Update the timer.
      timer = micros();
      
      //If the camera is focusing, check its timer.
      //If 0.5 seconds has passed, stop the focusing.
      if (focusing == true && (timer - focusTimer) >= 500000)
      {
         digitalWrite(focusPin, LOW);
         focusing = false;
      }
      
      //If the camera is taking a picture, check the timer.
      //If 0.5 seconds has passed, set the shutter signal to low again.
      if (shuttering == true && (timer - shutterTimer) >= 500000)
      {
         digitalWrite(shutterPin, LOW);
         shuttering = false;
      }
  }
  
  
  
  /*This function reads the values from the 9-axis gyroscope, performs the necessary computations
  to apply the Kamlan-filter to the recieved values, and then maps the final values into the range
  of angles that our servos are compatible for.*/
  void readCoordinates(int orientation[])
  {
      //Some intermediate values to store the raw motion-data.
      int16_t ax, ay, az;
      int16_t gx, gy, gz;
      int16_t cx, cy, cz;
      
      int pitchGyro;                  //Stores the mapped gyro-signals for the pitch-angle.
      int pitchAccel;                 //Stores the mapped accelerator-signals for the pitch-angle.
      int rollGyro;                   //Stores the mapped gyro-signals for the roll-angle.
      int rollAccel;                  //Stores the mapped accelerator-signals for the roll-angle.
      int yawGyro;                    //Stores the mapped gyro-signals for the yaw-angle.         
      int yawAccel;                   //Stores the mapped accelerator-signals for the yaw-angle. -> REMOVE?
      int yawCompass;                 //Stores the mapped compass-signals for the yaw-angle.
    
      //Get gyroscope-, accelerometer-, and compass-data.
      //getMotion9 calls getMotion6, then reads and stores the compass-data.
      mpu.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &cx, &cy, &cz);
      pitchAccel = map(ax, -17000, 17000, 0, 179);
      pitchGyro = map(gx, -33000, 33000, 0, 179);
      
      rollAccel = map(ay, -17000, 17000, 179, 0);
      rollGyro = map(gy, -33000, 33000, 179, 0);
      
      //Accellerator does not measure yaw.
      yawGyro = map(gz, -17000, 17000, 0, 179);
      //yawCompass = map(cz, -33000, 33000, 0, 179);
      
      //Apply the complimentary filter.
      //As the accellerometer does not measure the yaw/z-axis movement, we instead utilize the compass data.
      orientation[0] = (percentGyro*(pitchPrevious+(pitchGyro*(double)(micros()-timer)/1000000)))+(percentAcc*pitchAccel);
      orientation[1] = (percentGyro*(rollPrevious+(rollGyro*(double)(micros()-timer)/1000000)))+(percentAcc*rollAccel);
      orientation[2] =  (yawPrevious+(yawGyro*(double)(micros()-timer)/1000000))-1.65;
  }
  
  
  /*Simply reads the position of the joystick and alters the signal to makes sure it corresponds to the physical position.
  Also makes sure the joystick can't steer the servo past its set maximum angle.*/
  void readJoystick()
  {
      //Read the joystick-position and alter it. +/-3 is to make 0 its signal for the resting position.
      // -512 to provide equal +/- numbers. Ignore the signal if the maximum angle has been reached.
      float stickYposition = ((analogRead(joystickVerticalPin) - 512) / -50)*0.080;///5;
      float stickXposition = ((analogRead(joystickHorizontalPin) - 512) / 50)*0.04;///5; 
      
      if ((pitchPrevious + joystickVertical + stickYposition) >= maxPitch)
      {
        stickYposition = 0;
        joystickVertical -= 0.4;
      }
      else if ((pitchPrevious + joystickVertical + stickYposition) <= (minPitch))
      {
        stickYposition = 0;
        joystickVertical += 0.4;
      }
      
      if ((yawPrevious + joystickHorizontal + stickXposition) >= maxYaw)
      {
        stickXposition = 0;
        joystickHorizontal -= 0.4;
      }
      else if ((yawPrevious + joystickHorizontal + stickXposition) <= (minYaw))
      {
        stickXposition = 0;
        joystickHorizontal += 0.4;
      }
      
      //Add the input to the offset caused by the joystick.
      joystickVertical += stickYposition;
      joystickHorizontal += stickXposition;
  }
  
  //Resets the gimbals zero-angle position based on the current one.Might need to use accelerator-data here.
  //Maybe change this and use it for initializing the position on start-up as well.
  void reset()
  {
      joystickVertical = 0;
      joystickHorizontal = 0;
      servoPitch.write(zeroPitch);
      servoRoll.write(zeroRoll);
      servoYaw.write(zeroYaw);
      pitchPrevious = zeroPitch;
      rollPrevious = zeroRoll;
      yawPrevious = zeroYaw;
  }
  
  //Interupt routine for the camera-focus.
  void focus()
  {
    if (digitalRead(joyButtonPin) == HIGH)
    {
      digitalWrite(focusPin, HIGH);
      focusing = true;
      focusTimer = micros();
    }
    else
    {
      reset();
    }
  }
  
  //Interupt routine for the camera-shutter.
  void shutter()
  {
    if (digitalRead(joyButtonPin) == HIGH)
    {
      digitalWrite(shutterPin, HIGH);
      shuttering = true;
      shutterTimer = micros();
    }
    else
    {
      yawLocked = !yawLocked;
    }

  }
  
  //Prints values to the screen. For testing and monitoring.
  void printToMonitor()
  {
      Serial.print("Pitch:");
      Serial.print(pitchPrevious);
      Serial.print("\tRoll:");
      Serial.print(rollPrevious);
      Serial.print("\tYaw:");
      Serial.println(yawPrevious);
  }

We had some problems

We have tried to make the compass function of the gyro sensor to make the gimbal rotate, but while testing it we found out that the output from the compass is between about 20 degrees to 116 degrees. The problem is that the scale goes from 20 -> 116 -> 20, in other words if we for example start at position A (20 degree), and we move the gimbal 13 degrees, then it’s hard to tell what direction it went. It also seems like the sensor gets affected by other compass sensor axises.

Sensor grader

We experimented with temporary solutions which, when put into use, turned out to function far more satisfactory than we anticipated. In the end we found that we were able to adjust the rotation exclusively through the gyroscope, without it building up the drift we feared it would. It might not react to very slow and small rotations, perhaps depending on the placement of the MPU, but for our purpose it currently seems to be responding effectively and correctly.

Video av testen vår:

Vi kommer til å bruke uken som kommer til å justere verdier og prøve å gjøre gyroen mer responsiv, i tillegg vil vi prøve å få til å ta bilde via knapper gjennom arduinoen.

The parts has arrived!!

The new motion sensor named MPU-9150 has arrived! The new motion sensor contains a 3axis gyroscope/accelerometer/magnetometer and is hopefully what solves our “YAW” problem. The new chip has a digital compass that should make it possible to control the rotation axis. Last week we soldered a small circuit on our prototype shield. This circuit contains two optocouplers and a few resistors. The purpose of this circuit is to control the focus and shutter trigger on the camera. This is controlled by two buttons placed on the left handle on the gimbal. We also made a housing for these buttons. The connection to the Arduino-UNO is shown in the previous post named “small update”.

Motion sensor and shield

This week we focus on getting a functional code that serves all expected purposes for our gimbal. Implementing and testing the “compass” part of the motion sensor is our main focus. Trying to implement the joystick function will come next.

Things are coming together

Since we are going to use a joystick to overwrite the cameras position, we have decided we are going to place it on one of the handles. Therefore, we wanted to design a case for the joystick and 3D-print it, we had to make sure we could fit the case on the handle, while still being able to move the joystick. The result is seen in the image under.

pot case

Since the start of the project, we have been trying to make a arduino code. While doing so we encountered some problems, using the gyroscope for longer duration made it inaccurate. To resolve this we are using a kalman filter, which uses a percentage of the accelerometer to make it more accurate over time. Another problem is that our gyro sensor does not include a magnetometer, we have ordered a new gyro sensor but we are waiting for the shipping.

During the last week, the gimbal were painted black and the servos have been mounted. The next week we are going to make our arduino code better and do some testing.

gimbal

Ready for welding!

Since the first blog post, the group have advanced in our progress. We have looked into different Arduino codes, tried making our own version of the code and we have tried it out with our servos. While trying it out, we ran into some problems with controlling one of our axis. We are going to look into this problem the following week.

We have also completed our sketch of our gimbal in Solidworks. This sketch is used to simulate all the rotation in 3D and it makes the mechanical work easier.

gimbal solidworks

The group bought aluminum materials and it is cut into the right lengths according to the AutoCAD and Solidworks drawings. The materials are now ready to be welded. 

Aluminum materials

In the following weeks, we are going to look into controlling the last axis, welding our materials and mount our equipment on the gimbal

Gimbal-3000 – Current process

Autocad tegning

This is the blog for the project Gimbal-3000, an project about the making of a gimbal for an DSLR camera. There are 3 members in the group, two cybernetics- and one virtual systems- student

Cybernetics: Torbjørn Harsund and Ole Martin Rosbach

Virtual Systems: Jonny Bråten

We started off the project trying to find existing projects, using them as a template and analyzing their pros and cons. From there we started sketching different alternatives and later choosing our system. We also began making AutoCad drawing and Solidworks models to calculate the sizes of the metal we are going to use.

Solidworks

One of our problems is that we are going to use servos (Tower Pro MG995) but we can’t overburden the shaft, to solve this we are going to use bearings welded to the “chassi”. This was also a problem, since if it gets welded we risk of distortion. Therefore we had to find another way to attach it, our solution is to use a 3D printer to design and make a bearing support bracket

Bearing support

In the following weeks we are going to look into optocouplers, how to code the gyro sensor and find solutions on our extra features.