Skip to content

Instantly share code, notes, and snippets.

@bigjosh
Created May 8, 2018 03:17
Show Gist options
  • 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...
// http://wp.josh.com/2018/05/07/deconstructing-kitty
#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 );
pinMode(LED_PIN, OUTPUT);
}
// 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
delay(ms);
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
push(1);
}
void kick() { // A big kick to get it swinging from rest
push(50);
}
#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;
#define PLOT_INTERVAL_MS 3
void plot( int val1 ) {
if (millis() >= nextplot ) {
Serial.print(val1); // debug value
Serial.print(" "); // debug value
Serial.print(triggerflag ); // debug value
Serial.println();
nextplot = millis() + PLOT_INTERVAL_MS;
triggerflag=0;
}
}
void loop() {
// If we have not seen a swing in a while then give it a kick to get it started
if ( millis() >= nextkick ) {
kick();
resetKickTimeout();
}
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
runningTotal-=buffer[nextSlot];
// Add new value
runningTotal += val;
buffer[nextSlot] = val;
// Bump to next slot
nextSlot++;
if (nextSlot==BUFFER_COUNT) {
nextSlot=0;
}
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.
nudge();
triggerflag=peak;
resetKickTimeout();
triggered=peak;
}
}
// Display the data on the Arduino Serial Plotter
plot( smoothedvalue );
if (smoothedvalue == 0 ) { // Clear a trigger if we are back down to zero
triggered=0;
peak=0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment