Time between sensor readings, to calculate rate of change

25 Jan 2014

Continuing my little project: http://mbed.org/forum/helloworld/post/23256/ and http://mbed.org/forum/helloworld/post/23317/

So far I have created a 1dof robot arm that is positioned with feedback by an analog IR distance sensor. Currently the arm moves to maintain a desired sensor reading. I can adjust the desired reading to move the arm, or move a target in front of the sensor to move the arm. This all works pretty well.

My next step is to target a desired rate of change between target values. Right now the arm moves at a rate determined by a fixed PWM step value. I would like to change this so the arm will adjust the PWM step to achieve a certain rate of change in the sensor data. Long story short, I need to know the time between sensor readings so I can calculate the rate of change. I searched around but could not come up with a method to do this. Currently the program is running at nearly 200 hz, determined by using a stopwatch and a counter displayed on teraterm, best I could do.

The ultimate goal is to tell the arm "move 3 inches forward at a rate of 0.2 inches/second" and have it all be controlled by the sensor. I will need to calibrate and linearize the sensor data for this, but the first step is to figure out the rate of change. Any ideas to point me in the right direction?

25 Jan 2014

Quote:

Long story short, I need to know the time between sensor readings so I can calculate the rate of change.

Sounds like you need the Timer class: http://mbed.org/handbook/Timer

25 Jan 2014

That looks like the place to start thanks Erik! Is it better to use the time to create a controlled sampling rate, or just measure the time between the naturally occurring sample rate? I ask this because I noticed a significant difference in sample rate when I was printing debug info to terminal, vs turning off the debug statements. With the debug I was seeing about 40 Hz, without debug I saw 196 Hz. This makes me think I should invoke and read the timer every time the sensor is polling function is called, or maybe every other time. Seems to reset every 30 minutes, not sure how to handle that, I guess just ignore it for now.

25 Jan 2014

It depends on your situation. Sometimes it is better to control the sample rate (use Ticker for that btw). For example if you just have to update some output 10 times per second, you use that. If like you have it is mainly important to know the time between the read you use that one.

If you want you can btw increase the baudrate of your debug messages, that can help. Also the 30 minute reset happens when you don't reset your timer yourself, so if the time between two sensor calls is more than 30 minutes. If you just reset it yourself (which is the normal way to use it, you reset the timer, start it. Then next time you stop the timer and read the value, if it is running you can also skip on the starting and stopping, and just reset the timer everytime after you read the value since last reset), you aren't affected.

25 Jan 2014

So far this is what I have done inside of my median filter function, where the sensor is actually read. I read the timer immediately after the sensor, and store the time in the array cell next to the sensor value. I store the last five in order.

float median() 
{
    timer.reset();
    timer.start();
    countz += 1;
    sensval = Sensor;
    med[4][0] = med[3][0];  med[4][1] = med[3][1];
    med[3][0] = med[2][0];  med[3][1] = med[2][1];
    med[2][0] = med[1][0];  med[2][1] = med[1][1];
    med[1][0] = med[0][0];  med[1][1] = med[0][1];
    med[0][0] = sensval;    med[0][1] = timer.read_us();
        
    samples[4] = med[4][0];
    samples[3] = med[3][0];
    samples[2] = med[2][0];
    samples[1] = med[1][0];
    samples[0] = med[0][0];
        
    qsort (samples, 5, sizeof(int), compare);
    
//    pc.printf("\n%i   %f   %f",countz,sensval,samples[2]);
    
    return (samples[2]);
}
03 Feb 2014

Trouble with timers..Im not trusting the numbers I am getting.

I initiate the timer globally using: Timer timer;

I start the timer in the main function using: timer.start();

I read the timer in a function using: timer.read();

I track the last 5 samples in the arrays (all floats) as seen in the code below. The median function is running in a loop as fast as it can. The 'dt' variable is calculating consistently to be .000061 seconds, or 61 micro-seconds. So this equals 1/.000061=16393 Hz. Is that possible?? What am I doing wrong? An example of the five values stored in the times array are: 224.943375 224.943314 224.943268 224.943207 224.943130

