We’re using a variety of sensors this year including limit switches and inductive proximity sensors, however, I’m worried that sensor noise may mess with our programming logic. Are there any good ways to minimize the noise as much as possible?
Could you post more information about the sensors you’re using, along with how you’re using them?
If I were programming a micro controller and I were using a push button switch as an interrupt, I would need to add either a debouncing circuit or a debouncing function in software to ignore unintended repeated taps on the same button as it settles.
Two different ways to accomplish this - in hardware you might add an RC circuit to the button as a low pass filter to remove the bounces, in software you might use a timer to terminate all subsequent interrupts in the range of a millisecond or two.
Not sure what problems you may be having with the proximity sensor.
Another suggestion is to look at your software - what you’re interested in the switch might not be if it’s pressed or not, rather the state has changed from 0 to 1 or 1 to 0 (rising edge or falling edge).
This is accomplished by storing the old value and XOR’ing it with the new value (state has changed), then AND’ing the result with the old value or the new value.
This won’t debounce your circuit, but it will prevent you from running a function in your main loop more than once per button press.
We’re using an elevator-style indexer on our robot like this with a proximity sensor mounted on the aluminum bar in the lower left corner of that picture, which detects the carbon steel screws on the trays. The prox sensor should stop the lift when the screw is detected, which would put the frisbee in the right location to be injected into the shooter wheels. Noise in the sensor return could then cause the shooter to stop after only a few milliseconds instead of going to the next tray like it’s supposed to. If we gave it a command to “go up X slots,” noise would again cause it to stop early.
Could you explain a bit more about the de-noising circuits/software implementations?
Instead of stopping as soon as you detect a screw, you could wait for two (or three, or whatever) consecutive “screw present” readings. This would eliminate spurious stops from a single noisy reading. If necessary, you could stop the motor, collect a few readings, and then make a decision about whether there was a screw or just noise.
Because you know approximately how long the motor should run between screws, you could also filter out detections that come far too soon. However, this only reduces the problem; it doesn’t really eliminate it.
I’ve used this in some non-FRC applications:
here’s your sensor reading over time:
00011000000000001111111111111111111100000000
Noise Good input
Your goal is to ignore out the sporadic 1s in the beginning. Try ANDing your sensor input with the previous 2 inputs. This will filter out the noise.
Once you hit the noise:
(0 AND 0 AND 1) = 0
(0 AND 1 AND 1) = 0
(1 AND 1 AND 0) = 0
Electrical implementation depends a little bit on the specifics of your sensor’s output, I think. That is, whether it’s a TTL output, sinking, sourcing, open collector, etc.
Software implementation is conceptually easy, but implementation could be tricky depending on how you do it. The idea is to “debounce” the signal. Bouncing is when the sensor output, most typically on a physical limit switch, bounces from on to off before settling on one value. So conceptually, you don’t want to treat the Input as “On” until it has been On for Xms without any changes. If your debounce time is 10ms and the input is On for 5ms then briefly switches Off for 1ms, then you restart the timer and wait another 10ms after it turns back On. Eventually the signal turns on and stays that way for 10ms and you treat finally treat it as actually on.
Depending on how many of these you need to act like this, you can treat it in a number of ways. I was originally hoping you could wrap DigitalInput and use the input interrupts and a Timer that generated an interrupt event… and then I discovered that the Timer class (in C++ anyways) doesn’t have interrupts implemented. So wrapping DigitalInput looks like it’ll be somewhat more complicated… I suppose you can do it with a Timer and only have the check occur when the Get function is called… That’s the only time you’re going to care anyways, so it’d actually make sense. I think I could actually whip up code for that fairly easily. Whether it’d work right the first time is another question, and it’d definitely be in C++, so that might not be super useful to you.
If you only need debouncing on this one sensor, you might do a similar thing, but outside the class in the teleop loop or wherever you’re checking for this condition. Pseudo code:
if(oldInput != input)
timer.Reset();
oldInput = input;
if(timer.HasPeriodPassed(deb_time) && input != debInput)
debInput = input;
“debInput” would be the “denoised” value you’d want. Mind you, this has to run in some sort of periodic loop for it to work, and the resolution is only going to be as good as the period of said loop. If you’re running this in a 20ms loop, then it obviously can completely miss the signal bouncing around for up to 19 ms as long as the signal is at the same value from one 20ms cycle to the next. Interrupts would give you a lot better control on things, but would be more complex and might be unnecessary.
If you have the resources, you should hook the sensor up to an oscilloscope to determine how fast it is bouncing.
Another approach is to use interrupts to set flags. When the sensor is tripped, an interrupt sets the value of a variable and stores the time the interrupt was triggered.
When the main loop runs through, it checks the flag and compares the time it was triggered to the last. If the flag is set and time delta is great enough, you do whatever action you want (stop motors, for instance), then clear the flag and store the last time.
A problem I foresee with this implementation is you’ll be accessing variables on different threads, you’ll need to be careful with the way you declare the variables (use a mutex in C++ or atomic variables in java, not sure about LabView).
You might want to look into the kalman filter. Works well for lots of different sensors.
Because of the tolerances involved, I’m wondering if it might be better to wait for the first poll to come up positive, then wait X milliseconds before stopping (or continuing, to go more than one slot on the elevator). This assumes that it starts bouncing at roughly the same spot, which I don’t really have the ability to test.
That would serve the dual purpose of preventing accidental triggers both at the beginning of the rotation (when the screw leaves the range of the proximity sensor) and at the end of the rotation (when it comes back into range).
60 milliseconds (needed to check the sensor 3 times) might be too long unless there’s some way of making a loop run faster than 20ms. 2 checks might work. Interrupts or a kalman filter sound like the ideal solution but would take far to long to get programmed.
I supposed I could tell it to knock back the speed after X milliseconds (roughly 90% of the way there) to make the time less of an issue. Then we’d have to buy and mount another Jaguar. Ugh.
A Kalman filter is completely useless for this as you’re dealing with a digital switch, not an analog sensor. When do you need code for this by? Writing a wrapper for a C++ DigitalInput wouldn’t be too time consuming, but I can’t guarantee it’ll work until I get a chance to test it on our robot. And if you’re using Java, you’d have to port it yourself.
We’re using Java, and we’re in 3rd week comps, so we need to have it worked out by Tuesday/Wednesday night in a week and a half.
Have you determined what sort of noise you’re dealing with?
For switches, there are a couple sources of noise:
. bounce on the switch. This varies widely depending on the type of switch you are using. Our experience has been that the KOP Honeywell snap action limit switches have very little bounce, proven both by looking at them on the scope and observed in the robot.
. noise on the line. Our robot had troubles with this, due to long two wire runs. You can fix it a couple ways: 1) convert to 3 wire runs; 2) use shielded cable; 3) build an external pull-up with a lower valued resistor (we use 1000 ohm). We did #2 and #3 this year.
For encoders, so far we haven’t bothered averaging the counts as they haven’t seemed to have an impact.
Would wrapping the wires in Aluminum foil theoretically help with electrical noise?
Yes, if you’re absolutely convinced that you’re dealing with electrical noise, aluminum foil might help. But other things will probably help a lot more, like keeping your sensor wires away from high-current-carrying wires and using a pull-up resistor.
Are you actually dealing with electrical noise, or is this a sensor noise issue? Is your signal clean coming directly out of the sensor?
This year we’re using a moving average to filter out noise from our sensors. It’s about seven lines of code total, and works by feeding a stream of data into an array and calculating the average continuously. It works really well for rangefinders, but I’m sure it’s applicable to almost anything. All you need to do to adjust the sensitivity is change the sample size.
Applicable to anything except a digital signal. Unless 2/3rds on has some sort of meaning I’m unaware of.
While Kevin’s approach is far more elegant, this might work for you in a pinch:
/* some set-up */
#include <stdio.h>
#define true 1
#define false !true
typedef char boolean;
/* a program to run the stuff */
int main (void)
{
static int array[5] = {0,0,0,0,0};
static int counter = 0;
boolean persistence;
boolean digitalInput;
int i;
/* run the persistance checker in a loop */
for (i=0; i<10; i++)
{
/* put in some false then put in some true */
if(i>4)
digitalInput = true;
else
digitalInput = false;
/* check on the input and fill the
* persistence array with the result
*/
if( digitalInput)
array[counter] = 1;
else
array[counter] = 0;
/* keep tabs on the array index */
counter++;
if(counter > 4)
counter = 0;
/* now AND the entire array and show the result */
persistence = array[0] && array[1] && array[2] && array[3] && array[4];
printf(" perist = %d
",persistence);
}
}
When the array fills and remains filled, you get true, otherwise it’s false
…ugly but it could work
Eric
*Here’s a simple IIR filter which does essentially the same thing with 2 lines of code, no loops, and no conditional logic:
ave = 0.5*(input+ave);
output = truncate(ave+0.03);
It does use floating point (for ave), but the cRIO has an FPU.
input and output are 0 or 1.
Last year we created a class to handle averaging out our noise. we were using this for sensors that gave us analog data, but you could send in 1.0 and 0.0 on the output side for a digital signal.
What ended up being nice about this class last year was that we could very easily change how many samples were being included in the average. As we started to speed things up throughout the season, we needed the average to be more responsive (fewer samples)
Here’s the Java code: https://gist.github.com/jcorcoran/5097376