This is one of the most unconventional designs I've build up to date. It does not run straight, but crawls. The reason for this is that both motors are unidirectional. It uses two wristwatch lavet-type motors as it main actuators and uses two whiskers and two directional LDR light sensors for sensing it's environment. The biggest problem with robot is the fragile connection of the wheels to the shaft of the engine.
The Nano Rover is an autonomous vehicle that uses two wristwatch motors as its main actuators. Analog wristwatch motors are one-phase Lavet stepper motors and are driven by a biphase pulse for every step. Small actuators are hard to get, most micromotors are too big for very small scale - aka tabletop - robots and consume too much power. The wristwatch motors are a nice trade-off between cost and performance. The only drawback is that they can only turn clockwise. There are wristwatch motors that can turn in both directions, but these are very hard to find. The design of the robot is build around this limitation of clockwise turning. The movement pattern of this robot is worm-like, in which each motor runs after each other and let the robot crawl around.
The robot is build around an AT90L2313 in an SOIC formfactor. This allows for some miniaturization of the electronics.
Driving the wrist watch motors
To drive these motors, we have to provide a bi-phase pulse train. The following two images show us the pulses that are generated by the onboard electronics of a wristwatch.
The interval between each pulse is exactly 1 second, the unit of movement of the seconds handle of the watch. The next image shows a complete period of this pule train.
It is very easy to connect the wristwatch motor to a microcontroller, you connect one pin of the MCU to each end of the coil. There can be some concerns on the inductance of the coil, as the inducted potential can possibly damage the MCU. In practice , however, this has not happended to me.
Driving the watchmotor is easy as the next BASCOM AVR program shows us ...
ma alias PORTB.0 mb alias PORTB.1 DDRB = &B00000011 DDRD = &B01000000 dim a as byte dim b as byte ma = 0 mb = 0 a = 0 b = 1 MAIN: ma = a mb = b waitms 3 ma = 0 mb = 0 toggle a toggle b waitms 1 goto MAIN
This will generate a pulse of 3ms, with a pause interval of 1 ms. the polarity of the pulse is inverted every time. The output period is 4 ms, resulting in a frequency of 1/0.004 = 250Hz. The second hand of the watch takes 60 pulses for one revolution. The speed of the second is thus 4.17 revolutions per second.
The revolutions speed of the minute hand is 60 times slower then the seconds hand. This means that the minutes hand is revolving at 4.17/60 = 0.0696 revolutions per seconds. Or 4.17 revolutions per minute.
The diameter of a wheel is 25 mm, the speed of the robot is thus 25xpix4.17 = 327.5 mm/minute.
A general formula for the revolutions per second of the seconds hand is:
n = 1/(60t)
nis revolutions per minute of the minute hand
tis period of the pulse in seconds
The period of the pulse (t) can be split up in two part: t = ta + tp, whereby ta the time is that the pulse is active and tp is the pause time.
The time ta should always be between 3ms and 4 ms to have a steady going hand. Off course, other brands of wristwatch motors can vary this empirically defined optimum.
The control program
The next control program allows the robot to crawl along, reacting to touch whenever one of the whiskers hits an object. This simple behavior allows the robot to crawl along obstacles. Although the light value is measured, by counting the time it takes to charge a capacitor through the light dependend resistor, nothing is done with this information. The next step is to add a few lines of code that will seek out dark - or bright - places.
'( NanoRover --------- Watch motor driven autonomous vehicle - motion detection - touch reaction -> inverse engines! (very easy) - photofoob touch is low level behaviour compare two light sources, go to darkest place (e.g. n crawls) then measure again and repaet if dark censor under certain value, stay foot and do motion detection on motion detection -> start moving for n steps towards the lightests place ') ' -- interface declarations motor1_a alias PORTB.0 motor1_b alias PORTB.1 motor2_a alias PORTB.2 motor2_b alias PORTB.3 whisker1 alias PIND.4 whisker2 alias PINB.7 ldr1_pin alias PINB.4 ldr1_port alias PORTB.4 ldr2_pin alias PIND.5 ldr2_port alias PORTD.5 DDRB = &B00001111 PORTB = &B10000000 ' internal pull-up DDRD = &B00000000 PORTD = &B00010000 ' internal pull-up ' -- the next two bits define the polarity on lead a and b for the 2 motors dim polarity as bit dim motor1_enabled as bit dim motor2_enabled as bit dim pulse_counter as word dim state_on_tick as byte dim ldr1_cnt as word dim ldr2_cnt as word dim crawls as byte state_on_tick = 0 pulse_counter = 0 '( -- calculate 180° turn d = 24 mm l = 40mm 1 rot = 60*60 = 3600 pulses 1 rot ~ 3.1415*24 = 75.4 mm 180° ~ 2*pi*r/2 mm = 3.1415*40 = 126 mm n rot = 126/75.4 = 1.67 pulses = n * 3600 = 1.67 * 3600 = 6012 So we need to provide 6012 pulses, take 6000 for one half crawl (1 inchwormy movement ...) ') const HALF_CRAWL = 6000 const CRAWLS_BETWEEN_THINKING = 5 '( -- calculate timing for IRQ clock f = 10MHz interval 1 = 4 ms interval 2 = 8 ms ticks 1 = f*t = 10000000 * 0.004 = 40000 ticks 2 = 10000000 * 0.008 = 80000 we need to do a time irq every 40k and 80k clock ticks If we take the presacler at 1024, we need the next timer preload values ticks 1 timer value = 1024 - 40000/1024 = 984.9375 ~ 985 ticks 2 timer value = 1024 - 80000/1024 = 945.875 ~ 946 ') const PULSE_INTERVAL_ACTIVE = 1024 - 40000/1024 const PULSE_INTERVAL_REST = 1024 - 80000/1024 config TIMER0 = timer, PRESCALE=1024 on timer0 ON_TICK tcnt0 = 1023 enable timer0 enable interrupts ' -- initialize variables ' -- set up the interrupt handler to generate the drive puls for the 2 motors ' -- main subsumbtion loop motor1_enabled = 0 motor2_enabled = 1 crawls = 0 MAIN: ' -- measure light config ldr1_pin = output ldr1_port = 0 waitus 100 config ldr1_pin = input ldr1_cnt = 0 while ldr1_pin = 0 incr ldr1_cnt waitus 50 wend config ldr2_pin = output ldr2_port = 0 waitus 100 config ldr2_pin = input ldr2_cnt = 0 while ldr2_pin = 0 incr ldr2_cnt waitus 50 wend ' print ldr1_cnt; " "; ldr2_cnt ' -- crawl if pulse_counter > HALF_CRAWL then toggle motor1_enabled toggle motor2_enabled pulse_counter = 0 incr crawls end if ' -- react to touch debounce whisker1, 0, TOUCH debounce whisker2, 0, TOUCH goto NO_TOUCH TOUCH: toggle motor1_enabled toggle motor2_enabled pulse_counter = 0 NO_TOUCH: waitms 500 goto MAIN ON_TICK: select case state_on_tick case 0: stop timer0 tcnt0 = PULSE_INTERVAL_ACTIVE if motor1_enabled = 1 then motor1_a = polarity motor1_b = not polarity end if if motor2_enabled = 1 then motor2_a = polarity motor2_b = not polarity end if state_on_tick = 1 incr pulse_counter start timer0 case 1: stop timer0 tcnt0 = PULSE_INTERVAL_REST motor1_a = 0 motor1_b = 0 motor2_a = 0 motor2_b = 0 toggle polarity state_on_tick = 0 start timer0 end select return