Measuring acceleration of gravity with arduino

Hi everyone, I just got an arduino a few weeks ago and my first project was to measure the acceleration of gravity of a falling metal marble for physics class. The project uses an electromagnet to release a marble that eventually triggers a photodiode.

Here is what it does:

1) Push red button — engages electromagnet, place marble onto magnet 2) Push black button — release electromagnet and uses micro() to read initial time value 3) Marble eventually passes through an infrared beam and triggers an if statement to read a second time value using micros(s) 4) Find the time difference, display to serial port.

I didn't get the accurate results I was expecting. I am about 0.03 s too short from the ideal value. I am using an output pin to a transistor to a reed relay to trigger the electromagnet. That if anything should make the delta time higher.

I wonder what gives :(

Post your code, maybe it needs some optimizing.

Here it is in all my newbie glory :)

int electromagnet = 7;
int led2 = 6;
int led3 = 5;

int infra_led = 8;

int upperlimit = 0;

int i = 1;

int button1 = 4;
int button2 = 3;

int button_trigger = 0;
int button_release = 0;

int pd = 2;                    //Photodiode to digital pin 2
int senRead = 0;               //Readings from sensor to analog pin 0
int limit = 850;               //Threshold range of an obstacle

unsigned long t1;              // assign values to compute delta T
unsigned long t2;
unsigned long delta;

void setup()
{

  pinMode(infra_led, OUTPUT);
  pinMode(led3, OUTPUT);

  pinMode(pd, OUTPUT);
  digitalWrite(pd, HIGH);      //supply 5 volts to photodiode
  Serial.begin(9600);          //setting serial monitor at a default baund rate of 9600

  pinMode(electromagnet, OUTPUT);
  pinMode(led2, OUTPUT);

  pinMode(button1, INPUT); // sets pin 3 as input
  pinMode(button2, INPUT); // sets pin 4 as input

}
void loop()
{

  digitalWrite(infra_led, HIGH);



  // Read button values
  button_trigger = digitalRead(button2);
  button_release = digitalRead(button1);


  // Trigger the electromagnet
  if (button_trigger == 1)
  {
    digitalWrite(electromagnet, HIGH);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);
  }


  // Release the electromagnetuc
  if (button_release == 1)
  {
    digitalWrite(electromagnet, LOW);
    digitalWrite(led2, LOW);
    digitalWrite(led3, HIGH);

   

    // Reset i so it can print to serial once
    i = 1;
    
     t1 = micros();
    
  }


  int val = analogRead(senRead); //variable to store values from the photodiode

  // Serial.println(val); // Prints out value of Photo-Diode

  upperlimit = 1015;

  if (val > upperlimit) // Determine threshold value at run-time
  {

     // Read the time when the photo-diode is triggered
    t2 = micros();
    
    digitalWrite(led3, LOW);
    digitalWrite(led2, HIGH);

    // Find the time difference
    delta = t2 - t1;

    // Only print the time difference once
    while (i == 1)
    {
      Serial.print ("t = ");
      Serial.print (delta);
      Serial.println ( " microseconds");

      i++;
    }

  }

}

Try this variation

byte electromagnet = 7;
byte led2 = 6;
byte led3 = 5;
byte infra_led = 8;

byte i = 1;
byte button1 = 4;
byte button2 = 3;
byte button_trigger = 0;
byte button_release = 0;

byte pd = 2;                    //Photodiode to digital pin 2
byte senRead = 0;               //Readings from sensor to analog pin 0
int upperlimit = 1050;               //Threshold range of an obstacle
int val;                       // stop sensor

unsigned long startTime;              // assign values to compute delta T
unsigned long stopTime;
unsigned long delta;

