Trying to add a shaker motor to a pinball machine. I am using a shield that accepts switch inputs, flasher inputs and solenoid inputs and converts them to 0 to 5V for the Arduino to receive.
My problem is with the solenoids. I am reading the knocker and get a solid 5V pulse that last for 50ms. I can read this perfectly. When another coil fires I get noise on the knocker line, ~8 pulses from 0 - 5V in the same time span (about 7.5ms each). My Arduino reads this and triggers the shaker.
Attached are some pictures of the pulses I'm seeing. Hoping to hear some strategies where the Arduino will ignore the quick pulses. I tries using pulseIn with no luck (good pulse should have resulted in pulseIn outputting "0" over 20ms).
#include <PWM.h>
int shaker = 3;
int knocker = 9;
int32_t frequency = 20000; // sets PWM frequ above human hearing to keep shaker from making noise
void setup() {
pinMode (shaker, OUTPUT);
pinMode(knocker, INPUT);
InitTimersSafe(); // something for the frequency thing
SetPinFrequencySafe(shaker, frequency);
pwmWrite(shaker, 0); // make sure shaker is off
Serial.begin(9600);
}
void loop() {
int pulseCount = 1; // shaker should not run if this number is anything but 0
int knockerState = digitalRead(knocker);
if (knockerState == HIGH ) // arduino reads coils as LOW until they are activated
{
pulseCount = pulseIn(knocker, LOW, 20); // pulseIn should return 0 if knocker is activated and 1+ when another coil hits
}
if (pulseCount == 0)
{
shake();
pulseCount = 1;
Serial.print(pulseCount);
}
}
void shake() {
pwmWrite(shaker, 255);
delay(50);
pwmWrite(shaker, 239);
delay(400);
pwmWrite(shaker, 0);
}
It looks like a bad power supply or a wiring error. Post an annotated schematic showing how everything is wired including power sources and links to the hardware items.
The wiring and power supply appear to be functioning correctly based on the below:
I measured the knocker output with the scope (Arduino, power supply and shaker not in game) and I saw the same wave pattern, 50ms pulse for the knocker, and ~8 spikes on the knocker wire when any other solenoid was fired. The only difference was the peak was ~60V as that is what the game runs. The pinball machine is functioning correctly and I replicated these results on a different pinball machine.
The noise you see after the pulse is the shaker motor kicking on. I was able to see the same pulses (minus the shaker motor noise) when I scoped the machine with the shaker disconnected.
If there is a noise problem, it is usually best to try to eliminate the source rather that to eliminate it from the measurements.
Does that knocker output switch cleanly between the 0v and 5volt power rails or is there a pull down resistor so the Arduino input pin is never floating?
Probably the easiest method of eliminating the effect of those spurious pulses which seem to have a period of about 7.5ms is to use an exponential moving average algorithm. The description is quite technical but in practice it is only a few lines of code. Here is one example: Exponential Moving Average (EMA) Filters | mbedded.ninja
You'd probably have to get rid of those delays in the loop to use such an algorithm. Use millis() instead as in the "blink without delay" sample sketch.
If there is a noise problem, it is usually best to try to eliminate the source rather that to eliminate it from the measurements.
Unfortunately I just think that is how the game works as I got the identical "noise" on separate machines. These games have upwards of 20 solenoids so not sure it's practical to try and eliminate the stray pulses.
Does that knocker output switch cleanly between the 0v and 5volt power rails or is there a pull down resistor so the Arduino input pin is never floating?
The knocker from the game has a constant ~60VDC going to it. It is triggered through a transistor that pulls the other wire to ground. The shield converts this to a normally LOW (0V) signal that changes to a HIGH (5V) for the Arduino to read. There is a pull down resistor on the shield to prevent floating.
OK. I think I've understood it. That shield is doing all the voltage level shifting and signal conditioning for interfacing to that pinball game. If that shield is delivering these "spurious" pulses, then you have to use a filtering algorithm to get rid of them. How much latency can it have, that is between a detection of the knocker and the starting of the shaker? Up to 50ms ?. What ever filter you use will have some latency during which it discriminates between the valid and the invalid pulses.
You could try this code sample which respects pulses which are longer than 50ms only but does not use a moving average filter.
#include <PWM.h>
int shaker = 3;
int knocker = 9;
int32_t frequency = 20000; // sets PWM frequ above human hearing to keep shaker from making noise
void setup() {
pinMode (shaker, OUTPUT);
pinMode(knocker, INPUT);
InitTimersSafe(); // something for the frequency thing
SetPinFrequencySafe(shaker, frequency);
pwmWrite(shaker, 0); // make sure shaker is off
Serial.begin(9600);
}
void loop() {
static bool inPulse = false ;
static bool inLongPulse = false ;
static uint32_t inPulseAtMs = 0 ;
if ( digitalRead( knocker )) {
if (inPulse == false) {
inPulse = true ;
inPulseAtMs = millis() ;
}
else {
// have we been in this pulse for > 50ms ?
if (millis() - inPulseAtMs > 50 && inLongPulse == false ) {
inLongPulse = true ;
Serial.println("enter long pulse") ;
shake() ;
}
}
}
else {
inPulse = false ;
if ( inLongPulse ) {
inLongPulse = false ;
Serial.println("exit long pulse") ;
}
}
}
void shake() {
Serial.println("in shake()") ;
pwmWrite(shaker, 255);
delay(50);
pwmWrite(shaker, 239);
delay(400);
pwmWrite(shaker, 0);
}
So I tried your code, and it worked! But only why the game was in test mode
In test mode you can activate individual solenoids with some buttons in the coin door. Your code worked perfectly here. I then started a game and when random solenoids were activated, I got no shaker action. I then entered a mode where the knocker would activate... and the shaker did not turn on.
I hooked up the scope again and discovered that during test mode I see a ~50ms pulse when the knocker is activated but during actual game play the pulse is ~20ms.
I went back into your code and changed "inPulseAtMs > 50" to "inPulseAtMs > 15" and the shaker worked as I wanted it to
I seriously owe you a beer
I do not understand your code right now, but will figure it out to increase my understanding of code going forward. Once again, thank you for your time in helping me with this issue.
One thing that may be confusing is the behaviour of static variables. These are like global variables in that they retain their value between iterations of the function they are in and any initial value they are given happens only once.
The code effectively retains the start time of any pulse it is in and , while it is that pulse, continually checks if it is long enough to be considered a valid long pulse. Once the pulse is over, it resets and waits for the next pulse.
Instead of a beer you can click on the "like" button.