[Please excuse my English]
I really like the popular set-up of 2 servos arduino insects on youtube. When I looked at it, I always remember what BEAM robotic guys did long before that set-up became favorite. These people who are analog robot fanatics did better on the gait due to better angle between the two motors (microcore /bicore walker, etc).
However, in my opinion, none of those mentioned before look more alive than VBug1.5 (also known as Walkman) created by the founder of beam robotic, Mark Tilden. It’s using 5 motors, therefore it has more maneuverability.
Making a simple BEAM robot is not difficult, but building something as complicated as VBug1.5 could be distressing for an electronic novice like me. So, when I decided to make something like Tilden’s bugs, I had to settled with arduino platform, the easiest choice for non-engineers (or in my case, embarrassingly, an engineer wannabe).
As a result, I made Walter, a 4 legged arduino robot with 5 servos. You may wonder, if I wanted to make a look-alive bug robot then why I didn’t go with 8 or 12 servos instead. Well, I was thinking something simplest I can do to get most maneuverability I can have. I’m talking about using a lot of glue instead of making frames.
BEHAVIORS
Like many other arduino robots, Walter can avoid obstacles using HC-SR04 ultrasonic sensors. To add character as a bug, Walter also a photovore, means he is attracted to light. Photodiodes are used to detect light. There are random values generated in the arduino sketch to make Walter decides when he wants to stop to rest, and also to randomly changes his gait speed (3 speeds).When I started, I intended to have tact buttons under each of Walter’s feet so he would have a surface sensors. But the battery (a portable power bank for smartphone) costs the servos to much weight. I know tact buttons weigh almost nothing to worry to add weight, but ironically the weight of the robot is not enough to able to pressed the upside-downed buttons.
I planned to make Walter version 2 with bigger servos and then included these buttons as surface sensors.
BILL OF MATERIALS
- Controller: Arduino Pro Mini (5v, 16MHz)
- Sensors:
- 3x HC-SR04 Ultrasonic Sensors
- 4x Photodiodes (5mm)
- 4x 100kΩ resistors
- Actuators: 5x MG90S Metal Geared Micro Servos
- Power: 5200 mAH portable power bank for smartphone (2 channel output, 1 A and 2.1 A)
- Some wires and female header connectors
- 2x USB A connectors
- Toggle switch
- Coat hanger or any thin metal rod you can bend to make legs
- A lot of glue (hot glue gun, super glue, and plastic steel / epoxy glue)
CIRCUIT
Although they work fine for me, I think I need more experimenting with smaller values for the resistors.
ARDUINO CODES
I wrote this codes myself. That's a guarantee that this codes are a total noob work. Feel free to improve it as you see fit.WARNING: Some values need to calibrate before uploading the codes.
Read the top comments first to find which values they are. Calibration needed to find center values of each servos.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
WALTER - THE 4 LEGGED PHOTOVORE | |
This Arduino sketch is my attemp to build a 5 servo quadruped (4 legged) robot named "WALTER". | |
In order to use this sketch, you might need to change some values for your convenient or to adjust to your own hardware set up. | |
Find (Ctrl + F) these marks to easily search which values might need to be changed: | |
- **** : These marks mean they are servos' center potition and have to calibrated (your robot legs' potitioning when it's idle). | |
- *** : These marks mean arduino pins asignment (sensors & servos connection to arduino). Refer to this when you build the robot. | |
- ** : These marks mean that the values optionally can be changed according to your taste (legs' step width, how much to turn when sensing light/obstacle, etc). Just leave it as is if you don't know what you were doing. | |
You can use this sketch at your own risk.. and, it's provided as is and.. uh.. | |
What're those all about copyrights stuff people use to write at published source code?? | |
The point is I don't want to be held responsible if something bad happened when you were using this codes. | |
Have fun! | |
Yohanes Martedi - 2015 | |
*/ | |
#include <Servo.h> | |
// ****Calibrate servos' center angle (in microseconds because we'll use "xx.writeMicroseconds();" command). Start with 1500. | |
const int ANGLE_mid_Shaft = 1520; | |
const int ANGLE_mid_FLeft = 1550; | |
const int ANGLE_mid_FRight = 1570; | |
const int ANGLE_mid_BLeft = 1450; | |
const int ANGLE_mid_BRight = 1450; | |
const int ANGLE_sweep = 250; // **Set this value (in microseconds) to determine how wide the servos will sweep (legs' step width). Bigger value means wider sweep angle. | |
const int ANGLE_res = 10; // **Set the servo movement resolution (in microseconds) at least at minimum servo's default dead band width (highest resolution) or more (less resolution). Example: SG90 servo dead band width is 10 microseconds. | |
int sweepSPEED; // variable to determine how fast the servos will sweep. | |
int sweepSPEED_Rand[3] = {4, 6, 8}; // **Servo speed (gait speed) will change randomly in 3 modes. Set the speed (in miliseconds) for each mode. Smaller value means faster. | |
const int ANGLE_turnMAX = ANGLE_sweep * 1.5; // **Set this value to determine how much maximum the bot will turn toward light. Bigger value means bigger turn. | |
const int ANGLE_turnNARROW = ANGLE_sweep * 0.25; // **Set this value to determine how much maximum the bot will turn avoiding objects at its sides in narrow space. Bigger value means bigger turn. | |
const int SONAR_sum = 3; // Amount of sonars used. | |
const int PHOTO_sum = 4; // Amount of photodiodes used. | |
int PIN_trig[SONAR_sum] = {13, 11, 8}; // ***Set arduino pins connected to ultrasonic sensors' trigger pins; {front, left, right}. | |
int PIN_ec[SONAR_sum] = {12, 10, 7}; // ***Set arduino pins connected to ultrasonic sensors' echo pins; {front, left, right}. | |
int PIN_PHOTO[PHOTO_sum] = {2, 3, 1, 0}; // ***Set arduino analog input pins connected to photodiodes; {front left, front right, back left, back right}. | |
const int distRotate = 25; // **Configure minimum distance (in cm) between the robot and obstacle before the robot avoid it by rotating. | |
const int distRetreat = 10; // **Configure minimum distance (in cm) between the robot and obstacle before the robot avoid it by retreating. | |
const int distTurn = 20; // **Configure minimum distance (in cm) between the robot and obstacle before the robot avoid it by turning. | |
const int counter_gait_max = 8; // **Configure how many steps the robot will take to avoid obstacle (when rotating or retreating). | |
// **Configure how long the bot rest & run (in milliseconds). | |
const int RUN_time = 25000; | |
const int REST_time = 3000; | |
// ID's for sonars: | |
int SONAR_id; | |
const int FRONT = 0; | |
const int LEFT = 1; | |
const int RIGHT = 2; | |
// ID's for photodiodes: | |
const int FRONT_LEFT = 0; | |
const int FRONT_RIGHT = 1; | |
const int BACK_LEFT = 2; | |
const int BACK_RIGHT = 3; | |
// Variables for photodiodes reading: | |
int PHOTO_Front_Left; | |
int PHOTO_Front_Right; | |
int PHOTO_Back_Left; | |
int PHOTO_Back_Right; | |
const int SONAR_TrigSig = 10; // Duration (in µS) of trigger signal the sensors needed to produce ultrasonic sound (already specified by the products, don't change this value). | |
const unsigned long SONAR_MaxEc = 50000; // Maximum duration (in µS) of the echo signal given by the sensors (already specified by the products, don't change this value). | |
const float SOUND_speed = 0.034; // The speed of sound on air in µS/cm (already specified by sciene, avatar Aang is needed to do air bending if this value is wanted to be changed). | |
int distance[SONAR_sum]; // Results of the calculation of distance. | |
// Ddeclaration of servos: | |
Servo SERVO_shaft; | |
Servo SERVO_front_left; | |
Servo SERVO_front_right; | |
Servo SERVO_back_left; | |
Servo SERVO_back_right; | |
// Variables for each servos' angles: | |
int ANGLE_shaft = ANGLE_mid_Shaft; | |
int ANGLE_front_left = ANGLE_mid_FLeft; | |
int ANGLE_front_right = ANGLE_mid_FRight; | |
int ANGLE_back_left = ANGLE_mid_BLeft; | |
int ANGLE_back_right = ANGLE_mid_BRight; | |
// Angle manipulation for middle servo (shaft). | |
const int ANGLE_max_Shaft = ANGLE_mid_Shaft + ANGLE_sweep; | |
const int ANGLE_min_Shaft = ANGLE_mid_Shaft - ANGLE_sweep; | |
int ANGLE_sweep_val; | |
// Variables for recording current angles of each servos: | |
int ANGLE_shaft_record; | |
int ANGLE_front_left_record; | |
int ANGLE_front_right_record; | |
int ANGLE_back_left_record; | |
int ANGLE_back_right_record; | |
// Variables for servos angles correction according to light detection: | |
int LIGHT_left; | |
int LIGHT_right; | |
// Variables for servos angles correction according to sonar detection: | |
int SONAR_left; | |
int SONAR_right; | |
// That things such as flags, counters, records that I'm always not sure how to explain. :( | |
int ANGLE_prev; | |
int flag_shaft_reverse; | |
int flag_transition_rotate; | |
int flag_transition_start = 1; | |
int flag_rest = 0; | |
int flag_RUN_time = 0; | |
int rotate_random; | |
int counter_gait; | |
void setup() { | |
// Serial.begin(9600); // Serial.. you know, checking & debugging.. | |
SERVO_shaft.attach(2); // ***Set up horizontal (shaft) servo's signal pin on arduino. | |
SERVO_front_left.attach(4); // ***Set up front-left servo's signal pin on arduino. | |
SERVO_front_right.attach(3); // ***Set up front-right servo's signal pin on arduino. | |
SERVO_back_left.attach(6); // ***Set up back-left servo's signal pin on arduino. | |
SERVO_back_right.attach(5); // ***Set up back-right servo's signal pin on arduino. | |
// Get the servos ready at their middle angles. | |
SERVO_shaft.writeMicroseconds(ANGLE_mid_Shaft); | |
SERVO_front_left.writeMicroseconds(ANGLE_mid_FLeft); | |
SERVO_front_right.writeMicroseconds(ANGLE_mid_FRight); | |
SERVO_back_left.writeMicroseconds(ANGLE_mid_BLeft); | |
SERVO_back_right.writeMicroseconds(ANGLE_mid_BRight); | |
// Setting pins for sonars, both pinMode and value. | |
for(SONAR_id = 0; SONAR_id < SONAR_sum; SONAR_id++) { | |
pinMode(PIN_trig[SONAR_id],OUTPUT); | |
pinMode(PIN_ec[SONAR_id],INPUT); | |
digitalWrite(PIN_trig[SONAR_id], LOW); | |
} | |
randomSeed(analogRead(5)); // Using analog pin 5 to generate random values to be used later. | |
SONAR_READ_ALL(); // Initiate first sonar reading before doing anything, | |
SONAR_READ_ALL(); // and actually I forget why I have to call it twice for the first time. But believe me, it's needed. | |
START(); // This function make sure which legs are lifted randomly at the first step. | |
delay(3000); // **dum.. daa.. dum.. | |
} | |
void loop() { | |
int state = random(0,2); | |
if(state == 0) { | |
REST(); | |
} | |
else { | |
int randomSPEED = random(0,3); | |
sweepSPEED = sweepSPEED_Rand[randomSPEED]; | |
RUN(); | |
flag_rest = 0; | |
} | |
} | |
void REST() { | |
if(flag_rest == 0) { | |
TRANSITION_GAIT(); | |
flag_rest = 1; | |
} | |
delay(REST_time); | |
} | |
void RUN() { | |
unsigned long TIMER_state = millis(); | |
while((millis() - TIMER_state) <= RUN_time) { | |
if(distance[FRONT] > distRotate) { | |
flag_RUN_time = 0; | |
while(flag_RUN_time == 0) { | |
FORWARD(); | |
} | |
} | |
while(distance[FRONT] > distRetreat && distance[FRONT] <= distRotate) { | |
while(distance[LEFT] > distance[RIGHT]) { | |
ROTATE_LEFT_AVOID(); | |
break; | |
} | |
while(distance[LEFT] < distance[RIGHT]) { | |
ROTATE_RIGHT_AVOID(); | |
break; | |
} | |
while(distance[LEFT] == distance[RIGHT]) { | |
ROTATE_RANDOM_AVOID(); | |
break; | |
} | |
} | |
while(distance[FRONT] <= distRetreat) { | |
RETREAT_AVOID(); | |
} | |
} | |
} | |
/*________________________________________________________________________________________ | |
########################################## GAIT ########################################*/ | |
/*=================================== SHAFT MOVEMENT ===================================*/ | |
void SHAFT() { | |
unsigned long TIMER_servo = millis(); | |
while((millis() - TIMER_servo) <= sweepSPEED) { | |
while(ANGLE_shaft == ANGLE_mid_Shaft) { | |
counter_gait++; | |
SONAR_READ_ALL(); | |
LIGHT_COMPARE_EXECUTE(); | |
SIDE_AVOID(); | |
flag_RUN_time = 1; | |
break; | |
} | |
} | |
if(ANGLE_prev < ANGLE_shaft && ANGLE_shaft < ANGLE_max_Shaft) { | |
ANGLE_prev = ANGLE_shaft; | |
ANGLE_shaft += ANGLE_res; | |
} | |
else if(ANGLE_shaft >= ANGLE_max_Shaft) { | |
ANGLE_prev = ANGLE_shaft; | |
ANGLE_shaft -= ANGLE_res; | |
} | |
else if(ANGLE_prev > ANGLE_shaft && ANGLE_shaft > ANGLE_min_Shaft) { | |
ANGLE_prev = ANGLE_shaft; | |
ANGLE_shaft -= ANGLE_res; | |
} | |
else if(ANGLE_shaft <= ANGLE_min_Shaft) { | |
ANGLE_prev = ANGLE_shaft; | |
ANGLE_shaft += ANGLE_res; | |
} | |
SERVO_shaft.writeMicroseconds(ANGLE_shaft); | |
} | |
void SHAFT_REVERSE() { | |
if(ANGLE_prev < ANGLE_shaft) { | |
ANGLE_prev = ANGLE_shaft + 1; | |
} | |
else if(ANGLE_prev > ANGLE_shaft) { | |
ANGLE_prev = ANGLE_shaft - 1; | |
} | |
} | |
/*================================ END OF SHAFT MOVEMENT ================================*/ | |
/*===================================== TRANSITION =====================================*/ | |
void TRANSITION_GAIT() { | |
ANGLE_front_left_record = ANGLE_front_left; | |
ANGLE_front_right_record = ANGLE_front_right; | |
ANGLE_back_left_record = ANGLE_back_left; | |
ANGLE_back_right_record = ANGLE_back_right; | |
ANGLE_shaft_record = ANGLE_shaft; | |
int flag = HIGH; | |
int counter = 0; | |
while(flag == HIGH) { | |
SHAFT(); | |
LIGHT_left = 0; | |
LIGHT_right = 0; | |
counter++; | |
ANGLE_front_left = map(counter, 1, ((ANGLE_sweep * 2) / ANGLE_res), ANGLE_front_left_record, ANGLE_mid_FLeft); | |
ANGLE_front_right = map(counter, 1, ((ANGLE_sweep * 2) / ANGLE_res), ANGLE_front_right_record, ANGLE_mid_FRight); | |
ANGLE_back_left = map(counter, 1, ((ANGLE_sweep * 2) / ANGLE_res), ANGLE_back_left_record, ANGLE_mid_BLeft); | |
ANGLE_back_right = map(counter, 1, ((ANGLE_sweep * 2) / ANGLE_res), ANGLE_back_right_record, ANGLE_mid_BRight); | |
SERVO_shaft.writeMicroseconds(ANGLE_shaft); | |
SERVO_front_left.writeMicroseconds(ANGLE_front_left); | |
SERVO_front_right.writeMicroseconds(ANGLE_front_right); | |
SERVO_back_left.writeMicroseconds(ANGLE_back_left); | |
SERVO_back_right.writeMicroseconds(ANGLE_back_right); | |
if(counter == ((ANGLE_sweep * 2) / ANGLE_res)) { | |
flag = LOW; | |
START(); | |
flag_transition_rotate = 0; | |
} | |
} | |
} | |
void TRANSITION_START() { | |
if(ANGLE_shaft == ANGLE_mid_Shaft || (ANGLE_shaft > ANGLE_mid_Shaft && ANGLE_shaft > ANGLE_prev) || (ANGLE_shaft < ANGLE_mid_Shaft && ANGLE_shaft < ANGLE_prev)) { | |
ANGLE_sweep_val = 0; | |
} | |
else { | |
flag_transition_start = 0; | |
} | |
} | |
void START() { | |
ANGLE_prev = random((ANGLE_shaft), (ANGLE_shaft + 2)); | |
if(ANGLE_prev == ANGLE_shaft) { | |
ANGLE_prev -= 1; | |
} | |
flag_transition_start = 1; | |
} | |
int ROTATE_RANDOM() { | |
return random(0, 2); | |
} | |
/*================================== END OF TRANSITION ==================================*/ | |
/*======================================== WALK ========================================*/ | |
void FORWARD() { | |
while(flag_transition_rotate == 2) { | |
TRANSITION_GAIT(); | |
} | |
flag_transition_rotate = 1; | |
while(flag_shaft_reverse == 0) { | |
SHAFT_REVERSE(); | |
break; | |
} | |
flag_shaft_reverse = 1; | |
while(flag_transition_start == 1) { | |
SHAFT(); | |
TRANSITION_START(); | |
WALK(); | |
} | |
SHAFT(); | |
ANGLE_sweep_val = ANGLE_sweep; | |
WALK(); | |
} | |
void RETREAT() { | |
while(flag_transition_rotate == 2) { | |
TRANSITION_GAIT(); | |
} | |
flag_transition_rotate = 1; | |
while(flag_shaft_reverse == 1) { | |
SHAFT_REVERSE(); | |
break; | |
} | |
flag_shaft_reverse = 0; | |
while(flag_transition_start == 1) { | |
SHAFT(); | |
LIGHT_left = 0; | |
LIGHT_right = 0; | |
TRANSITION_START(); | |
WALK(); | |
} | |
SHAFT(); | |
LIGHT_left = 0; | |
LIGHT_right = 0; | |
ANGLE_sweep_val = (ANGLE_sweep * -1); | |
WALK(); | |
} | |
void WALK() { | |
if(ANGLE_shaft >= ANGLE_mid_Shaft && ANGLE_prev < ANGLE_shaft) { | |
ANGLE_front_left = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_max_Shaft, ((ANGLE_mid_FLeft - ANGLE_sweep_val) + LIGHT_left + SONAR_left), ANGLE_mid_FLeft); | |
ANGLE_front_right = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_max_Shaft, ((ANGLE_mid_FRight - ANGLE_sweep_val) - LIGHT_right - SONAR_right), ANGLE_mid_FRight); | |
ANGLE_back_left = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_max_Shaft, ((ANGLE_mid_BLeft + ANGLE_sweep_val) - LIGHT_left - SONAR_left), ANGLE_mid_BLeft); | |
ANGLE_back_right = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_max_Shaft, ((ANGLE_mid_BRight + ANGLE_sweep_val) + LIGHT_right + SONAR_right), ANGLE_mid_BRight); | |
} | |
else if(ANGLE_shaft >= ANGLE_mid_Shaft && ANGLE_prev > ANGLE_shaft) { | |
ANGLE_front_left = map(ANGLE_shaft, ANGLE_max_Shaft, ANGLE_mid_Shaft, ANGLE_mid_FLeft, ((ANGLE_mid_FLeft + ANGLE_sweep_val) - LIGHT_left - SONAR_left)); | |
ANGLE_front_right = map(ANGLE_shaft, ANGLE_max_Shaft, ANGLE_mid_Shaft, ANGLE_mid_FRight, ((ANGLE_mid_FRight + ANGLE_sweep_val) + LIGHT_right + SONAR_right)); | |
ANGLE_back_left = map(ANGLE_shaft, ANGLE_max_Shaft, ANGLE_mid_Shaft, ANGLE_mid_BLeft, ((ANGLE_mid_BLeft - ANGLE_sweep_val) + LIGHT_left + SONAR_left)); | |
ANGLE_back_right = map(ANGLE_shaft, ANGLE_max_Shaft, ANGLE_mid_Shaft, ANGLE_mid_BRight, ((ANGLE_mid_BRight - ANGLE_sweep_val) - LIGHT_right - SONAR_right)); | |
} | |
else if(ANGLE_shaft < ANGLE_mid_Shaft && ANGLE_prev > ANGLE_shaft) { | |
ANGLE_front_left = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_min_Shaft, ((ANGLE_mid_FLeft + ANGLE_sweep_val) - LIGHT_left - SONAR_left), ANGLE_mid_FLeft); | |
ANGLE_front_right = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_min_Shaft, ((ANGLE_mid_FRight + ANGLE_sweep_val) + LIGHT_right + SONAR_right), ANGLE_mid_FRight); | |
ANGLE_back_left = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_min_Shaft, ((ANGLE_mid_BLeft - ANGLE_sweep_val) + LIGHT_left + SONAR_left), ANGLE_mid_BLeft); | |
ANGLE_back_right = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_min_Shaft, ((ANGLE_mid_BRight - ANGLE_sweep_val) - LIGHT_right - SONAR_right), ANGLE_mid_BRight); | |
} | |
else if(ANGLE_shaft < ANGLE_mid_Shaft && ANGLE_prev < ANGLE_shaft) { | |
ANGLE_front_left = map(ANGLE_shaft, ANGLE_min_Shaft, ANGLE_mid_Shaft, ANGLE_mid_FLeft, ((ANGLE_mid_FLeft - ANGLE_sweep_val) + LIGHT_left + SONAR_left)); | |
ANGLE_front_right = map(ANGLE_shaft, ANGLE_min_Shaft, ANGLE_mid_Shaft, ANGLE_mid_FRight, ((ANGLE_mid_FRight - ANGLE_sweep_val) - LIGHT_right - SONAR_right)); | |
ANGLE_back_left = map(ANGLE_shaft, ANGLE_min_Shaft, ANGLE_mid_Shaft, ANGLE_mid_BLeft, ((ANGLE_mid_BLeft + ANGLE_sweep_val) - LIGHT_left - SONAR_left)); | |
ANGLE_back_right = map(ANGLE_shaft, ANGLE_min_Shaft, ANGLE_mid_Shaft, ANGLE_mid_BRight, ((ANGLE_mid_BRight + ANGLE_sweep_val) + LIGHT_right + SONAR_right)); | |
} | |
SERVO_front_left.writeMicroseconds(ANGLE_front_left); | |
SERVO_front_right.writeMicroseconds(ANGLE_front_right); | |
SERVO_back_left.writeMicroseconds(ANGLE_back_left); | |
SERVO_back_right.writeMicroseconds(ANGLE_back_right); | |
} | |
/*===================================== END OF WALK =====================================*/ | |
/*======================================= ROTATE =======================================*/ | |
void ROTATE_LEFT() { | |
while(flag_transition_rotate == 1) { | |
TRANSITION_GAIT(); | |
} | |
flag_transition_rotate = 2; | |
while(flag_shaft_reverse == 2) { | |
SHAFT_REVERSE(); | |
break; | |
} | |
flag_shaft_reverse = 3; | |
while(flag_transition_start == 1) { | |
SHAFT(); | |
LIGHT_left = 0; | |
LIGHT_right = 0; | |
TRANSITION_START(); | |
ROTATE(); | |
} | |
SHAFT(); | |
LIGHT_left = 0; | |
LIGHT_right = 0; | |
ANGLE_sweep_val = ANGLE_sweep; | |
ROTATE(); | |
} | |
void ROTATE_RIGHT() { | |
while(flag_transition_rotate == 1) { | |
TRANSITION_GAIT(); | |
} | |
flag_transition_rotate = 2; | |
while(flag_shaft_reverse == 3) { | |
SHAFT_REVERSE(); | |
break; | |
} | |
flag_shaft_reverse = 2; | |
while(flag_transition_start == 1) { | |
SHAFT(); | |
LIGHT_left = 0; | |
LIGHT_right = 0; | |
TRANSITION_START(); | |
ROTATE(); | |
} | |
SHAFT(); | |
LIGHT_left = 0; | |
LIGHT_right = 0; | |
ANGLE_sweep_val = (ANGLE_sweep * -1); | |
ROTATE(); | |
} | |
void ROTATE() { | |
if(ANGLE_shaft >= ANGLE_mid_Shaft && ANGLE_prev < ANGLE_shaft) { | |
ANGLE_front_left = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_max_Shaft, (ANGLE_mid_FLeft + ANGLE_sweep_val), ANGLE_mid_FLeft); | |
ANGLE_front_right = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_max_Shaft, (ANGLE_mid_FRight - ANGLE_sweep_val), ANGLE_mid_FRight); | |
ANGLE_back_left = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_max_Shaft, (ANGLE_mid_BLeft - ANGLE_sweep_val), ANGLE_mid_BLeft); | |
ANGLE_back_right = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_max_Shaft, (ANGLE_mid_BRight + ANGLE_sweep_val), ANGLE_mid_BRight); | |
} | |
else if(ANGLE_shaft >= ANGLE_mid_Shaft && ANGLE_prev > ANGLE_shaft) { | |
ANGLE_front_left = map(ANGLE_shaft, ANGLE_max_Shaft, ANGLE_mid_Shaft, ANGLE_mid_FLeft, (ANGLE_mid_FLeft - ANGLE_sweep_val)); | |
ANGLE_front_right = map(ANGLE_shaft, ANGLE_max_Shaft, ANGLE_mid_Shaft, ANGLE_mid_FRight, (ANGLE_mid_FRight + ANGLE_sweep_val)); | |
ANGLE_back_left = map(ANGLE_shaft, ANGLE_max_Shaft, ANGLE_mid_Shaft, ANGLE_mid_BLeft, (ANGLE_mid_BLeft + ANGLE_sweep_val)); | |
ANGLE_back_right = map(ANGLE_shaft, ANGLE_max_Shaft, ANGLE_mid_Shaft, ANGLE_mid_BRight, (ANGLE_mid_BRight - ANGLE_sweep_val)); | |
} | |
else if(ANGLE_shaft < ANGLE_mid_Shaft && ANGLE_prev > ANGLE_shaft) { | |
ANGLE_front_left = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_min_Shaft, (ANGLE_mid_FLeft - ANGLE_sweep_val), ANGLE_mid_FLeft); | |
ANGLE_front_right = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_min_Shaft, (ANGLE_mid_FRight + ANGLE_sweep_val), ANGLE_mid_FRight); | |
ANGLE_back_left = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_min_Shaft, (ANGLE_mid_BLeft + ANGLE_sweep_val), ANGLE_mid_BLeft); | |
ANGLE_back_right = map(ANGLE_shaft, ANGLE_mid_Shaft, ANGLE_min_Shaft, (ANGLE_mid_BRight - ANGLE_sweep_val), ANGLE_mid_BRight); | |
} | |
else if(ANGLE_shaft < ANGLE_mid_Shaft && ANGLE_prev < ANGLE_shaft) { | |
ANGLE_front_left = map(ANGLE_shaft, ANGLE_min_Shaft, ANGLE_mid_Shaft, ANGLE_mid_FLeft, (ANGLE_mid_FLeft + ANGLE_sweep_val)); | |
ANGLE_front_right = map(ANGLE_shaft, ANGLE_min_Shaft, ANGLE_mid_Shaft, ANGLE_mid_FRight, (ANGLE_mid_FRight - ANGLE_sweep_val)); | |
ANGLE_back_left = map(ANGLE_shaft, ANGLE_min_Shaft, ANGLE_mid_Shaft, ANGLE_mid_BLeft, (ANGLE_mid_BLeft - ANGLE_sweep_val)); | |
ANGLE_back_right = map(ANGLE_shaft, ANGLE_min_Shaft, ANGLE_mid_Shaft, ANGLE_mid_BRight, (ANGLE_mid_BRight + ANGLE_sweep_val)); | |
} | |
SERVO_front_left.writeMicroseconds(ANGLE_front_left); | |
SERVO_front_right.writeMicroseconds(ANGLE_front_right); | |
SERVO_back_left.writeMicroseconds(ANGLE_back_left); | |
SERVO_back_right.writeMicroseconds(ANGLE_back_right); | |
} | |
/*==================================== END OF ROTATE ====================================*/ | |
/*_________________________________________________________________________________________ | |
/*##################################### END OF GAIT #####################################*/ | |
/*================================= ULTRASONIC READING =================================*/ | |
void SONAR_READ_ALL() { | |
for(SONAR_id = 0; SONAR_id < SONAR_sum; SONAR_id++) { | |
distance[SONAR_id] = int (SONAR_READ(SONAR_id)); | |
} | |
} | |
float SONAR_READ(int index) { | |
float SONAR_distance; | |
digitalWrite(PIN_trig[index], HIGH); | |
delayMicroseconds(SONAR_TrigSig); | |
digitalWrite(PIN_trig[index], LOW); | |
float SONAR_EcInterval = float (pulseIn(PIN_ec[index], HIGH, SONAR_MaxEc)); | |
while(SONAR_EcInterval > 0.0) { | |
SONAR_distance = SONAR_EcInterval * (SOUND_speed / 2.0); | |
break; | |
} | |
while(SONAR_EcInterval == 0.0) { | |
SONAR_distance = 501.0; | |
break; | |
} | |
return SONAR_distance; | |
} | |
/*============================= END OF ULTRASONIC READING =============================*/ | |
/*==================================== LIGHT DETECT ====================================*/ | |
void LIGHT_COMPARE_EXECUTE() { | |
//PHOTO_FLeft_RAW = analogRead(PIN_PHOTO[FRONT_LEFT]); | |
//PHOTO_FRight_RAW = analogRead(PIN_PHOTO[FRONT_RIGHT]); | |
PHOTO_Front_Left = analogRead(PIN_PHOTO[FRONT_LEFT]); | |
PHOTO_Front_Right = analogRead(PIN_PHOTO[FRONT_RIGHT]); | |
PHOTO_Back_Left = analogRead(PIN_PHOTO[BACK_LEFT]); | |
PHOTO_Back_Right = analogRead(PIN_PHOTO[BACK_RIGHT]); | |
if((PHOTO_Front_Left + PHOTO_Front_Right) >= (PHOTO_Back_Left + PHOTO_Back_Right)) { | |
int LIGHT_Sensitivity = 50; | |
if(LIGHT_COMPARE() > LIGHT_Sensitivity) { | |
LIGHT_left = LIGHT_COMPARE(); | |
LIGHT_right = 0; | |
} | |
else if(LIGHT_COMPARE() < -LIGHT_Sensitivity) { | |
LIGHT_left = 0; | |
LIGHT_right = LIGHT_COMPARE(); | |
} | |
else { | |
LIGHT_left = 0; | |
LIGHT_right = 0; | |
} | |
} | |
else { | |
if(PHOTO_Back_Left > PHOTO_Back_Right) { | |
LIGHT_right = 0; | |
LIGHT_left = ANGLE_turnMAX; | |
} | |
else if(PHOTO_Back_Left < PHOTO_Back_Right) { | |
LIGHT_right = -ANGLE_turnMAX; | |
LIGHT_left = 0; | |
} | |
else { | |
int RANDOM_back_light = random(0,2); | |
if(RANDOM_back_light == 0) { | |
LIGHT_right = 0; | |
LIGHT_left = ANGLE_turnMAX; | |
} | |
else if(RANDOM_back_light == 1) { | |
LIGHT_right = -ANGLE_turnMAX; | |
LIGHT_left = 0; | |
} | |
} | |
} | |
} | |
int LIGHT_COMPARE() { | |
int LIGHT_rate; | |
if(PHOTO_Front_Left > PHOTO_Front_Right) { | |
LIGHT_rate = PHOTO_Front_Left; | |
} | |
else if(PHOTO_Front_Right > PHOTO_Front_Left) { | |
LIGHT_rate = PHOTO_Front_Right; | |
} | |
else { | |
// choose to use one and comments the other of these variables bellow | |
// LIGHT_rate = PHOTO_Front_Left; | |
LIGHT_rate = PHOTO_Front_Right; | |
} | |
int LIGHT_compareRAW = PHOTO_Front_Left - PHOTO_Front_Right; | |
LIGHT_compareRAW = map(LIGHT_compareRAW, -LIGHT_rate, LIGHT_rate, -ANGLE_turnMAX, ANGLE_turnMAX);; | |
return LIGHT_compareRAW; | |
} | |
/*================================= END OF LIGHT DETECT =================================*/ | |
/*====================================== BEHAVIOUR ======================================*/ | |
void RETREAT_AVOID() { | |
counter_gait = 0; | |
while(counter_gait <= counter_gait_max) { | |
RETREAT(); | |
} | |
} | |
void ROTATE_LEFT_AVOID() { | |
counter_gait = 0; | |
rotate_random = 2; | |
while(counter_gait <= counter_gait_max) { | |
ROTATE_LEFT(); | |
} | |
} | |
void ROTATE_RIGHT_AVOID() { | |
counter_gait = 0; | |
rotate_random = 2; | |
while(counter_gait <= counter_gait_max) { | |
ROTATE_RIGHT(); | |
} | |
} | |
void ROTATE_RANDOM_AVOID() { | |
rotate_random = ROTATE_RANDOM(); | |
while(rotate_random == 0) { | |
ROTATE_LEFT_AVOID(); | |
} | |
while(rotate_random == 1) { | |
ROTATE_RIGHT_AVOID(); | |
} | |
} | |
void SIDE_AVOID() { | |
if(distance[LEFT] <= distTurn && distance[RIGHT] > distTurn) { | |
LIGHT_left = 0; | |
LIGHT_right = 0; | |
SONAR_left = 0; | |
SONAR_right = -(map(distance[LEFT], 0, distTurn, ANGLE_turnMAX, 0)); | |
} | |
else if(distance[RIGHT] <= distTurn && distance[LEFT] > distTurn) { | |
LIGHT_left = 0; | |
LIGHT_right = 0; | |
SONAR_right = 0; | |
SONAR_left = map(distance[RIGHT], 0, distTurn, ANGLE_turnMAX, 0); | |
} | |
else if(distance[LEFT] <= distTurn && distance[RIGHT] <= distTurn) { | |
LIGHT_left = 0; | |
LIGHT_right = 0; | |
if(distance[LEFT] < distance[RIGHT]) { | |
SONAR_left = 0; | |
SONAR_right = -(map(distance[LEFT], 0, distTurn, ANGLE_turnNARROW, 0)); | |
} | |
else if(distance[RIGHT] < distance[LEFT]) { | |
SONAR_right = 0; | |
SONAR_left = map(distance[RIGHT], 0, distTurn, ANGLE_turnNARROW, 0); | |
} | |
} | |
else { | |
SONAR_right = 0; | |
SONAR_left = 0; | |
} | |
} | |
/*================================== END OF BEHAVIOUR ==================================*/ |
ASSEMBLY
Glues are essential for this project. I used 3 kind of glues; hot glue gun, super glue, and plastic steel / epoxy glue.At first I used white polymorph plastic, but then I switched using a lot of plastic steel epoxy. They're easier to use.