void setup()
{

  pinMode(infra_led, OUTPUT);
  pinMode(led3, OUTPUT);

  pinMode(pd, OUTPUT);
  digitalWrite(pd, HIGH);      //supply 5 volts to photodiode
  Serial.begin(9600);          //setting serial monitor at a default baund rate of 9600

    pinMode(electromagnet, OUTPUT);
  pinMode(led2, OUTPUT);

  pinMode(button1, INPUT_PULLUP); // sets pin 3 as input - button to GND to trigger
  pinMode(button2, INPUT_PULLUP); // sets pin 4 as input - button to GND to trigger

}
void loop()
{

  digitalWrite(infra_led, HIGH);



  // Read button values
  button_trigger = digitalRead(button2);
  button_release = digitalRead(button1);


  // Trigger the electromagnet
  if (button_trigger == 0) // button to GND to trigger
  {
    digitalWrite(electromagnet, HIGH);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);
  }


  // Release the electromagnetuc
  while (button_release == 1) {
    // wait here for button to GND to release  ball
  }

  // button pressed!

  digitalWrite(electromagnet, LOW);
  startTime = micros();
  digitalWrite(led2, LOW);
  digitalWrite(led3, HIGH);

  while ( analogRead(senRead) < upperlimit){
    // wait for stop trigger
  }
  // Read the time when the photo-diode is triggered
  stopTime = micros();

  // turn off infrared LED
  digitalWrite(infra_led, LOW);

  digitalWrite(led3, LOW);
  digitalWrite(led2, HIGH);

  // Find the time difference
  delta = stopTime - startTime;

  Serial.print ("t = ");
  Serial.print (delta);
  Serial.println ( " microseconds");


}

Hi, You might have a problem with the fact that it takes time for the influence of the magnetic field to let the ball go, also there will be a delay through the reed relay. You need another photo diode, this one to start the time just below the electromagnet, that way you know the ball is falling. Or have it obstructed by the ball when it is held by the magnet then exposed when it drops.

Tom.... :)

mattosx: I am about 0.03 s too short from the ideal value

Is it possible that it's (partly) because of whatever value you're using for g, not being correct for your locality? Wikipedia (what would we do without it?) shows a list of values for cities round the world.

are you using metric, it may be a roundoff error.

no seriously, you will not get the ideal value due to what was stated above, the earth is a geoiod not a sphere as well as wind resistance, or drag and other bla bla bla stuff

looks like you have a pretty darn good system to me

if you wanted another experiment, you could drop mercury inside a vacuum tube and see what that does

what are you looking for 9.8 mps2? what are you getting?

You have calculated the errors in your experiment haven't you?

Mark

mattosx: 2) Push black button — release electromagnet and uses micro() to read initial time value

I think this happens with your experiment: An electromagnet consists of an inductor which saves electric energy. As soon as you release the electromagnet, the saved energy will lead to a reversed current in the coil, which will also attract the metal marble.

So the falling of the marble starts a little bit later than you cut off the current from the electromagnet. First the electromagnetic field of the electromagnet must collapse enough, so that the magnetic force isn't longer strong enough to hold the marble. Then the marble starts falling down. Maybe after a few hundredths of seconds after you cut off the current.

For exact timing you'd have to measure the time when the marble starts falling and not the time when you cut off the current from the electromagnet.

You will also have to use the same principle of measuring start and stop time, or otherwise any delay caused by the measuring principle will distort the timings.

You would get better data if you put a trip beam just below the starting point so you could get the actual time of drop instead of the time you start to release the ball.

Even more accurate would be three trip beams so you could measure the speed across two consecutive intervals. That would allow you to measure the acceleration without assuming an instantaneous speed of 0 when you release.

Even more accurate would be to do it all in a vacuum to eliminate air drag. :slight_smile:

Thanks all for the responses. The notion of the electromagnet not immediately releasing the marble does make sense, but this does not seem to be culprit.

The theoretical time should be 0.355 s and I am getting 0.32 s or so from arduino. So, it would make sense if I got, say, 0.38 s from arduino given the delay of the reed switch and the time for the magnetic field to collapse, but the time difference is in the other direction! The marble is not dropping too slow, but too fast!

Yes, I realize I can use photo-diodes to record the start and end time and I have done this in the past with other equipment, but unfortunately this means the initial velocity is not zero. For other reasons, I wish to do this experiment with no initial velocity and was hoping the electromagnet would be the solution.

Have you tried video taping and going frame by frame to verify that the arduino is not correct?

Your error is 6.5% which could be due to the arduino clock. You might need to replace the resonator with a crystal. Or use a GPS based frequency reference.

mattosx: The theoretical time should be 0.355 s

Full calculation details? Calculated with which assumed falling distance?

Perhaps you assume a wrong falling distance in your "theoretical time" calculation? Maybe wrong by half or full diameter of the marble?

