And now for something completely different for the World in Motion Challenge
The video, glamour photos, schematic, and code are humbly submitted for your entertainment.
This Raspberry Pi Pico robot is built with subtle and not so subtle optical effects.
- The rear wheels spin opposite the direction of travel.
- The tires have hubcaps with the "Twilight Zone Spiral of Madness" to make them appear off center.
- The spiral on the right hand side will make you really dizzy if you stare at it for long and then look away.
- The black & white wheel (Benham's Disc) on the back will show colors when it rotates at the proper speed, which fixed in the code, found by experiments using a power supply.
- A rotating warning beacon spins and lights when the robot is moving forward.
For motional content, the Wheels of Illusion has qty 4 servos and 4 DC motors controlled by a Raspberry Pi Pico.
The control is by bumper switches on the front, and a ping sensor on the rear.
All my gear motors on hand have different gear ratios and each optical pattern were effective at different speeds. Each motor was run with a power supply to find their best sweet spot rpm and running volts. The value was noted, and set into the PWM duty, tweaked a bit while running on battery.
Python makes the PWM really easy.
The video: https://youtu.be/unmvSvUllOM
I'd ordered some clamp TBs 1-2834015-3 to try.
Wire-To-Board Terminal Block, Screwless, 2.54 mm, 3 Positions, 26 AWG, 20 AWG, Clamp
https://www.newark.com/te-connectivity/1-2834015-3/tb-wire-to-board-3pos-26-20awg/dp/30AC2754
as shown in this photo of the motor driver assembly. I only have used the screw type in the past.
Those clamp connectors are fabulous on the homebrew level shifter board (far right).
I'm mixed on using them on the FET driver card, I had to plan daisy chains since they only fit one wire.
# If the LHS side whisker bumps an object, Wheels Of Illusion backs up and makes a righthand turn to avoid it. # The time Wheels Of Illusion backs up is random, from 1.5 seconds to 4 seconds,. # It will stop backing up if an object is detected 7 inches from the rear # HC-SR04 ping sensor in the rear of Wheels Of Illusion. # If the RHS whisker encounters an object, the behavior is the same except Wheels Of Illusion turns left after backing up. # The beacon turns off when backing up from machine import Pin, PWM # Pin uses the GPIO value , not the actual pin number import utime import random LHSWhisker= Pin(14, machine.Pin.IN,machine.Pin.PULL_DOWN)#GPIO14 physical pin 19 RHSWhisker= Pin(13, machine.Pin.IN,machine.Pin.PULL_DOWN)#GPIO13 physical pin 17 LHSWhiskerLED= Pin(12, machine.Pin.OUT)#GPIO12 physical pin 16 RHSWhiskerLED= Pin(11, machine.Pin.OUT)#GPIO11 physical pin 15 AliveLED = Pin(25,machine.Pin.OUT) LHSservo = PWM(Pin(16))#GPIO16 physical pin 21 RHSservo = PWM(Pin(17))#GPIO17 physical pin 22 # 50 Hz is 20 msec period LHSservo.freq(50) RHSservo.freq(50) # 100% duty of PWM is 65200 counts # 2 ms of 20 ms is 10% for full spd FWD # ( 1.5 ms / 20 ms ) * 65200 = 4875 for servo zerospeed # 1 ms of 20 ms is full spd rev , .05* 65200 zerospd = 4875 LHS_FullSpd = 3250 # LHS side servo is mounted opposite so gets a reversed reference RHS_FullSpd = 6500 LHS_TopSpdRev = 6500 RHS_TopSpdRev = 3250 AliveLED.value(1) PingTrigger=Pin(9,Pin.OUT)#GPIO9 physical pin 12 PingEcho=Pin(8,Pin.IN)#GPIO18 physical pin 11 Beacon = Pin(18, machine.Pin.OUT)#GPIO18 physical pin 24 #ColorSpinner = Pin(19, machine.Pin.OUT)#GPIO19 physical pin 25 #LHS_Spinner = Pin(20, machine.Pin.OUT)#GPIO20 physical pin 26 #RHS_Spinner = Pin(21, machine.Pin.OUT)#GPIO21 physical pin 27 ColorSpinner = PWM(Pin(19))#GPIO19 #GPIO19 physical pin 25 LHS_Spinner = PWM(Pin(20))#GPIO20 physical pin 26 RHS_Spinner = PWM(Pin(21))#GPIO21 physical pin 27 ColorSpinner.freq(100) LHS_Spinner.freq(100) RHS_Spinner.freq(100) ColorSpinner.duty_u16(7000) LHS_Spinner.duty_u16(2500) RHS_Spinner.duty_u16(65000) def Ping(): echotries=0 PingTrigger.low() utime.sleep_us(2) # note sleep_us is for microsecs PingTrigger.high() utime.sleep_us(10) PingTrigger.low() while ((PingEcho.value() == 0) and (echotries<30)): EchoStartTime = utime.ticks_us() echotries=echotries+1 # This check bails out of the loop on a problem with a long echo or failed echo, I havent been able to prove its needed. while PingEcho.value()==1: EchoHeard = utime.ticks_us() PingDeltaTime=EchoHeard-EchoStartTime PingDistance_cm =(PingDeltaTime*.0343)/2 # sound is 343.2 m/s .0343 cm/usec PingDistance_in=(PingDistance_cm)/2.54 #print ("Measured distance is ",PingDistance_cm, "cm" ) print ("Measured distance is ",PingDistance_in, "inches" ) #print ("Echotries =", echotries) return PingDistance_in def backup(): LHSservo.duty_u16(LHS_TopSpdRev) #top speed rev on LHS RHSservo.duty_u16(RHS_TopSpdRev) # top spd rev on RHS Beacon.value(0) ###################### MAIN LOOP ################################ while True: #this is start of the main loop routine AliveLED.toggle() # if no action on the whiakers go straight LHSservo.duty_u16(LHS_FullSpd) #top speed forward on LHS RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS # zerospeed = 4875 Beacon.value(1) # if no action on the whiskers go straight, clear LEDs if ((LHSWhisker.value() ==0) & (RHSWhisker.value() ==0)): LHSWhiskerLED.value(0) RHSWhiskerLED.value(0) ################ LHS whisker routine, backup and turn right if LHSWhisker.value() ==1: #gotta latch this operation LHSWhiskerLED.value(1) count=1 while True: # using break to exit the loop backup() #Ping() PingDistance=Ping() utime.sleep(.2) count=count+1 backuptime=random.randint(7,14) # backuptime is comprised as the number of 200msec cycles before breaking out of the backup loop #print ("backuptime = ",backuptime) print ("count = ",count) print ("backuptime = ",backuptime) #print ("LoopCycles= ",Loopcycles) if (PingDistance<6): break if (count>backuptime): break # print ("ping distance = ",PingDistance) # back up tthen right turn RHturntime=random.uniform(.5,3) LHSservo.duty_u16(LHS_FullSpd) #top speed forward on LHS RHSservo.duty_u16(zerospd) # zerospeed on RHS utime.sleep(RHturntime) #on exit of LHS Whisker routine, go staright again LHSservo.duty_u16(LHS_FullSpd) #top speed forward on LHS RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS ## start RHS side whisker behavior definition if RHSWhisker.value() ==0: RHSWhiskerLED.value(0) if RHSWhisker.value() ==1: RHSWhiskerLED.value(1) count=1 while True: # using break to exit the loop backup() #Ping() PingDistance=Ping() utime.sleep(.2) count=count+1 backuptime=random.randint(7,14) # backuptime is comprised as the number of 200msec cycles before breaking out of the backup loop #print ("backuptime = ",backuptime) print ("RHScount = ",count) print ("RHSbackuptime = ",backuptime) if (PingDistance<6): break if (count>backuptime): break # print ("ping distance = ",PingDistance) # turn left LHturntime=random.uniform(.5,3) LHSservo.duty_u16(zerospd) # zerospeed on LHS RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS utime.sleep(LHturntime) LHSservo.duty_u16(LHS_FullSpd) #top speed forward on LHS RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS