0

How is a tiny braitenberg vehicle robot made? by Alexander Weber

tiny_robotIt weighs 17 gramms, is driven by two pager motors, powered by a small lipo cell and controlled by an 8-pin ATtiny25V.  Pretty isn’t it? After reading this post you can build this amazing robot on your own. First, i want to explain what exactly braitenberg robot is?
Braitenberg vehicle : A Braitenberg vehicle is an agent that can autonomously move around. It has primitive sensors (measuring some stimulus at a point) and wheels (each driven by its own motor) that function as actuators or effectors. A sensor, on its simpler form, is directly connected to an effector, so that a sensed signal immediately produces a movement of the wheel. Depending on how sensors and wheels are connected, the vehicle exhibits different behaviors (which can be goal-oriented). This means that it appears to strive to achieve certain situations and to avoid others, changing course when the situation changes.[1]

Schematic and parts

This tiny robot has a very low component count. At least for a robot, based on a microcontroller. That has, of course, some implications. It can handle only two sensors and the motors run only in one direction. A full H-bridge for both motors would need 8 transistors and more lines to control it. So I decided to just use a single transistor to drive the motor. That means it can only run forward. Not a big deal for a Braitenberg vehicle. Here is the parts list. Most parts are very common.
  • ATtiny25V, 2 kB flash RAM, ATTINY25V-10PU-ND
  • MPC1700 3.3 voltage regulator, MCP1700-3302E/TO-ND
  • 2 * light dependent resistors (LDR)
  • 2 * 10 kOhm resistor
  • 2 * 470 Ohm resistor
  • 2 * 2n3904 transistor
  • 2 * 1n4148 diode
  • 100n capacitor
  • 100u capacitor
  • Lithium-polymer battery, 3.7 V, 100mAh, HobbyCity
  • 2 * fuse holder
  • 2 * pager motor
  • heat shrink tubes
  • rubber tube
  • custom PCB
  • 6-pin ISP header
A bit tricky was to find the right rubber tube to build the wheels. I found these, which are normally used to connect tiny motors to a model stern tube. Because the inner diameter is a bit to wide, I used short pieces of cable isolation as an adaptor. If you have pager motors with an attached weight on their shaft, you may want to take a look at the RobotRoom for instruction on how to get rid of the weights. I had no locking pliers, maybe that’s the reason why I ruined at least three motors. Mostly by twisting the shaft while trying to pull off the weight.

Software and programming

The software is straigt forward. Reading two inputs, the light sensors, and driving two ouput lines accordingly with a PWM signal. But it turns out, that the software needs a lot of adjustments. First you have to figure out in what range the light sensors report values. Next, check at what PWM level the robot starts to move. Maybe even adjust the directional stability. Programming the robot in circuit via the 6-pin ISP header didn’t work out in the first place. The programmer was not able to set the lines to high that were driving the transistors. So I soldered a socket in place and can now pull off the two 470 Ohm resistors. After programming I can re-insert the resistors. Can be seen on the left critter on the picture above. A bit awkward, but it works.

Demo

You should have a very clean surface for them to run on. If you put them on a table, as I did, be sure to have very good reflexes or put a kind of fence around them. Mine dropped off the table a couple of times. Mostly no dramatic damage, but the sensors got twistet and the motors sprung out of their holders. Depending on the ambient light, the light source itself and the nature of the surface you may have to adjust the light sensors. As an example, if the surface is white and diffuses the light, then you would have to bend the sensors away from the surface, because the surface looks bright, even if the robot turns away from the light source.

Issues and conclusion

There are still a couple of issues to resolve.
  • Software improvements, use ADC in free running mode and use hardware PWM to drive the motors
  • Place the skid in the middle of the PCB.
  • There is no protection of deep discharging the battery, no idea how to solve this.
  • Add a small power switch.
Someone wanting to volunteer for some private beta testing and helping with improvements? Besides these issues, these two critters are fun. There was a lot of testing, reprogramming and re-adjustment needed, to get them doing, what I thought they should do. But hey, that’s the way to learn something.

Links and downloads

/* -----------------------------------------------------------------------
 * Title:    tiny braitenberg
 * Author:   Alexander Weber <alex@tinkerlog.com>
 *           http://tinkerlog.com
 * Date:     24.07.2009
 * Hardware: ATtiny25v, ATtiny45 or 85 will work as well.
 *
 * If using a lipo-cell, never get under 2.5 V.
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>

#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))

#define LED_BIT PB0
#define LEFT_MOTOR_BIT PB1
#define RIGHT_MOTOR_BIT PB2
#define LEFT_SENSOR_BIT PB3
#define RIGHT_SENSOR_BIT PB4

#define LEFT_OFFSET 10
#define RIGHT_OFFSET 0

static int16_t left_sensor = 0;
static int16_t right_sensor = 0;
static volatile uint8_t left_motor = 0;
static volatile uint8_t right_motor = 0;
static volatile uint8_t act_left_motor = 0;
static volatile uint8_t act_right_motor = 0;
static uint8_t count = 0;

/* -----------------------------------------------------
 * ADC interrupt
 * TODO: use ADC in free running mode
 */
