Functions and random behavior

During this class we use pan/tilt-servo-setups to explore putting animated behavior in functions of our own, that we then can call randomly and thereby get a behavior that looks intelligent, and at the same time have code that is easy to overview and change.

Functions
We start with the example from the arduino webpage called Sweep which turns a servo from 0 degrees to 180 and back again. Each direction is animated by setting up a for-loop going from one number to the other and for each increment/decrement we move the servo one degree with the command myServo.write(pos) where pos contains the new angle.

We take each of those for-loops and put into a function of our own, called left() and right(), which could look something like this:

void left()
{
// goes from 0 to 180 degrees
// in steps of 1 degree 
  for(pos = 0; pos < 180; pos++)   
   {    
        // tell servo to go to 'pos' 
     myservo.write(pos);
        // waits 15ms to get there
     delay(15);       
   }
} 

Now wherever we write “left();” the full movement of the for-loop will be performed before the code moves on.

We can do similar things for the other servo called up() and down() thinking the first servo turns us around, and the other looks up or down.

Random behavior
Once we have a few functions we can add the randomness to it. By using random() we can get a random number to use to select one of our prepared movements. It can look something like this:

 int action = random(4);
  if(action == 0)
    left();
  else if (action == 1)
    right();
  else if (action == 2)
    down();
  else if(action == 3)
    up();

Notice that there are no curly brackets in the code above. There is a special case with if that says that if you’re only doing ONE thing in the if-statement, you can skip the curly brackets. It makes it easier to read, but also might make you forget to put in brackets if they NEED to be there.

By having the actual specifics of the movement defined in functions outside of loop, and in loop only have this structure of which animation to do at what time, the code becomes a lot easier to read. And if you want to tweak something, it’s a lot easier to find the part of the code that’s relevant.

Extra tidbits
We can define an ÜBER movement function that would take an angle as input and turn to it regardless of if that angle would be to the left or right of the servo:

void move(int angle)
{
  if (pos > angle) //is the servo too far to one side?
  {
    for (; pos > angle; pos--)
    {
      waist.write(pos);
      delay(50);
    }
  }
  else //or too far to the other side?
  {
    for (; pos < angle; pos++)
    {
      waist.write(pos);
      delay(50);
    }
  }
}

This example introduces two other neat things.

1) Sending a value through when calling the movement, for example “move(75);” and also

2) by not setting a start condition in the for-loop, we avoid the servo swinging crazy from an end angle to a start angle, and just goes from wherever it happens to be.

“for (; pos < angle; pos++)”

For our robot-head to not seem like it’s a hyperactive psychopath we might want to make one function just to pause from time to time as well.

void pause(int duration)
{
    delay(duration);
}

A previous student played around with trigonometry to move the head in a circle and noticed that if you use this simple calculation, you get a nice gradual start and end of movement.

for (int i = 0; i <= 360; i++) {
    float x = 20 * (cos ((PI * i)/180)) + 90;
    float y = 20 * (sin ((PI * i)/180)) + 60;
    servoX.write(x);
    servoY.write(y);
    Serial.print(x);
    Serial.print(",");
    Serial.println(y);
    delay(5);
  }