Skip to content

Instantly share code, notes, and snippets.

Created May 8, 2018 03:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bigjosh/7123a4d5fe9b4452f366d091c05ccf56 to your computer and use it in GitHub Desktop.
Save bigjosh/7123a4d5fe9b4452f366d091c05ccf56 to your computer and use it in GitHub Desktop.
// 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