void median() 
{
    sensvals[4] = sensvals[3];      times[4] = times[3];
    sensvals[3] = sensvals[2];      times[3] = times[2];
    sensvals[2] = sensvals[1];      times[2] = times[1];
    sensvals[1] = sensvals[0];      times[1] = times[0];
    sensvals[0] = Sensor.read();    times[0] = timer.read();
  
    sensort[4] = sensvals[4];
    sensort[3] = sensvals[3];
    sensort[2] = sensvals[2];
    sensort[1] = sensvals[1];
    sensort[0] = sensvals[0];
        
    qsort (sensort, 5, sizeof(int), compare);
    
    medians[4] = medians[3];
    medians[3] = medians[2];
    medians[2] = medians[1];
    medians[1] = medians[0];
    medians[0] = remap(sensort[2]);  //this is the current position
    
    dt = times[0]-times[1];
    velocity = (medians[0] - medians[1])/dt;
}
03 Feb 2014

You can put in a wait statement if you don't trust it, see if that gives a normal result. But would it be too slow or too fast? And I assume you got those values after it ran for a couple of minutes? Also if you only want the time between measurements, reset the timer after reading it.

Is Sensor an AnalogIn? Or is it another library? (Btw if you want faster AnalogIn, have a look at: https://mbed.org/users/Sissors/code/FastAnalogIn/). That will take quite some time, since the library reads a couple of times and then averages it. Most other stuff is fairly easy, just some SRAM copy/paste operations. No idea how long qsort takes, but I don't expect that long either. And I don't know what remap does. Your few floating point operations you have there will take some time.

Personally I would have expected it to be a bit faster, but it doesn't look that far off to me. If you want you can try to figure out yourself what takes most time. And you can probably do alot more with ints than what you do now, that should speed it up more.

If you expected it to be slower, then I wouldn't worry about it ;).

03 Feb 2014

Hi Erik, Good question...do i think it's too slow or too fast..I should have specified! I thought this was way too fast. I did not think it could take data that quickly. I thought I read somewhere that 200Hz was the max. Yes Sensor is an Analogin. remap takes the sensor reading and converts it to inches using a polynomial curve equation from excel. I understand your comment about the floats, but I do not know enough about that stuff yet to tweak. I was actually trying to figure that out yesterday if I needed int, float, or double for the timer, actually tried all three. I will make a point to read up on it the differences and when to use what...I thought ints didnt have a decimal place in them.

So I am surprized to here that it should be faster! I guess that is good, but probably way to fast for the PI feedback loop I am attempting to create. I initiallywas reseting the timer as you mention, but it was giving me 23 micro-seconds between readings which I thought was way to fast. I assumed there must have been a lag time at timer startup so i eliminated the per cycle resets. And i was taking the values within the first 30 seconds of running, should I wait a couple minutes for some reason? I guess if this high speed data taking is for real then I can spend more time on signal conditioning.

Thanks and I will have a look at FastAnalogIn and see if I can make heads or tails of it.

03 Feb 2014

There is not much heads or tails to make of FastAnalogIn, you can just replace regular AnalogIn and it should work. But if it is going more than fast enough anyway I wouldn't worry about it, regular AnalogIn averages a few times, so that is more accurate. I think you are confused with the 200kHz of the ADC, not 200Hz ;). So that is 5us per ADC sample, it takes a few, some overhead, lets say 20us. And then some other stuff, your remap function will also take a few microseconds probably for example.

Regarding which you need, timer.read returns a float, but timer.read_us returns the time in microseconds as an integer. Advantage of that is also that you don't need to worry about overflows when you calculate the time between two samples (that will fix itself when you substract them, as long as you define them as unsigned ints.

The reason I assume it was running a few minutes is because of the times you showed, somewhere in the 200 seconds range. Which would be roughly 4 minutes.