Skip to content

Instantly share code, notes, and snippets.

@jes
Created January 18, 2021 16:26
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 jes/e3cbc0e10c0b1041d073bbe7531c7ac4 to your computer and use it in GitHub Desktop.
Save jes/e3cbc0e10c0b1041d073bbe7531c7ac4 to your computer and use it in GitHub Desktop.
/* Cat Laser */
#include <Servo.h>
// pin configuration
const int xservopin = 2;
const int yservopin = 3;
const int speedpin = A0;
const int dwellpin = A1;
const int xrangepin = A2;
const int yrangepin = A3;
// parameter configuration
const float minspeed = 100.0; // servo usecs/sec (1000 usecs == 180 degrees)
const float maxspeed = 1200.0; // servo usecs/sec
const unsigned long mindwell = 100; // millisecs
const unsigned long maxdwell = 3000; // millisecs
const float xmin = 800, xmax = 1800; // servo usecs
const float ymin = 1000, ymax = 1800; // servo usecs
const float xmid = (xmin+xmax)/2;
const float ymid = (ymin+ymax)/2;
const float epsilon = 0.1; // for floating point comparison
float xpos = xmin;
float ypos = ymin;
float xtarget = xpos;
float ytarget = ypos;
bool dwelling = false;
unsigned long dwell_start;
Servo xservo, yservo;
void setup() {
xservo.attach(xservopin);
yservo.attach(yservopin);
Serial.begin(9600);
}
void new_target(int xrange, int yrange) {
xtarget = random(xmid-xrange/2, xmid+xrange/2);
ytarget = random(ymid-yrange/2, ymid+yrange/2);
Serial.print("Target: "); Serial.print(xtarget); Serial.print(","); Serial.println(ytarget);
dwelling = false;
}
void loop() {
static unsigned long last_tick = 0;
float speed = map(analogRead(speedpin), 0, 1023, minspeed, maxspeed);
unsigned long dwell_ms = map(analogRead(dwellpin), 0, 1023, mindwell, maxdwell);
int xrange = map(analogRead(xrangepin), 0, 1023, 0, xmax-xmin);
int yrange = map(analogRead(yrangepin), 0, 1023, 0, ymax-ymin);
// if the range has been updated such that we're now outside it, or
// we were dwelling and the dwell time is now over, pick a new target
if ( xpos > (xmid+xrange/2) || xpos < (xmid-xrange/2)
|| ypos > (ymid+yrange/2) || ypos < (ymid-yrange/2)
|| (dwelling && millis() > dwell_start+dwell_ms)) {
new_target(xrange, yrange);
}
// if we're not dwelling, but we should be, start dwelling
if (!dwelling && abs(xtarget-xpos) < epsilon && abs(ytarget-ypos) < epsilon) {
Serial.println("Dwelling...");
dwell_start = millis();
dwelling = true;
} else if (!dwelling && last_tick != 0) {
// if we're not dwelling and we know how long ago the last tick was, move the servos
unsigned long elapsed_ms = millis() - last_tick;
float stepdist = (elapsed_ms * speed / 1000);
float dx = xtarget-xpos;
float dy = ytarget-ypos;
float hypotenuse = sqrt(dx*dx + dy*dy);
if (stepdist > hypotenuse) // don't overshoot
stepdist = hypotenuse;
dx = dx * (stepdist / hypotenuse);
dy = dy * (stepdist / hypotenuse);
xpos += dx;
ypos += dy;
xservo.writeMicroseconds(xpos);
yservo.writeMicroseconds(ypos);
}
last_tick = millis();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment