Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
// This Arduino sketch drives a coil to make a Lucky Cat wave
// The coil should be connected directly to pins A0 and ground
// It uses the voltage generated by the magnet passing the coil to time its pulses
// More info at...
#define LED_PIN 13 // Show a flash on this pin everytime we pulse the coil
void setup() {
Serial.begin(9600); // setup serial
pinMode( A0 , INPUT );
// Keep track of the highest value since we last triggered
// so we can detect when the bob is moving away from the coil just
// as it switngs past bottom dead center
int peak=0;
int triggered=0;
// The values from the ADC are very noisy, so we make a crude
// averaging filter here
#define BUFFER_COUNT 25
int buffer[BUFFER_COUNT];
int nextSlot=0;
int runningTotal=0;
// Push the magnet away by energizing the coil
void push(unsigned int ms) {
pinMode( A0 , OUTPUT ); // Switch the input pin to output so we can drive it.
digitalWrite( A0 , HIGH );
digitalWrite(LED_PIN, HIGH); // Flash the LED to show the coil is on
digitalWrite( A0 , LOW );
digitalWrite(LED_PIN, LOW);
pinMode( A0 , INPUT ); // Go back to input mode so we can keep sensing the back voltage
void nudge() { // A very short and low power nudge
void kick() { // A big kick to get it swinging from rest
#define KICKCOUNT_TIMEOUT_MS (5*1000) // Give a kick if we have not seen a swing in 5 seconds to get things started
unsigned long nextkick=0;
void resetKickTimeout() {
nextkick = millis() + KICKCOUNT_TIMEOUT_MS;
// Slow down the data feed back to the Arduino plotter so it doesn't run too
// fast to see
unsigned long nextplot=0;
// Display the trigger as the 2nd variable so we can see when we give a nudge
// on the plot.
int triggerflag=0;
void plot( int val1 ) {
if (millis() >= nextplot ) {
Serial.print(val1); // debug value
Serial.print(" "); // debug value
Serial.print(triggerflag ); // debug value
nextplot = millis() + PLOT_INTERVAL_MS;
void loop() {
// If we have not seen a swing in a while then give it a kick to get it started
if ( millis() >= nextkick ) {
int val;
val = analogRead(A0); // read the input pin. We are lucky that the voltage of the coil
// falls in the range of the Arduino ADC or we would need some
// kind of scaling here
// Remove oldest value
// Add new value
runningTotal += val;
buffer[nextSlot] = val;
// Bump to next slot
if (nextSlot==BUFFER_COUNT) {
int smoothedvalue = runningTotal/BUFFER_COUNT;
if (triggered==0) {
if (smoothedvalue> peak ) {
peak = smoothedvalue;
} else if ( smoothedvalue < (peak*8)/10 ) {
// Trigger a nudge when we are at 80% of the most recent peak
// this helps prevent false triggers from noise and also
// I think gives a better force vector away rather than just up.
// Display the data on the Arduino Serial Plotter
plot( smoothedvalue );
if (smoothedvalue == 0 ) { // Clear a trigger if we are back down to zero
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.