Robotic SUSE Mascot – Part 4. Brain & Code

Please visit Part 3 – Electronics

With Arduino it is very easy to move a servo to any position between 0 and 180 degrees. You only need to connect the input signal of the servo to a PWM output of the Arduino. In fact, there is a library included to move servos.

On the other hand, a servo needs some time to move to the final position. Some servos are faster than others, but typically, 300ms, is a common value to move 180 degrees.  For that reason, you cannot program a servo to do two movements consecutively, because it will cancel the first one. Instead, you have to wait enough time to complete the first movement to send the second one. You can use a delay, but since Arduinos have only one thread of execution you can do anything than wait. This is the reason to use a timeout-driven solution (Arduino Timer library). The code is a little more complex, but all delays are removed.

An IR receiver is important to give orders to the robot. It is an easy way and cheap instead of Bluetooth, WiFi,  or radio. Everyone has a TV remote at home with a lot of buttons. Also, we don’t need to control the robot from other room. There is a library to do that easily: IRremote. You can install it from Arduino library manager

This is the source code:

To compile the code and upload to the arduino you will need the Arduino IDE

Concepts

An state is a loop doing something special. For instance, the state ‘walking’ keeps our mascot walking.

#define state_stop 0
#define state_walking 1
#define state_happy 2
#define state_moveHead 3
#define state_happy2 4
#define state_crazy 5

In a state, there might be some different steps to complete a sequence for the loop.

Structure of the code

Each state has a setup and a sequence trigger.  When the state is changed, the setup moves the robot to a neutral position, initialize the variables and launch the first trigger.

This is the  setup for walking

void walk(){
 if (state == state_walking)
 return;
 
 state = state_walking;
 state_step=0;
 walk_seq();
}

The trigger will execute the command defined in the current step, increase this step and prepare the next timeout.

This is the state sequencer for walking

void walk_seq(){
 int delayTimeout = 100;
 
 if (state != state_walking)
 return;
 
 switch (state_step){
 // LEFT step
 // move the hip and head to stabilize
 case 0:
 Head(head_left);
 Hip(hip_right);
 Tail(tail_left);
 break;

// up the left leg
 case 1:
 Leg_l(leg_l_ahead);
 break;

// down the hip
 case 2:
 Hip(hip_neutral);
 break;

case 3:
 Leg_l(leg_l_neutral);
 break;

// RIGHT step
 // move the hip and head to stabilize
 case 4:
 Head(head_right);
 Hip(hip_left);
 Tail(tail_right);
 break;

// up the left leg
 case 5:
 Leg_r(leg_r_ahead);
 break;

// down the hip
 case 6:
 Hip(hip_neutral);
 break;

case 7:
 Leg_r(leg_r_neutral);
 break;
 }

state_step = (state_step + 1) % 8;
 
 ilTimerControl.timeout(walk_seq, delayTimeout);
}

The main loop has two missions: check the timeouts and check the IR incoming messages.

void loop() {
 ilTimerControl.check();

 if (irrecv.decode(&results)) {
   if (results.decode_type == NEC) {
     switch(results.value){
       case IR_up:
       case IR_5:
       walk();
     break;
     case IR_ok:
       stop();
     break;
     case IR_1:
       happy();
     break;
     case IR_2:
       moveHead();
     break;
     case IR_3:
       happy2();
     break;
     case IR_4:
       crazy();
     break;
    }
   }
   irrecv.resume();
 }
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *