Behaviour - Overview


Now it is time to make your RoboBrrd actually do something! This is designed as a basis to get you started, it will help you get going and then you can experiment and create new behaviours. First, we will add some new helper functions. Afterwards, two behaviours to dance and react to light. Let's get going!

Behaviour - Helper Functions


These are helper functions to help with some common RoboBrrd actions, like flapping its wings and opening & closing its beak. The functions can be added in the code after the loop() function. Same place as where the other helper functions were, from Programming - Step 4.

Wings

// -- WINGS -- //

void leftWave(int repeat, int d) {
  for(int i=0; i<repeat; i++) {
    lwing.write(l_upper);
    delay(d);
    lwing.write(l_lower);
    delay(d);
  }
  lwing.write(l_middle);
}

void rightWave(int repeat, int d) {
  for(int i=0; i<repeat; i++) {
    rwing.write(r_upper);
    delay(d);
    rwing.write(r_lower);
    delay(d);
  }
  rwing.write(r_middle);
}

The above are two functions for the left and right wing that make the, 'wave'. Going from the top to the bottom for a given number of repeats, and returning to the bottom. The speed of the movement from top to bottom is controlled with the variable d. d is the given amount of time that the servo will have to complete its movement before going on to the next one.

If d is really small, it is possible that the servo won't have enough time to reach its position before having to move to the next one. This will give the appearance that the wings are flapping quite quickly. If d is really large, the servo will have enough time to reach its position, and possibly wait for a little while before moving on to the next one. I usually use 100ms for d, to give the wings a medium/normal flapping speed.


Both wings

void bothWave(int repeat, int d, boolean alt) {
  for(int i=0; i<repeat; i++) {
    rwing.write(r_upper);
    if(alt) {
      lwing.write(l_lower);
    } 
    else {
      lwing.write(l_upper); 
    }
    delay(d);
    rwing.write(r_lower);
    if(alt) {
      lwing.write(l_upper);
    } 
    else {
      lwing.write(l_lower); 
    }
    delay(d);
  }
  rwing.write(r_middle);
  lwing.write(l_middle);
}

Here is a helper function to flap both wings. Similar to the ones above, it is for a specified number of repeats, with a specified time for the wing movements between positions. There is also the option to specify if the wings should be alternate each other or not. This will just make the wings either go up and down in unison, or both sides would alternate between up and down.


Beak

// -- BEAK -- //

void beakOpen(int s) {
  beak.write(b_open);
  delay(s);
}

void beakClose(int s) {
  beak.write(b_closed);
  delay(s);
}
These ones are pretty straight forward. Since opening and closing the beak is pretty straight forward, we have this helper function so that we can specify a delay time for the beak to reach that position. A smaller value of s will make the beak open/close quickly, though possibly not all the way. Slower value of s will make the beak open/close slowly, and possibly wait at that position. I usually use 50ms for s, for a medium/normal opening/closing speed.


Eyes

// -- EYES -- //
void eyes(int rval, int gval, int bval) {
  analogWrite(r, rval);
  analogWrite(g, gval);
  analogWrite(b, bval);
}
This will really depend on how you have your eyes wired. If both left and right sides are wired onto PWM pins, this function will be able to control the brightness of the red, green, and blue LEDs.


Eyes (alternate version)

// -- EYES -- //
void eyes(int rlval, int glval, int blval, int rrval, int grval, int brval) {
  
  (rlval == 1) ? digitalWrite(rl, HIGH) : digitalWrite(rl, LOW);
  (glval == 1) ? digitalWrite(gl, HIGH) : digitalWrite(gl, LOW);
  (blval == 1) ? digitalWrite(bl, HIGH) : digitalWrite(bl, LOW);
  
  (rrval == 1) ? digitalWrite(rr, HIGH) : digitalWrite(rr, LOW);
  (grval == 1) ? digitalWrite(gr, HIGH) : digitalWrite(gr, LOW);
  (brval == 1) ? digitalWrite(br, HIGH) : digitalWrite(br, LOW);
  
}
Here is an alternate example of an eyes helper function, if the RGB LEDs were connected to separate pins (making left and right independently controlled). By passing a 1 to any of the values, it will make that colour lit. By passing a 0 (or actually, anything other than a 1), will make them not lit. As a programming note, the reason why we check to see if it is a 1 or 0, instead of directly passing that to digitalWrite, is just in case HIGH and LOW change in some future version of Arduino. It's unlikely, but good programming practice.

Behaviour - Crazy


