![]() |
Unexpected results from Encoder::GetRate()
I'm trying to set up a speed controller using the US Digital E4P-250-250-D-D-D-B encoder and the WPI Encoder class. Everything basically works fine but I'm seeing an odd discrepency between the values out of GetRate() and GetDistance(). Spinning the encoder at a constant rate, I would expect that the rate returned by GetRate() (units/sec) would more or less match the one-second delta returned by GetDistance(). But what I see is this: the distance returned for one second is almost exactly half of GetRate(). Because GetRate() is fairly noisy, I'm testing using a 20 sample moving average (with a sampling rate of 40hz). I'm sure I'm missing something obvious... Can one of the WPIlib experts here clue me in on what it is? Thanks!
Update, possible clue: Looking through the WPI source I noticed this comment in Counter.cpp (used by 1x and 2x Encoder): /* * Get the Period of the most recent count. * Returns the time interval of the most recent count. This can be used for velocity calculations * to determine shaft speed. * @returns The period of the last two pulses in units of seconds. */ double Counter::GetPeriod() |
Re: Unexpected results from Encoder::GetRate()
Just now seeing the same problem when running x1 with the kit encoders.
GetDistance() gives the correct value but the GetRate() gives double rate. Anybody using this function with success? We have all the latest updates in SW. Update: I decided to check the GetPeriod() in Encoder.cpp. I don't see any problem with the LyraS question but something else seems strange to me here and maybe someone can tell me why its correct. double Encoder::GetPeriod() { if (m_counter) { return m_counter->GetPeriod() * DecodingScaleFactor(); //****THIS IS WHERE I SEE A PROBLEM *** } else { tEncoder::tTimerOutput output = m_encoder->readTimerOutput(&status); double value; if (output.Stalled) { // Return infinity double zero = 0.0; value = 1.0 / zero; } else { value = (double)output.Period / (double)output.Count; } wpi_assertCleanStatus(status); return value * 1.0e-6 / (DecodingScaleFactor() * 4.0); } } In the 1x and 2x the counters are used. The period that the counters return should be for the actual pulses not the spec pulse frame. Hence, the periods should be shorter when running 2x. So when if (m_counter) { return m_counter->GetPeriod() * DecodingScaleFactor(); //****THIS IS WHERE I SEE A PROBLEM *** } occurs, it should correct the counter period to the spec period which would be longer. This statement makes the period the same or shorter since DecodingScaleFactor() returns 1 for 1x , .5 for 2x. It seems that this should read if (m_counter) { return m_counter->GetPeriod() / DecodingScaleFactor(); //****USE DIVISION TO CORRECT PERIOD *** } The division by DecodingScaleFactor() would then be similar to that used in the 4x return value. If my reasoning is correct, then the 2x should be off by a factor of 4 but the 1x should be ok. So unfortunately this doesn't explain why we still are double the rate when running at 1x and maybe when I get some time, I'll check this hypothesis. Where is Joe Hershberger when we need him? |
Re: Unexpected results from Encoder::GetRate()
Have you guys tried 2x and 4x modes? Do you get what you expect in those modes?
At a glance, it looks like the period should be divided by DecodingScaleFactor(), as suggested. I don't think the 4x version should have the "4.0" in the denominator either. I need to try it out when I'm at a system that has an encoder. I'm at the regional in Cleveland this weekend. -Joe |
Re: Unexpected results from Encoder::GetRate()
Quote:
Quote:
|
Re: Unexpected results from Encoder::GetRate()
Encoder::GetRate() in 4x mode returns crap. And by crap I mean the value returned is proportional to the speed of the robot, but I know our bot is not going 80 feet per second (55 mph)... I tried changing (4x mode) to return:
Code:
value * 1.0e-6 / DecodingScaleFactor()Code:
value * 1.0e-6 / (DecodingScaleFactor() * 4)I know I can just multiply the returned value by some gain, but I'd rather have the code actually be right. I'm about to go chuck the dang thing up in the lathe so I know what the value returned should be, and work from that. |
Re: Unexpected results from Encoder::GetRate()
Good to have another data point. Couple of questions.
Is the GetDistance() correct? If so, can you use it to make a quantitative estimate on what the ratio of encoder rate to actual rate in x4 after you eliminated the 4 factor in the denominator? I'm guessing it might be off by a factor of two like the 1x. If it is, that could provide a clue to whats going on. In my experience, using 4x to get rate always introduces extra noise due to inherent phase errors built into the code wheels. http://www.chiefdelphi.com/forums/sh...=encoder+noise |
Re: Unexpected results from Encoder::GetRate()
Quote:
|
Re: Unexpected results from Encoder::GetRate()
Quote:
1x and 2x are not as noisy. And are normally distributed. 4x is distributed towards the center and +- some value. It's either a code problem or an encoder problem. I'm going to hook it up to a function generator and figure out which it is. |
Re: Unexpected results from Encoder::GetRate()
Quote:
|
Re: Unexpected results from Encoder::GetRate()
Quote:
I could also just fix my stupid 2nd probe and look at the encoder output on the scope... BTW, the FPGA code could be changed to account for the phase lag. It's actually a very easy fix, although it would require you to experimentally determine the phase lag and pass it to the FPGA. Determining this would simply require spinning the encoder at a constant speed and look at the channel B phase offset. |
Re: Unexpected results from Encoder::GetRate()
Quote:
It is hard to envision that the encoder could be in error if GetDistance() is working, so I vote for the code. |
Re: Unexpected results from Encoder::GetRate()
Quote:
The encoders are the reason for the noisy data returned by 4x decoding. GetDistance isn't greatly effected by this because every rising/falling edge is offset an equal but opposite amount, so it averages out to be correct. The problem comes in when you try to take the derivative (GetSpeed), because now these offsets are no longer averaged out. |
Re: Unexpected results from Encoder::GetRate()
I did not follow the entire thread of discussion so if I misunderstood the issue, I apologize. But I do want to mention my experience on dealing with the accelerometer by integrating it twice to get distance. How did you differentiate the distance value to get speed? In particular, how did you get dt? The reason I ask is because I discovered that if you have code that is supposed to be run periodically at a fixed interval, don't count on the interval being accurate. For example, my integrator code is supposed to run every 10 msec, eventually I found out that it got called every 20+ msec instead. So don't use the period as your dt because it is not accurate. Your speed data will be all over the place. I scratched my head on the accelerometer for a while until I finally timed the interval of my code being called and found that I can't depend on it being constant. So I now wrote the code to measure the interval and use it as my dt instead. Then my integrator is now quite accurate.
|
Re: Unexpected results from Encoder::GetRate()
Quote:
Quote:
So the noise is expected, but the mean values being off by a constant is what I'm focused on. This smacks of a FPGA counter average period problem. |
Re: Unexpected results from Encoder::GetRate()
Quote:
In support of your comments, we use the iterative robot class and a navigation function that integrates encoder rate resolved to field coordinates. Distance tests were off by a factor of 2. Either the speeds were double or the loop iteration rate was double. We integrated dt = 1/(Update_Rate) and checked that the computed time matched real time so this led us to the double encoder GetRate() error which we verified independently using motor rpm measurements. |
| All times are GMT -5. The time now is 14:23. |
Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi