Friday 24 March 2017

Variable speed motors and radio control


This is a quick project I came up with to use the first DAVE robot I made, which was gathering dust and feeling a bit unloved. I wanted to demonstrate two things: variable speed motor control and radio communication between two micro:bits.



Remember, my first DAVE does not use the micro:bit motor controller board by Kitronik. This was not available back then, so I had to make my own much simpler one with transistors and stripboard. Pin 1 of the micro:bit controls the left motor, pin 2 controls the right motor. There is no option to reverse the motors. 

I used the Mu MicroPython editor to write some code that takes control inputs from a handheld micro:bit and transmits data to a receiver micro:bit on the robot.

This is the MicroPython code for the transmitter:

from microbit import *

import radio
radio.on()

speed_both = 0
speed_left = 0
speed_right= 0
wait_until_time=0

while True:
    
    #stop the robot if A+B are pressed, decrease speed with A and increase speed with B 
    #there is a slight delay in the increase/decrease to improve controller usability
    if button_a.is_pressed() and button_b.is_pressed():
        speed_both = 0
    elif button_a.is_pressed() and running_time() > wait_until_time:
        if speed_both > 0:
            speed_both = speed_both - 1
            wait_until_time=running_time() + 200           
    elif button_b.is_pressed() and running_time() > wait_until_time:
        if speed_both < 4:
            speed_both = speed_both + 1
            wait_until_time=running_time() + 200  
    
    #split speed into left and right motor values
    speed_left = speed_both
    speed_right = speed_left
    
    #tilting will steer the robot
    steering = accelerometer.get_x()
    
    #reduce left motor speed according to amount of left tilt 
    if steering < -200:
        speed_left = speed_left - 1
        if steering < -400:
            speed_left = speed_left - 1
            if steering < -600:
                speed_left = speed_left - 1
                if steering < -800:
                    speed_left = speed_left - 1 
                    
    #reduce right motor speed according to amount of right tilt
    if steering > 200:
        speed_right = speed_right - 1
        if steering > 400:
            speed_right = speed_right - 1        
            if steering > 600:
                speed_right = speed_right - 1
                if steering > 800:
                    speed_right = speed_right - 1
 
    #motor speeds are not allowed to be negative
    if speed_left < 0:
        speed_left = 0 
    if speed_right < 0:
        speed_right = 0

    #show motor speeds on LED display    
    display.clear()    
    display.set_pixel(0,4 - speed_left,9)
    display.set_pixel(4,4 - speed_right,9)
    
    #transmit a three char string where the second and third chars are left and right motor speeds  
    #the +100 fixes the string length at 3 and allows string indexing in the receiver to get the speed values
    speed_left = speed_left * 10
    radio.send(str(100 + speed_left + speed_right))
    
    #this pause helps reliability when using the radio
    sleep(50)

And this is the MicroPython code for the reciever:

from microbit import *

import radio
radio.on()

pin1.write_analog(0)
pin2.write_analog(0)
speeds = "100"
display.show(Image.NO)

while True:   
    
    #get a string from the radio message queue
    #if nothing is recieved, the robot continues as before
    #the sleep helps reliability when using the radio
    sleep(50)
    speeds=radio.receive()
    if speeds != None:   
        #speeds '100' is stop
        #speeds '144' is forward
        #speeds '104' is hard left turn
        #speeds '142' is wide right turn, etc
        speed_left = int(speeds[1])
        speed_right = int(speeds[2])   
    
        #analog output values can be 0 up to 1023  
        pin1.write_analog(speed_left * 255)
        pin2.write_analog(speed_right * 255)        
        
        #show motor speeds on led display
        display.clear()    
        display.set_pixel(0,4 - int(speed_left),9)
        display.set_pixel(4,4 - int(speed_right),9)