User login

Powered by Drupal, an open source content management system

Theory and Practice of Tangible User Interfaces

Lab 7 - Servo Motors

Submitted by ash on Wed, 10/22/2008 - 23:04

Assignment: Servo Motor: Actuation Assignment 2

Collaborators:

Collaborators: nick


Description:

Our crawler is a four-legged creature named Walkie :)

It's a pretty simple design using two servo's and some popsicle sticks (as legs) stuck together with putty and electrical tape.

He first started out in captivity, tethered to the arduino board and featured two pot controllers; one which enabled us to adjust the range of motion for his 'legs', the other which controlled how far out of phase the two legs be.   We set the arduino controller to oscillate the legs back and forth along a SIN function and then experimented with the amplitude and phase of the legs in order to find the right gate for his walk.  Once proper values for amplitude and phase were found, we hardcoded those into arduino and made the crawler self contained.

Like any good pet, he is drawn towards his owner.  We used a light-sensor in order to detect someone's hand, which in turn, controls his forward motion.

Components Used:

  • 2 Servos
  • 1 Light Sensor
  • 220-ohm Resistor
  • Arduino board
  • Battery Pack
  • Popsicle Sticks
  • Erasers

 

Video: Tethered Walkie:

 

Video: Freerange Walkie:

Sample code (Arduino):

/*
* Crawler Control, with optional potentiometer debugging
*
*/

boolean potControl = false;
boolean photoControl = true;

int servoPin1 = 7; // Control pin for servo motor 1
int servoPin2 = 6; // Control pin for servo motor 2
int photoPin = 0; // Photocell
int potPin1 = 0; // select the input pin for the potentiometer 1
int potPin2 = 1; // select the input pin for the potentiometer 2

int pulseWidth1 = 0; // Amount to pulse the servo 1
int pulseWidth2 = 0; // Amount to pulse the servo 2
long lastPulse1 = 0; // the time in millisecs of the last pulse of servo 1
long lastPulse2 = 0; // the time in millisecs of the last pulse of servo 2
int val_1; // variable used to store data from potentiometer 1
int val_2; // variable used to store data from potentiometer 2

int refreshTime = 20; // the time in millisecs needed in between pulses
int minPulse = 500; // minimum pulse width

int servoRange = 180; // range (out of 500) of servo motion
int phaseShift = 118; // phase shift (in degrees) between the servos
int arrowSpeed = 22; // denominator of speed fraction

float servoSpeed = 1.0;
char serialInStr;
int pot_1;
int pot_2;
int photo;
int photoBase;

int goCounter;
int loopCounter = 0;
boolean debug = false;

void setup() {
pinMode(servoPin1, OUTPUT); // Set servo pin 1 as an output pin
pinMode(servoPin2, OUTPUT); // Set servo pin 2 as an output pin
pulseWidth1 = minPulse; // Set the motor position to the minimum
pulseWidth2 = minPulse; // Set the motor position to the minimum
Serial.begin(9600); // connect to the serial port
Serial.println("Two servos with two potentiometers ready");
photoBase = analogRead(photoPin);
}

void loop() {
if (potControl) {
pot_1 = analogRead(potPin1); // read the value from the sensor 1, between 0 - 1024
pot_2 = analogRead(potPin2); // read the value from the sensor 2, between 0 - 1024

// set range by pot
servoRange = (int)((float)pot_1 * 498.0 / 1024.0);
// set phase shift by pot
phaseShift = (int)((float)pot_2 * 180.0 / 1024.0);
}

if (photoControl) {
photo = analogRead(photoPin);
// stop or go based on photocell
if (((float)photo / (float)photoBase) < 0.8) {
goCounter = goCounter + 10;
} else {
if (goCounter > 0) goCounter--;
}
}

// serial monitor commands
readSerialString();
switch(serialInStr) {
case 'f':
if (arrowSpeed > 15) arrowSpeed--;
break;
case 's':
if (arrowSpeed < 30) arrowSpeed++;
break;
case 'd':
debug = debug ? false : true;
break;
}
serialInStr = ' ';
// set speed by serial input
servoSpeed = 10.0 / (float)arrowSpeed;

// slows down arduino like crazy if true
if (debug) {
Serial.print("range:");
Serial.print(servoRange);
Serial.print(" phase:");
Serial.print(phaseShift);
Serial.print(" speed:");
Serial.println(arrowSpeed);
}

// calculate servo positions
val_1 = 500 + (int)(sin((loopCounter * servoSpeed) * (PI / 180.0)) * (float)servoRange);
val_2 = 500 + (int)(sin(((loopCounter * servoSpeed) + phaseShift) * (PI / 180.0)) * (float)servoRange);

if (val_1 > 0 && val_1 <= 999 ) {
pulseWidth1 = val_1*2 + minPulse; // convert angle to microseconds
}
updateServo1(); // update servo 1 position

if (val_2 > 0 && val_2 <= 999 ) {
pulseWidth2 = val_2*2 + minPulse; // convert angle to microseconds
}
updateServo2(); // update servo 2 position

// update loop counter
if (goCounter > 0) loopCounter++;
}

void updateServo1() {
if (millis() - lastPulse1 >= refreshTime) {
digitalWrite(servoPin1, HIGH);
delayMicroseconds(pulseWidth1);
digitalWrite(servoPin1, LOW);
lastPulse1 = millis();
}
}

void updateServo2() {
if (millis() - lastPulse2 >= refreshTime) {
digitalWrite(servoPin2, HIGH);
delayMicroseconds(pulseWidth2);
digitalWrite(servoPin2, LOW);
lastPulse2 = millis();
}
}

// read a string from the serial and store it in a variable
void readSerialString () {
if(!Serial.available()) {
return;
}
serialInStr = Serial.read();
}