SIGNAL(ADC_vect) {
 // act_light = ADCH;        // read only 8-bit
}

/* -----------------------------------------------------
 * Timer0 overflow interrupt
 * F_CPU 8.000.000 Hz
 * -> prescaler 0, overrun 256 -> 31.250 Hz
 * -> 256 steps -> 122 Hz
 *
 */
SIGNAL(TIM0_OVF_vect) {
 // every 256th step take over new values
 if (++count == 0) {
 act_left_motor = left_motor + LEFT_OFFSET;
 act_right_motor = right_motor + RIGHT_OFFSET;
 if (act_left_motor > 40) {
 PORTB |= (1 << LEFT_MOTOR_BIT);
 }
 if (act_right_motor > 40) {
 PORTB |= (1 << RIGHT_MOTOR_BIT);
 }
 }
 if (count == act_left_motor) {
 PORTB &= ~(1 << LEFT_MOTOR_BIT);
 }
 if (count == act_right_motor) {
 PORTB &= ~(1 << RIGHT_MOTOR_BIT);
 }
}

/*
 * get_adc
 * Return the 8 bit value of the selected adc channel.
 */
uint16_t get_adc(uint8_t channel) {

 // ADC setup
 ADCSRA =
 (1 << ADEN) |                   // enable ADC
 (1 << ADPS1) | (1 << ADPS0);    // set prescaler to 8

 // select channel
 ADMUX = channel;

 // select reference voltage
 // ADMUX |= (1 << REFS0);       // use internal reference

 // warm up the ADC, discard the first conversion
 ADCSRA |= (1 << ADSC);
 while (ADCSRA & (1 << ADSC));

 ADCSRA |= (1 << ADSC);           // start single conversion
 while (ADCSRA & (1 << ADSC));    // wait until conversion is done

 return ADCW;
}

uint16_t scale_down(uint16_t v) {
 v = max(300, v);
 v -= 300;
 // v /= 6;
 v >>= 2;
 v = min(120, v);
 return v;
}

int main(void) {

 uint8_t i = 0;

 // eneable pins as output
 DDRB |=
 (1 << LED_BIT) |
 (1 << LEFT_MOTOR_BIT) |
 (1 << RIGHT_MOTOR_BIT);

 // timer 0 setup, prescaler none
 TCCR0B |= (0 << CS02) | (0 << CS01) | (1 << CS00);

 // enable timer 0 interrupt
 TIMSK |= (1 << TOIE0);
 // TIMSK0 |= (1 << TOIE0);

 // enable all interrupts
 sei();

 // intro, blink red
 for (i = 0; i < 5; i++) {
 PORTB |= (1 << LED_BIT);
 _delay_ms(100);
 PORTB &= ~(1 << LED_BIT);
 _delay_ms(100);
 }

 _delay_ms(5000);

 while (1) {

 /* motor starts with 5
 for (i = 0; i < 15; i++) {
 right_motor = i * 10;
 left_motor = i * 10;
 _delay_ms(5000);
 right_motor = 0;
 left_motor = 0;
 PORTB |= (1 << LED_BIT);
 _delay_ms(500);
 PORTB &= ~(1 << LED_BIT);
 }
 */

 // sensor reads from ~100 to 800
 left_sensor = get_adc(2);
 right_sensor = get_adc(3);

 // scale down
 left_sensor = scale_down(left_sensor);
 right_sensor = scale_down(right_sensor);

 // give some visual feedback
 if (abs(left_sensor - right_sensor) < 10) {
 PORTB |= (1 << LED_BIT);
 }
 else {
 PORTB &= ~(1 << LED_BIT);
 }

 // aggression
 right_motor = left_sensor;
 left_motor = right_sensor;

 // love
 // right_motor = 120 - right_sensor;
 // left_motor = 120 - left_sensor;

 // fear
 // right_motor = right_sensor;
 // left_motor = left_sensor;

 _delay_ms(10);

 }

 return 0;}
  • Source code and Eagle CAD files, really BETA, tiny_braitenberg.zip
  • Related posts:

    1. Stanford Students Claim Altitude Record For Tiny, Autonomous Airplanes
    2. How a Drawdio is made?
    3. The ROPID Robot
    4. Öğrenebilen robot kol.
    5. Cockroach-Inspired hexapod Robot
    0.0/60votes
    Voting statistics:
    RatePercentageVotes
    60%0
    50%0
    40%0
    30%0
    20%0
    10%0
    Click to share thisClick to share this