This machine uses a single servo to simulate the motion of a children’s toy drinking bird (to see real life version in action, click here), where normally, traveling fluid in the body of toy causes it to tip back and forth in a distinct gesture. This electric drinking bird was constructed from paper (for the body) and a hinged hook (for the neck). Connecting the hook to the bird’s body allows for the drinking motion to be more accentuated–as the servo moves the bird closer to the ground, the neck will “flop” suddenly. While the drinking motion is relatively slow and robotic, the back and forth gesture is adapted from the movement in a simple harmonic oscillator.
See below for code. If questions, feel free to contact jkwang1@andrew.cmu.edu
// "Drinking Bird" by Jen Kwang // moves a single servo to simulate the motion of a toy drinking bird. // code below is altered examples from: // https://courses.ideate.cmu.edu/16-223/f2018/text/days/day02.html #include <Servo.h> const int SERVO_PIN = 9; Servo svo; // ================================================================ // constants for Simple Harmonic Motion oscillator movement (wobbling bird) const float k = 4*M_PI*M_PI; // 1 Hz; freq = (1/2*pi) * sqrt(k/m); k = (freq*2*pi)^2 const float b = 1.5; // damping const float q_d = 90.0; // neutral spring position const float dt = 0.02; // integration time step float q = 0.0; // initial position float qd = 300.0; // initial velocity bool turning = false; // constants for bird drinking motion const float center = 90.0; // in degrees const float magnitude = 130.0; // in degrees const float period = 10.0; // in seconds, duration of cycle const float interval = 0.002; // in seconds, duration of each step // ================================================================ void setup(void){ Serial.begin(115200); svo.attach(SERVO_PIN); } // ================================================================ void loop(){ // "Drinking" motion ============================================ if (turning == false) { int cycle_steps = period / interval; for (int step = 0; step < cycle_steps; step++){ float phase = step * (M_PI/cycle_steps/1.1); float angle = center + magnitude * sin(phase); svo.write(angle); delay(500*interval); } turning = true; } // "Wobbling" motion ============================================ while (turning){ // calculate the derivatives float qdd = k * (q_d - q) - b * qd; // integrate one time step, update servo q += qd * dt; qd += qdd * dt; svo.write(q); // logic to reset the oscillator after a cycle has completed if (fabs(qd) < 0.1 && fabs(q_d - q) < 0.1) { q = 0.0; turning = false; } delay((int)(830*dt)); } }
Leave a Reply
You must be logged in to post a comment.