Many of these photos taken before I switched to plastic steel. Notice the amount of glues used. I meant it when I wrote glues are essential before.

The shaft is made from servo horn and spacer glued together.

I found a convenient way to put header connectors on arduino pro mini without soldering them to proto board or any pcb. Yeah.. Glues baby! (Do I start to sound like a weird glue fetish guy?)

I also used spacer as a stand to hold the arduino pro mini and ultrasonic sensors.


2 USB connectors glued together with toggle switch. The USB's would then connect to 2 channels of power bank. Although the power bank has power button itself, the button can only turn the power bank on and start open the current, but it can't cut its current itself. Hence I added a toggle switch.

Here You see the legs had redone with plastic steel epoxy.

Here is an easy set up of my photodiode and resistor. No pcb, only wires and female headers needed. Sorry I missed taking picture details of the photodiodes glued to power bank.

First time fully assembled.


Well, that's all folks, I hope you'll join the fun building this creature.
How to calibrate the servo motors? I am using 360 degree continuous rotating servo motor.
ReplyDeleteWhy are you using continuous servos? You shouldn't use continuous servos. Please read the comments in the arduino sketch. There you'll find instructions to find which codes their values need to be changed.
DeleteThanks for your reply.
DeleteHii I intend to make this project for my students as academic project. But i have some queries. From what material you made shaft(servo horn and spacer: couldnt understand these, are they readily available or made from scratch).
ReplyDeletespacers (or some call them standoffs) are something like these:
Deletehttps://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Dindustrial&field-keywords=nylon+standoff&rh=n%3A16310091%2Ck%3Anylon+standoff
servo horns usually come with the servos, no need to buy them separately:
https://www.servocity.com/servos/servo-accessories/servo-attachments/servo-horns
They are things I had already lying around in my parts box. I just glued them together to made a shaft.
Do spacers need to be in specific diameter?
DeleteAnother issue is with portable power bank. What happens when power bank goes empty, i mean how to recharge them..?
ReplyDeleteCharge them using usb cable from any usb port (computers, etc) or any charger that has usb port output.
Deletewhere are the connectors connected to Aurdino pro mini board pins. I see two sets of connecting wires and also connecting bread combs soldered, can you elaborate on this detail. Plz drop your mail for clarification.
ReplyDeleteThanks and regards.
I already insert circuit diagram in my post.
DeleteAnd no, I'm sorry, I will not write my email address here.
HOw much does it cost?
ReplyDeleteI guess it will depend where you live. In my country it costs no more than $50.
Deletecan you please make a more detailed step on how to make it
ReplyDeleteCodes are already provided. Circuit diagram is also provided. Parts are all in the list. As for construction, you need to be creative. It's not a kit that has an assembly instruction. So I think it's all already there. Why don't you tell me which part you find it hasn't clear?
DeleteHere is an inspiration for the body construction if you need it: https://www.youtube.com/watch?v=sqDfYtm3opI (Mr. Michael Barratt made a better version of my Walter)
Thanks, this is great description, well done!
ReplyDeleteThank you for your kind words.
Deletehow to code it
ReplyDeleteWhat do you mean? I already provided the codes. Just copy it to your arduino IDE then upload it to your arduino board.
DeleteIf you're not familiar with arduino environment please first visit arduino.cc. There are a lot of tutorials and documentations in the site to begin.
Hello and thank you very much for sharing your knowledge and experience ! Great job !
ReplyDeleteIm a really noob in electronics so I have some few (stupid) questions.
First is where do the 5v (red) wires from servos, sonars and diodes go ?
And second is why did you stick 2 other rows of header connectors and can I get a more detailed diagram/schema about it please ?
Yeah im a real newbie from all points of view but I really love arduino based electronics and these little home made robots.
Cheers mate !
Scmb.
Hi Nerko.
DeleteI see you haven't used to see circuit schematics. That's alright, and these aren't stupid questions.
1. All 5v lines connected to 5v power source which in this case is the portable power bank. Notice there's also 5v coming out from one of the USB connectors? That's the power source. That particular USB connector goes to 2.1A channel of the power bank. I didn't write it in the schematics, but the other USB also provide 5v power (like any others usb power), and you can see it connected to arduino's 5v pin, as the arduino also need to be 5v powered.
Then why did I separate power sources between arduino and other electronics? Because the servos drawn a lot of current, and if the arduino shared power with the servos, the arduino would sometimes restart itself due to lost power 'stealed' by the servos.
2. Actually your second question is still related to the matter of power line. Those two rows added on the each side of the arduino are power lines. Middle rows are positive (5v) come from 2.1A USB, and outside rows are negative (ground). With those rows I can conveniently connect my servos' headers and other electronics' headers to arduino's pins and power line. So just solder the middle rows together (left and right side also connected using a wire) to 2.1A USB. Do the same with the negative/ground line (outside rows) to ground. Remember to connect all the ground.
Alright Nerko, time to grab your solder iron.
Cheers!
Oooh dam' I couldn't expect better and more clear answer than this. Thanks a lot and may God bless you !
DeleteYour project is very impressive. But I want to ask to you. Is the power bank for the flow of electricity can be replaced with ordinary batteries? How many batteries should Volt have to be connected to the robot?
ReplyDeleteYes, of course it can. Power bank is actually a regulated batteries anyway.
DeleteWell, you can see in the schematic attached in the post that the arduinos need 5v, and so do the ultrasonic sensors.
With the resistor value I use in the schematic I think the photodiodes can still take higher voltage (I already mentioned in the post that I might have put the resistors value too high).
The servos can take up to 6v. But I chose not to push the voltage to their limit.
Arduino pro mini already have voltage regulator on board that can take up to 9v through raw pin (be careful not to connect more than 5v to 5v pin). Say you're going to power the arduino with 7.4 lithium, maybe arduino's 5v pin can still provide enough current for the three ultrasonic sensors, but not for the servos. So you'll still need a voltage regulator anyway for powering the servos separately.
So for the conclusion, the easiest way is to step-down your batteries using voltage regulator to 5v, and use it to power all the electronics. Make sure your batteries and regulator can provide a large current, cause those servos are beasts!
Okay. For the servo, you say there are 5 servings, 2 pieces for the front, 2 more for the back, and 1 piece for the middle. The middle part where it is placed servo?
DeleteThis comment has been removed by the author.
DeleteAnd one more, can you show how to assemble the robot? It will be very helpful in the work of the robot. Can you share my tutorial video?
DeleteCan this robot be controlled using Bluetooth friend???
ReplyDeleteNope.
DeleteI don't know. Maybe, depends on the problem.
ReplyDeletei have a question ? what is the fifth servo doing in this project ? which is in the middle?
ReplyDeleteThe fifth servo is making vertical movement for the legs. It's between the two front servos.
Deleteokay thankyou, and please tell me about the two different grounds one you have given to switch and second to arduino from where to connect them
ReplyDeleteWhat 'two different grounds'? All grounds must be connected together.
Deleteyeah i have done that but there's a problem in my robot its going in backward direction rather than front, i have checked everything its all same as yours but havent got a solution, can you help me at this ?
Deleteand also tell me the serial number of photodiodes you have used
Deletehey, i'm fairly new to electronics and i don't really understand the concept of grounding (the 3 lines on the circuit diagram) , does that mean i just leave it hanging or do i insulate it or what
ReplyDeletesorry for the basic question, using this project as my introduction to electronics
No need to sorry. Connect all those grounds to the batteries' negative pole.
Delete(The fifth servo is making vertical movement for the legs)
ReplyDeleteWhy we need to do this? Is it make robot turn left or right?
Hello. It's such a great project. I wanna ask, can i just use the 9V battery instead of using a power bank? Thankyou :)
ReplyDeleteFirst; I don't think standard 9V batteries have enough amps for the servos. Second; if you find a 9V battery that can supply high amps, you're still going to need a 5V voltage regulator.
DeleteThis comment has been removed by the author.
ReplyDeleteHello dear friend, I comme back to tell you that I made it. Thanks to you and your great work I made the same quadruped insect robot... Not completely the same, check out a litlle video I made of it : https://streamable.com/rasrl
ReplyDeleteThat's excellent! Yours looks beautiful.
DeleteAre those 18650 batteries? Are they connected in series or parallel? What kind of voltage regulator are you using?
Good job man! I wish you shared your video in youtube.
Yeah 2 18650 batteries on 2 separate circuits to power up 3 of 5 servos and the other one to power up the others 2 servos + arduino and all detectors.
ReplyDeleteWith a MT3608 step up converter delivering each 5V and 2A (widely enough, doesn't even heat up).
But this supply circuit is temporary because I'm waiting for 2 li-po batteries to make it look thiner.
But now Im hesitating bcause with these 2 18650 batteries it looks good too.
Nah, you are the one who did good job mate. I was only following your steps.
I will made a better video of it and will post it soon on YouTube.
Will sharz the link
Hello , Can you tell me how exactly to upload code to the pro mini cuz i got errors.
ReplyDeleteWithout any further details on how you uploaded the code and what the errors are, I can only assume generic misstep people usually did: Have you change the board selection on arduino IDE to arduino pro mini and select processor setting to whatever atmega chip on your pro mini board?
DeleteThis comment has been removed by the author.
ReplyDeleteno worries ,was sort of bad connection
ReplyDeleteI have question on the switch part. On the diagram there are 3 wires that came out ( 5v from 1st usb, 5v from the 2nd usb , 1 ground from the switch ), but then u connect 4 wires with the 5v and ground on the arduino. From where it that 4th wire?
ReplyDeleteHello again, dear friend. Everything on this project works fine except the part where it should chase light. I switched the resistors to 82k ohm, switched the places of photodiods legs but still cant make it chase light. For light source im using my phones lighter. Do i need to use more powerful light source and can u give some info bout this part?
ReplyDeleteHi. Have you checked the photodiodes polarity? They should connected in reverse biased manner. The cathodes should connect to 5v and the anodes should connect to resistors/analog arduino pins. I think I messed up on the complete circuit scheme. Please refer to detailed photodiode connection image.
Deletehttps://imgur.com/VWc2IzU here is the image all 4 diodes are connected like this.
DeleteHi,
Deletei have a different problem. Everything works except the front sonar. I replaced the sonar with a new one...not working...then i checked the cables all work...so finally i decided to use a different arduino board...still not working no matter what i do, any idea ?
Can we use 3 servo motors instead of 5 ?
ReplyDeleteHello. I really appreciate your work and I was inspired to make one. I have a question. Is it ok to use SG90s rather than MG90s Servo motor ? I will substitute the SG90s because my budget is so tight :) Thank you in advance :)
ReplyDeleteGreat Info about AI. Thanks For Providing
ReplyDeleteArtificial Intelligence and Robotics
Tech News In India
Technology in India Today
Artificial Intelligence Pros and Cons
Artificial Intelligence use Cases
hello sir, I appreciate the hard word put in this project and sharing the same with us. I have only one question which i did not understand...what is the fifth servo for? and how is it mechanically connected.....i cant make out from the photos you have shown. Please only if you could give me the detailed fitting for the fifth servo, ill be grateful...Thank you once again
ReplyDeletehow i will upload the code?
ReplyDeleteWhich libraries should we download to use this code
ReplyDeleteTed apa kabarlu? Msh inget gua ga?
ReplyDeleteHi where should I fix the 5th horizontal servo plsss tell
ReplyDeleteAnyone help please
ReplyDeleteHi. I have a question. In what conditions did walter will run and walk?
ReplyDeletehello sir, I appreciate the hard word put in this project and sharing the same with us. I have only one question which i did not understand...what is the fifth servo for? and how is it mechanically connected.....i cant make out from the photos you have shown. Please only if you could give me the detailed fitting for the fifth servo, ill be grateful...
ReplyDeleteCan i ask whether we can use a arduino uno instead of arduino pro mini
ReplyDeletewhen i upload the codes it says that "servo.h: no such file or directory
ReplyDeleteMy servos are not working with power output so for that I had used pca9856 servo driver
ReplyDeleteSo can you please help me tell about what amendments I would made in code to connect aurdino with driver?