Alright, let's get going with our first behaviour! This one is pretty straight forward and slightly boring. All that it is are sequential calls to the various actions. You can think of it as a pre-rehearsed dance routine. There's no interaction between the user and RoboBrrd. RoboBrrd is just dancing and flapping its wings.

Crazy Behaviour



// -- CRAZY BEHAVIOUR -- //

void crazyBehaviour() {

  eyes(255,255,0);
  
  beak.write(b_closed+20);
  delay(100);
  beak.write(b_closed);
  delay(50);
  beak.write(b_closed+30);
  delay(150);
  beak.write(b_closed);
  delay(100);

  eyes(0,255,0);

  bothWave(3, 150, true);
  
  eyes(0,128,255);
  
  beakOpen(50);
  
  eyes(0,255,255);
  
  leftWave(3, 100);
  
  eyes(255,0,0);
  
  beak.write(b_closed+20);
  delay(100);
  beak.write(b_closed);
  delay(50);
  beak.write(b_closed+30);
  delay(150);
  beak.write(b_closed);
  delay(100);
  
  eyes(255,255,255);
  
  rightWave(3, 100);
  
  eyes(255,0,255);
  
  beakOpen(50);

  eyes(0,0,255);

  bothWave(3, 150, false);

}

This function can be pasted in below the end of the loop() function and before all the helper functions. Inside of the loop() function, you can call crazyBehaviour() to make it run. For example:


void loop() {
	crazyBehaviour();
}

// crazy behaviour function pasted here
This will make the crazy behaviour run forever.

For extra fun and tricks, customize the crazy behaviour to do a dance that you think is cool! Maybe it will blink its eyes, then flap its wings. Or maybe it will just open and close its beak repeatedly! Go for it!

Behaviour - LDRs


LDR Behaviour

Now let's make RoboBrrd do something when it senses a change in light! Since RoboBrrd has two light dependent resistors, it knows whether it is dark or bright. In this behaviour, RoboBrrd will read the values of the light sensors, see if there was a change from last time it read the values, and if there was it will flap its wing.

First up, lets add in some variables. The variables go near the top of the program (remember from Programming - Step 1). These are used to store the current and past reading, as well as a threshold.

// -- ldr behaviour -- //
int ldrLval = 0;
int ldrLval_pre = 0;
int ldrRval = 0;
int ldrRval_pre = 0;
int ldrThresh = 20;

Now for the LDR behaviour. This will set the old values to the previous reading, and read the current values of the sensor. It then prints out the current readings to Serial so that you can read it. Next, we will check the sensors to see if they went from dark to bright, or vice versa. We then update the lights and wave the wing accordingly.

// -- LDR BEHAVIOUR -- //
void ldrBehaviour() {
 
  ldrLval_pre = ldrLval;
  ldrRval_pre = ldrRval;
  
  ldrLval = analogRead(ldrL);
  ldrRval = analogRead(ldrR);

  Serial << "LDR L: " << ldrLval << " R: " << ldrRval << endl;


  // left
  if(ldrLval-ldrLval_pre > ldrThresh) { // bright! (was dark)
    eyes(255,255,255);
    leftWave(1, 50);
  } else if(ldrLval_pre-ldrLval > ldrThresh) { // dark! (was bright)
    eyes(0,0,0);
    leftWave(1, 50);
  }
  
  // right
  if(ldrRval-ldrRval_pre > ldrThresh) { // bright! (was dark)
    eyes(255,255,255);
    rightWave(1, 50);
  } else if(ldrRval_pre-ldrRval > ldrThresh) { // dark! (was bright)
    eyes(0,0,0);
    rightWave(1, 50);
  }
  
  delay(20);
  
}

The behaviour function has to be pasted after the end of the loop function and before the helper functions. Inside of loop(), call ldrBehaviour() to make it run forever. For example:

void loop() {
	ldrBehaviour();
}

// ldr behaviour pasted here

If the left and right light sensor do not correspond to the proper wing, you can change what function is called in the code above. For example, in the left block of code, if you want the right wing to wave, replace the calls to leftWave() with rightWave().

If it is being triggered too easily (or not triggered enough), you can change the value of the ldrThresh variable. It may require some tweaking to get it right.

This is a straight forward example of what robots do, they sense and react to the world. What other ways do you think RoboBrrd can do this? Be creative and code it up!

Congrats!


You are done creating the initial behaviours for RoboBrrd! Next up, let's take a look at how RoboBrrd can be further modified and what you can make with it. Let's go!

Further

"I just finished adding behaviours to RoboBrrd! Beep bloop!"
RoboBrrd Kit Building I just finished adding behaviours to RoboBrrd! Beep bloop! #RoboBrrd