I'm still going with my question: is the value of g that you're using in the theroretical calc, the right value for your area?

I'd do a quick test with as long a pendulum you can make, measure period as the avge of say 10 or 20 cycles and calc g from that as a double check. That will take you 2 minutes to set up with a piece of string and a nut.

I have tested gravity using video analysis and have gotten nearly exactly 9.8 m/s/s. My measurement distance of 0.62 m which gives a time of 0.355 s using:

t = sqrt(2*height/g)

Changing by the width of the marble does not dramatically change the time. For example, 0.64 m gives t = 0.36 s. The issue remains that the marble drops faster than it should.

If you have a gated frequency counter available, you could use the arduino to gate it. If that gives decent results, it is probably the accuracy of the arduino.

mattosx: My measurement distance of 0.62 m which gives a time of 0.355 s using:

t = sqrt(2*height/g)

And 0.62 m is the distance - from the lower edge of the marble connected to the electromagnet - to the lower edge of the marble when it interrupts the IR beam Correct?

Is the code you posted in reply #2 the same you are using until now?

I think there is something wrong with the release button logic of your code. If you did not correct the code you posted in reply #2, I'd fix/correct the code first before doing further measurements.

TomGeorge:
Hi,
You might have a problem with the fact that it takes time for the influence of the magnetic field to let the ball go, also there will be a delay through the reed relay.
You need another photo diode, this one to start the time just below the electromagnet, that way you know the ball is falling.
Or have it obstructed by the ball when it is held by the magnet then exposed when it drops.

Tom… :slight_smile:

His recorded G value is too LARGE. Any delay in releasing the ball or a delay anywhere else would show up as a too SMALL G value.

Maybe it’s a timing error caused by the @#&^%$@^# inaccurate resonator the Arduino uses for a CPU clock.

Krupski:
Maybe it’s a timing error caused by the @#&^%$@^# inaccurate resonator the Arduino uses for a CPU clock.

I don’t think so. Even an inaccuracy of 5000 ppm with the resonator would be only an inaccuracy of:

t= 0.355 s * 5000 / 1000000 = 0.001775 s

That’s negligible because it’s much less than 10% of the inaccuracy he found.

But I think that his code is a bit weird.

I’d better try timing with something like that:

int electromagnet = 7;
int led2 = 6;
int led3 = 5;

int infra_led = 8;

int upperlimit = 1015;

int i = 1;

int button1 = 4;
int button2 = 3;

int pd = 2;                    //Photodiode to digital pin 2
int senRead = 0;               //Readings from sensor to analog pin 0
int limit = 850;               //Threshold range of an obstacle

unsigned long t1;              // assign values to compute delta T
unsigned long t2;
unsigned long delta;

void setup()
{

  pinMode(infra_led, OUTPUT);
  pinMode(led3, OUTPUT);

  pinMode(pd, OUTPUT);
  digitalWrite(pd, HIGH);      //supply 5 volts to photodiode
  Serial.begin(9600);          //setting serial monitor at a default baund rate of 9600

  pinMode(electromagnet, OUTPUT);
  pinMode(led2, OUTPUT);

  pinMode(button1, INPUT); // sets pin 3 as input
  pinMode(button2, INPUT); // sets pin 4 as input

}
void loop()
{
  digitalWrite(infra_led, HIGH);
  
  Serial.println("Press button to trigger electromagnet");
  while (digitalRead(button2)==LOW); // wait for button2

  // Trigger the electromagnet
  digitalWrite(electromagnet, HIGH);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);

  Serial.println("Press button to release electromagnet");
  while (digitalRead(button1)==LOW); // wait for button1

  // Release the electromagnetuc
  digitalWrite(electromagnet, LOW);
  t1 = micros();
  digitalWrite(led2, LOW);
  digitalWrite(led3, HIGH);

  // wait for sensor signal
  while (analogRead(senRead)<=upperlimit);

  // Read the time when the photo-diode is triggered
  t2 = micros();
    
  digitalWrite(led3, LOW);
  digitalWrite(led2, HIGH);

  // Find the time difference
  delta = t2 - t1;

  Serial.print ("t = ");
  Serial.print (delta);
  Serial.println ( " microseconds");
}

.6 of a metre? That's like off the desk?

I though you would be dropping it off the roof at least.... 3-4 metres