Making a Rpi Pico Based Smart Vehicle
ProjectsJun 3017 / 17Sep 715h ago1 MONTH LATER

SPV v50.01 Development Notes
Last reply was hitting this forum’s 30k words limit. So I am making this new reply. Let me make a briefly progress report.
(1) Progress so far
I started with a copy cat of Tom’sHardware tutorial of using a motor driver to drive a single motor (MX1508 driving TT130). Everything went OK.
I then used the TB6612FNG motor driver to drive two N20 motor. Everything also went well.
I then used the TB6612FNG motor driver to drive two TT130 motors, and I had a big problem of intermittent failures when trying to sequentially test one motor and then the other, and found that one or other motor could not start, or only could start if I used my hand to help start moving. One starts moving, the motor can move happily. It took me some 4 or 5 hours to conclude that the non start problem might be a software problem, and a software reset might solve the problem. Anyway, I tidied up the program, version 50.01 which can almost always start one motor then another motor, and the other way round. I am saving this almost very good program for later reference.
(2) Troubleshooting by swapping
I have been using the swapping/pairing trick which I found very effective to locate the trouble making place. Very briefly, I test two motors, with two sets of hardware and wiring. So I can swap motor, connector, wring in seconds, as show in the photo below. Actually I have 4 or 5 identical sets of motors and duPont connectors for fast swapping.
spv_2wd_5001_2021sep01011024×1145 313 KB
Rpi Pico TB6612FNG TT130 Motor Schematic V5.0
pico_tb6612fng_2021sep0101799×690 137 KB
Sticky Motor 2 Cannot Always Self Start Problem
I use the following test to sequentially run Motor 1 and Motor 2 four times.
for count in range(4):
testMeasureEncodeIntCountMoveSeconds(motorDriverDictNum = 2, motorNum = 1, pwmFreq = 1000, dutyCycle = 100, moveSeconds = 2)
testStopMotor(motorDriverDictNum = 2, motorNum = 1)
utime.sleep(1)
testMeasureEncodeIntCountMoveSeconds(motorDriverDictNum = 2, motorNum = 2, pwmFreq = 1000, dutyCycle = 100, moveSeconds = 2)
testStopMotor(motorDriverDictNum = 2, motorNum = 2)
utime.sleep(1)
I still find Motor has a problem to start, and I need to push it a little bit to help it to start. I am not sure if it is the motor’s stick gear box problem, or the motor driver’s second channel sticky problem. I need to do some swapping troubleshooting tomorrow.
TT130 Encoder Motor Calibration Notes
I am going to measure the speeds of a range of motor power, 9V, 7.2V, 6V, 4.5V, and 3V. The picture below shows 9V motor power gives 70rpm.tt130_12v_2021sep0203800×480 149 KB
Now below is the complete list of Vm (V motor) vs speed (rpm)
9.0V = 350mA = 240uS = 70rpm
7.2V = 270mA = 300us = 55rpm
6.0V = 250mA = 340us = 49rpm
4.5V = 200mA = 400us = 42rpm
3.0V = 150mA = 660us = 25rpm
Now what I am curious to know or to calibrate is if I use Vm motor power = 9V, what is the corresponding (PWM freq = 1000Hz) Duty Cycle of 7.2V/55rpm, 6.0V 49rpm 4.5V/42rpm, 3.0V/25rpm?
TT130 Motor Vm vs speed (rpm)
I found speed vs Vm (yellow line) is rather linear. I also need to plot speed vs duty cycle, as I did for N20 motor earlier. So far so good. So I will take a longer break this time.tt130_rpm_vs_vm_2021sep0201869×309 125 KB
Vehicle Dictionary Config
So far we have been assigning each of the two motors by two numbers: motorDictNum, motorNum. So far so good. We have tested OK all the motor dependant functions by two numbers motorDictNum, motorNum
Now we are going the motor dictionary one level up, to vehicle dictionary vechicleDict. Each vehicleDict configs on vehicle which has two motors.
Earlier to setup two motors, we need to set two motors one by one. Now we can set up the two motors of one vehicle in one go, by just saying setup vehicle,
All the low functions stays the same, it is only the higher vehicle dictionaries and functions are new. In other words if the vehicle dicts and function are working, all the lower calling functions should work without any problem (this is the beauty of “Functional Programming”.
The new vehicle dictionaries and functions are listed below:
# *** Vehicle Config ***
vehicleDict01 = {
'MOTOR_DRIVER_DICT_NUM': 2,
}
vehicleDictDict = {
'1': vehicleDict01,
'2': vehicleDict01,
}
# *** Vehicle Functions ***
def setupVehicle(vehicleNum):
motorDriverDictNum = vehicleDictDict[str(vehicleNum)]['MOTOR_DRIVER_DICT_NUM']
setupMotor(motorDriverDictNum, 1)
setupMotor(motorDriverDictNum, 2)
return
Vehicle Abstract Level Functions
Now I am starting off to write the first coouple of vehicle level functions. Below is an example.
# *** Old Motor Abstract Level Function ***
# Motor Level ADT (Abstract Data Type) on moving motor forward
def testMoveMotorForwardSeconds(motorDriverDictNum, motorNum, moveSeconds):
print('\ntestmoveMotorForwardSeconds()')
motorDict = setupMotor(motorDriverDictNum, motorNum)
motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
moveMotorForwardSeconds(motorConfigDict, moveSeconds)
stopMotor(motorConfigDict)
return
# Example call
testMoveMotorForwardSeconds(motorDriverDictNum = 2, motorNum = 1, moveSeconds = 2)
# *** Proposed New Vehicle Abstract Level Functions ***
def testVehicleMoveOneMotor(vehicleNum, wheelNum, actionNum, speedNum, moveSeconds):
...
return
Progress report of writing vehicle level functions
Writing the vehicle functions has been as smooth as I expected. I first wrote a function to move a vehicle’s two front motors, then another function to stop the front two motors. The test sample below (1) run the two motors non stop, (2) hold 4 seconds, (3) stop two motors.
# *** Vehicle Config ***
vehicleDict01 = {
'MOTOR_DRIVER_DICT_NUM': 2,
}
vehicleDictDict = {
'1': vehicleDict01,
'2': vehicleDict01,
}
# *** Vehicle and Wheel Functions ***
def setupVehicle(vehicleNum):
motorDriverDictNum = vehicleDictDict[str(vehicleNum)]['MOTOR_DRIVER_DICT_NUM']
frontLeftMotorDict = setupMotor(motorDriverDictNum, 1)
frontRightMotorDict = setupMotor(motorDriverDictNum, 2)
motorDictDict = {'FRONT_LEFT_MOTOR': frontLeftMotorDict, 'FRONT_RIGHT_MOTOR': frontRightMotorDict}
return motorDictDict
def moveVehicleTwoFrontMotorsForwardNonStop(vehicleNum):
motorDictDict = setupVehicle(vehicleNum)
frontLeftMotorConfigDict = motorDictDict['FRONT_LEFT_MOTOR']['MOTOR_CONFIG_DICT']
frontRightMotorConfigDict = motorDictDict['FRONT_RIGHT_MOTOR']['MOTOR_CONFIG_DICT']
moveMotorForwardNonStop(frontLeftMotorConfigDict)
moveMotorForwardNonStop(frontRightMotorConfigDict)
return
def stopVehicleTwoFrontMotors(vehicleNum):
motorDictDict = setupVehicle(vehicleNum)
frontLeftMotorConfigDict = motorDictDict['FRONT_LEFT_MOTOR']['MOTOR_CONFIG_DICT']
frontRightMotorConfigDict = motorDictDict['FRONT_RIGHT_MOTOR']['MOTOR_CONFIG_DICT']
stopMotor(frontLeftMotorConfigDict)
stopMotor(frontRightMotorConfigDict)
return
def testMoveVehicleTwoFrontMotorsForwardNonStop():
moveVehicleTwoFrontMotorsForwardNonStop(vehicleNum = 1)
return
def testStopVehicleTwoFrontMotors():
stopVehicleTwoFrontMotors(vehicleNum = 1)
return
# *** Sample Test ***
# testMoveVehicleTwoFrontMotorsForwardNonStop()
# utime.sleep(4)
# testStopVehicleTwoFrontMotors()
Move vehicle forward and backward, turn vehicle left and right tested OK
Only four statements are need to move vehicle forward and backward, turn left and right, as listed below:
# test move vehicle forward and backward, turn vehicle left and right
testMoveVehicleMotorListForwardHoldTime() # move forward 4 seconds
testMoveVehicleMotorListBackwardHoldTime() # move backward 4 seconds
testTurnVehicleLeftHoldTime() # turn left 4 seconds
testTurnVehicleRightHoldTime() # turn right 4 seconds
Full listing below:
# Program Name
# spv5011_2021sep0504.py - tlfong01 2021sep05hkt1927
# Reference
# Pi-Top Forum - making-a-rpi-pico-based-smart-vehicle/924
# https://forum.pi-top.com/t/making-a-rpi-pico-based-smart-vehicle/924
#
# Configuration
# Acer Aspire XC-780 Intel CORE i5-6400 2.7GHz, 8GB, Chinese Windows 10 Home (64-bit, 2020nov15),
# Thonny 3.3.3, Python 3.7.9 (32-bit), Tk 8.6.9, USB COM Port #4
#
# Thonny MicroPython Intepreter
# Micropython (Rapsberry Pi Pico)
#
# DC Motor
# TT130 1:48 gear motor
# 9.0V = 350mA = 240uS = 70rpm
# 7.2V = 270mA = 300us = 55rpm
# 6.0V = 250mA = 340us = 49rpm
# 4.5V = 200mA = 400us = 42rpm
# 3.0V = 150mA = 660us = 25rpm
# N20 1:100 6V DC Gear Motor with quadrature encoder signals A, B
# N20 Gear Motor Spec (6V gear 1:100 no load speed = 300 rpm (https://www.pololu.com/search/compare/173)
#
# DC Motor Driver
# TB6612FNG Dual DC Motor Driver
# Brief Description of Program Function
# 1. Move DC motor forward, backware, stop.
# 2. Use PWM to control motor speed
# 3. Use motor encoder to measure speed
# 4. Use encoder signals to help driving a 2WD to move in a straight line
# Digital Oscilloscope ATTEN ADS1102CAL+
# https://toolboom.com/en/digital-oscilloscope-atten-ads1102calplus/
# ATTEN ADS100 User Manual
# https://micromir.ucoz.ru/Oscil/Atten/ADS1000_User_Manual.pdf
import utime
from machine import Pin, PWM
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# *** Motor Level Config and Functions ***
# *** Motor Dicts ***
motorDriverDict02 = {
'TITLE' : 'TB6612FNG Dual DC Motor Driver Dictionary v0.2 tlfong01 2021aug23hkt1009',
'STANDBY' : 5,
'1': {'IN1': 10, 'IN2': 11, 'PWM' : 3, 'ENCODE': 14, \
'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},
'2': {'IN1': 12, 'IN2': 13, 'PWM' : 4, 'ENCODE': 15, \
'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},
'3': {'IN1': 0, 'IN2': 0, 'PWM' : 0, 'ENCODE': 0, \
'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},
'4': {'IN1': 0, 'IN2': 0, 'PWM' : 0, 'ENCODE': 0, \
'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},
}
motorDriverDictDict = {
'1': motorDriverDict02,
'2': motorDriverDict02,
}
# *** Motor Functions ***
def setupMotor(motorDriverDictNum, motorNum):
motorDriverDict = motorDriverDictDict[str(motorDriverDictNum)] # Get driver dict
driverStandBy = Pin(motorDriverDict['STANDBY'], Pin.OUT) # create driverStandBy pin object
motorIn1 = Pin(motorDriverDict[str(motorNum)]['IN1'], Pin.OUT) # Create Motor # motorNum In1 pin object
motorIn2 = Pin(motorDriverDict[str(motorNum)]['IN2'], Pin.OUT) # Create Motor # motorNum In2 pin object
motorPwm = PWM(Pin(motorDriverDict[str(motorNum)]['PWM'])) # Create Motor # motorNum Pwm pin object
motorEncode = Pin(motorDriverDict[str(motorNum)]['ENCODE'], Pin.IN, Pin.PULL_DOWN) # Create Motor # motorNum Encode pin object
motorPwmFreq = motorDriverDict[str(motorNum)]['DEFAULT_PWM_FREQ']
motorDutyCycle = motorDriverDict[str(motorNum)]['DEFAULT_DUTY_CYCLE']
motorEncIntCntRev = motorDriverDict[str(motorNum)]['DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION']
motorConfigDict = {'StdBy': driverStandBy, 'In1': motorIn1, 'In2': motorIn2, 'Pwm': motorPwm, 'Encode': motorEncode}
motorStateDict = {'PwmFreq': motorPwmFreq, 'DutyCycle': motorDutyCycle, 'EncodeIntCntRev': motorEncIntCntRev}
motorDict = {'MOTOR_CONFIG_DICT': motorConfigDict, 'MOTOR_STATE_DICT': motorStateDict}
motorConfigDict['StdBy'].high() # enable motor driver normal operation, (low = disable)
motorConfigDict['Pwm'].freq(motorStateDict['PwmFreq']) # setup frequency
motorConfigDict['Pwm'].duty_u16(int(65536 / 100) * motorStateDict['DutyCycle']) # and duty cycle
stopMotor(motorConfigDict)
return motorDict
def changeMotorPwmFreqAndDutyCycle(motorDict, pwmFreq, dutyCycle):
motorStateDict = motorDict['MOTOR_STATE_DICT']
motorStateDict['PwmFreq'] = pwmFreq
motorStateDict['DutyCycle'] = dutyCycle
motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
motorConfigDict['Pwm'].freq(motorStateDict['PwmFreq'])
motorConfigDict['Pwm'].duty_u16(int(65536 / 100) * motorStateDict['DutyCycle'])
return
def stopMotor(motorConfigDict):
motorConfigDict['In1'].low()
motorConfigDict['In2'].low()
return
def moveMotorForwardNonStop(motorConfigDict):
motorConfigDict['In1'].low() # move motor
motorConfigDict['In2'].high() # backward
return
def moveMotorForwardSeconds(motorConfigDict, moveSeconds):
moveMotorForwardNonStop(motorConfigDict)
utime.sleep(moveSeconds)
stopMotor(motorConfigDict)
return
def moveMotorForwardHoldTime(motorConfigDict, holdTime):
moveMotorForwardNonStop(motorConfigDict)
utime.sleep(holdTime)
stopMotor(motorConfigDict)
return
def moveMotorBackwardNonStop(motorConfigDict):
motorConfigDict['In1'].high() # move motor
motorConfigDict['In2'].low() # backward
return
def moveMotorBackwardSeconds(motorConfigDict, moveSeconds):
moveMotorBackwardNonStop(motorConfigDict)
utime.sleep(moveSeconds)
stopMotor(motorConfigDict)
return
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# *** Interrupt Related Functions ***
def encodeIntCallBack(pin):
global encodeIntCount
encodeIntCount = encodeIntCount + 1
return
def readEncodeIntCount(motorDriverDictNum, motorNum, pwmFreq, dutyCycle, moveSeconds):
motorDict = setupMotor(motorDriverDictNum, motorNum)
motorStateDict = motorDict['MOTOR_STATE_DICT']
motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
changeMotorPwmFreqAndDutyCycle(motorDict, pwmFreq, dutyCycle)
motorConfigDict['Encode'].irq(encodeIntCallBack, Pin.IRQ_FALLING)
global encodeIntCount
encodeIntCount = 0
moveMotorForwardNonStop(motorConfigDict)
utime.sleep(moveSeconds)
stopMotor(motorConfigDict)
totalEncodeIntCount = encodeIntCount
return totalEncodeIntCount
# *** Move revoloutions and distance ***
def moveMotorEncodeIntCount(motorDriverDictNum, motorNum, encodeIntCount):
motorDict = setupMotor(motorDriverDictNum, motorNum)
motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
#intCountPerSecond = 983
intCountPerSecond = 750
print(' encodeIntCount =', encodeIntCount)
print(' intCountPerSecond =', intCountPerSecond)
moveSeconds = encodeIntCount / intCountPerSecond
print(' moveSeconds =', moveSeconds)
moveMotorForwardNonStop(motorConfigDict)
utime.sleep(moveSeconds)
stopMotor(motorConfigDict)
return
def moveMotorRevolutions(motorDriverDictNum, motorNum, revolutions):
motorDict = setupMotor(motorDriverDictNum, motorNum)
motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
intCountPerRevolution = 983
intCountPerSecond = 750
moveSeconds = (revolutions * intCountPerRevolution) / intCountPerSecond
print(' intCountPerRevolution =', intCountPerRevolution)
print(' intCountPerSecond =', intCountPerSecond)
print(' moveSeconds =', moveSeconds)
moveMotorForwardNonStop(motorConfigDict)
utime.sleep(moveSeconds)
stopMotor(motorConfigDict)
return
# *** Test Functions ***
def testMoveMotorForwardSeconds(motorDriverDictNum, motorNum, moveSeconds):
print('\ntestmoveMotorForwardSeconds()')
motorDict = setupMotor(motorDriverDictNum, motorNum)
motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
moveMotorForwardSeconds(motorConfigDict, moveSeconds)
stopMotor(motorConfigDict)
return
def testMoveMotorBackwardSeconds(motorDriverDictNum, motorNum, moveSeconds):
print('\ntestMoveMotorBackwardSeconds()')
motorDict = setupMotor(motorDriverDictNum, motorNum)
motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
moveMotorBackwardSeconds(motorConfigDict, moveSeconds)
stopMotor(motorConfigDict)
return
def testChangeMotorPwmFreqAndDutyCycleAndmoveMotorForwardSeconds(motorDriverDictNum, motorNum, pwmFreq, dutyCycle, moveSeconds):
print('\ntestChangeMotorPwmFreqAndDutyCycleAndmoveMotorForwardSeconds()')
motorDict = setupMotor(motorDriverDictNum, motorNum)
changeMotorPwmFreqAndDutyCycle(motorDict, pwmFreq, dutyCycle)
motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
print('moveSeconds =', moveSeconds)
moveMotorForwardSeconds(motorConfigDict, moveSeconds)
stopMotor(motorConfigDict)
return
def testMeasureMotorSpeed(motorDriverDictNum, motorNum, pwmFreq, dutyCycle):
totalEncodeIntCount = readEncodeIntCount(motorDriverDictNum, motorNum, pwmFreq, dutyCycle, moveSeconds = 1)
print('motorNum =', motorNum, end = '')
print(' pwmFreq =', pwmFreq, end = '')
print(' dutyCycle =', dutyCycle, end = '')
print(' totalEncodeIntCount Per Second =', totalEncodeIntCount, end = '')
print(' motor speed rpm =', int(int(totalEncodeIntCount * 60)/100))
return
def testMoveMotorEncodeIntCount(motorDriverDictNum, motorNum, encodeIntCount):
print('testMoveMotorEncodeIntCount(), ...')
moveMotorEncodeIntCount(motorDriverDictNum, motorNum, encodeIntCount)
return
def testMoveMotorRevolutions(motorDriverDictNum, motorNum, revolutions):
print('testMoveMotorRevolutions(), ...')
moveMotorRevolutions(motorDriverDictNum, motorNum, revolutions)
return
def testMeasureEncodeIntCountMoveSeconds(motorDriverDictNum, motorNum, pwmFreq, dutyCycle, moveSeconds):
encodeIntCount = readEncodeIntCount(motorDriverDictNum, motorNum, pwmFreq, dutyCycle, moveSeconds)
print('MotorDriverDictNum =', motorDriverDictNum, ' ', end = '')
print('MotorNum =', motorNum, ' ', end = '')
print('PWM Freq =', pwmFreq, ' ', end = '')
print('DutyCycle =', dutyCycle, ' ', end = '')
print('MoveSeconds =,', moveSeconds, ' ', end = '')
print('encodeIntCount =', encodeIntCount)
return encodeIntCount
def testStopMotor(motorDriverDictNum, motorNum):
motorDict = setupMotor(motorDriverDictNum, motorNum)
motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
stopMotor(motorConfigDict)
return
# *** Old Main Tests ***
'''
testMoveMotorForwardSeconds(motorDriverDictNum = 2, motorNum = 1, moveSeconds = 2)
testMoveMotorBackwardSeconds(motorDriverDictNum = 2, motorNum = 2, moveSeconds = 4)
testChangeMotorPwmFreqAndDutyCycleAndmoveMotorForwardSeconds(motorDriverDictNum = 2, motorNum = 1 , \ pwmFreq = 1000, dutyCycle = 10, moveSeconds = 2)
testChangeMotorPwmFreqAndDutyCycleAndmoveMotorForwardSeconds(motorDriverDictNum = 2, motorNum = 1 , \
pwmFreq = 1000, dutyCycle = 90, moveSeconds = 1)
testMeasureMotorSpeed(motorDriverDictNum = 2, motorNum = 1, pwmFreq = 1000, dutyCycle = 80)
testMeasureMotorSpeed(motorDriverDictNum = 2, motorNum = 1, pwmFreq = 1000, dutyCycle = 10)
testMoveMotorEncodeIntCount(motorDriverDictNum = 2, motorNum = 1, encodeIntCount = 1020)
testMoveMotorEncodeIntCount(motorDriverDictNum = 2, motorNum = 2, encodeIntCount = 1920)
testMoveMotorRevolutions(motorDriverDictNum = 2, motorNum = 1, revolutions = 1)
testMeasureEncodeIntCountMoveSeconds(motorDriverDictNum = 2, motorNum = 1, pwmFreq = 1000, dutyCycle = 100, moveSeconds = 4)
testStopMotor(motorDriverDictNum = 2, motorNum = 1)
'''
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
#
# *** Vehicle Level Config and Functions ***
vehicleDict01 = {
'MOTOR_DRIVER_DICT_NUM': 2,
}
vehicleDictDict = {
'1': vehicleDict01,
'2': vehicleDict01,
}
# *** Vehicle and Wheel Functions ***
def setupVehicle(vehicleNum):
motorDriverDictNum = vehicleDictDict[str(vehicleNum)]['MOTOR_DRIVER_DICT_NUM']
frontLeftMotorDict = setupMotor(motorDriverDictNum, 1)
frontRightMotorDict = setupMotor(motorDriverDictNum, 2)
motorDictDict = {'FRONT_LEFT_MOTOR': frontLeftMotorDict, 'FRONT_RIGHT_MOTOR': frontRightMotorDict}
return motorDictDict
def moveVehicleMotorListForwardHoldTime(vehicleNum, holdTime):
motorDictDict = setupVehicle(vehicleNum)
frontLeftMotorConfigDict = motorDictDict['FRONT_LEFT_MOTOR']['MOTOR_CONFIG_DICT']
frontRightMotorConfigDict = motorDictDict['FRONT_RIGHT_MOTOR']['MOTOR_CONFIG_DICT']
motorConfigDictList = [frontLeftMotorConfigDict, frontRightMotorConfigDict]
for motorConfigDict in motorConfigDictList:
moveMotorForwardNonStop(motorConfigDict)
utime.sleep(holdTime)
for motorConfigDict in motorConfigDictList:
stopMotor(motorConfigDict)
return
def moveVehicleMotorListBackwardHoldTime(vehicleNum, holdTime):
motorDictDict = setupVehicle(vehicleNum)
frontLeftMotorConfigDict = motorDictDict['FRONT_LEFT_MOTOR']['MOTOR_CONFIG_DICT']
frontRightMotorConfigDict = motorDictDict['FRONT_RIGHT_MOTOR']['MOTOR_CONFIG_DICT']
motorConfigDictList = [frontLeftMotorConfigDict, frontRightMotorConfigDict]
for motorConfigDict in motorConfigDictList:
moveMotorBackwardNonStop(motorConfigDict)
utime.sleep(holdTime)
for motorConfigDict in motorConfigDictList:
stopMotor(motorConfigDict)
return
def turnTwoMotorsLeftHoldTime(frontLeftMotorConfigDict, frontReghtConfigDict, holdTime):
moveMotorForwardNonStop(frontLeftMotorConfigDict)
moveMotorBackward(frontRightMotorConfigDict)
utime.sleep(holdTime)
stopMotor(frontLeftMotorConfigDict)
stopMotor(frontRightMotorConfigDict)
return
def turnVehicleLeftHoldTime(vehicleNum, holdTime):
motorDictDict = setupVehicle(vehicleNum)
frontLeftMotorConfigDict = motorDictDict['FRONT_LEFT_MOTOR']['MOTOR_CONFIG_DICT']
frontRightMotorConfigDict = motorDictDict['FRONT_RIGHT_MOTOR']['MOTOR_CONFIG_DICT']
moveMotorForwardNonStop(frontLeftMotorConfigDict)
moveMotorBackwardNonStop(frontRightMotorConfigDict)
utime.sleep(holdTime)
stopMotor(frontLeftMotorConfigDict)
stopMotor(frontRightMotorConfigDict)
return
def turnVehicleRightHoldTime(vehicleNum, holdTime):
motorDictDict = setupVehicle(vehicleNum)
frontLeftMotorConfigDict = motorDictDict['FRONT_LEFT_MOTOR']['MOTOR_CONFIG_DICT']
frontRightMotorConfigDict = motorDictDict['FRONT_RIGHT_MOTOR']['MOTOR_CONFIG_DICT']
moveMotorBackwardNonStop(frontLeftMotorConfigDict)
moveMotorForwardNonStop(frontRightMotorConfigDict)
utime.sleep(holdTime)
stopMotor(frontLeftMotorConfigDict)
stopMotor(frontRightMotorConfigDict)
return
# *** Test Functions ***
def testMoveVehicleMotorListForwardHoldTime():
moveVehicleMotorListForwardHoldTime(vehicleNum = 1, holdTime = 4)
return
def testMoveVehicleMotorListBackwardHoldTime():
moveVehicleMotorListBackwardHoldTime(vehicleNum = 1, holdTime = 4)
return
def testTurnVehicleLeftHoldTime():
turnVehicleLeftHoldTime(vehicleNum = 1, holdTime = 4)
return
def testTurnVehicleRightHoldTime():
turnVehicleRightHoldTime(vehicleNum = 1, holdTime = 4)
return
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# *** Main Tests ***
# * test move vehicle forward and backward, turn vehicle left and right
testMoveVehicleMotorListForwardHoldTime() # move forward 4 seconds
testMoveVehicleMotorListBackwardHoldTime() # move backward 4 seconds
testTurnVehicleLeftHoldTime() # turn left 4 secopnds
testTurnVehicleRightHoldTime() # turn right 4 seconds
# End
Now the youtube.

How to sync the two motors
We can see that the two motors do not sync, in the sense that the two wheels, each with the white stripe (cable tie), should move at the same speed.
In other words, if they start being adjacent to each other, they should always stay adjacent after any number of revolutions, forward or backward. And for turning left and right, they should go opposite direction, but stay adjacent again (for a split second) after one revolution.
I have not yet any solid idea of how to do the sync. It would be nice if any interested readers can reply with suggestions.
My first version of interrupt function works OK, but only for one motor. Now I am trying to modify it for use in 2WD and 4WD. The first draft is listed below.
# *** Interrupt Functions - Draft v0.1 2021sep06hkt1632 ***
# Design Notes
# 1. I am drafting the interrupt functions for 2WD, scalable to 4WD
# 2. / to continue, ...
def setupMotorIntCallBacks(VehicleNum = 1):
# draft only!!!
#motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
#motorStateDict = motorDict['MOTOR_STATE_DICT']
#motorConfigDict['Encode'].irq(encodeIntCallBack, Pin.IRQ_FALLING)
return
def motorEncodeIntCallBack1(pin):
global motorEncodeIntCount1
motorEncodeIntCount1 = motorEncodeIntCount1 + 1
return
def motorEncodeIntCallBack2(pin):
global motorEncodeIntCount2
motorEncodeIntCount2 = motorEncodeIntCount2 + 1
return
def motorEncodeIntCallBack3(pin):
global motorEncodeIntCount3
motorEncodeIntCount3 = motorEncodeIntCount3 + 1
return
def motorEncodeIntCallBack4(pin):
global motorEncodeInt4
motorEncodeIntCount4 = motorEncodeIntCount4 + 1
return
def readMotorEncodeIntEventCount1(motorDict, countTime):
global motorEncodeInt1
return motorEncodeInt1
def readMotorEncodeIntEventCount2(motorDict, countTime):
global motorEncodeInt2
return motorEncodeInt2
def readMotorEncodeIntEventCount3(motorDict, countTime):
global motorEncodeInt3
return motorEncodeInt3
def readMotorEncodeIntEventCount4(motorDict, countTime):
global motorEncodeInt4
return motorEncodeInt4
I am hitting the forum’s 32k limit. So I am making another reply to move on, …

I am drafting a test function to proving the concept of:
- Using a list of two interrupt event counts of this 2WD (later 4 counts for 4WD).
- Using only one callback function for 2WD’s two interrupt pins.
# *** Interrupt Functions ***
# *** Interrupt Event Variables and Service Routines ***
# *** Setup Motor and Vehicle ***
def setupMotorV2(motorDriverDictNum, motorNum):
motorDriverDict = motorDriverDictDict[str(motorDriverDictNum)] # Get driver dict
driverStandBy = Pin(motorDriverDict['STANDBY'], Pin.OUT) # create driverStandBy pin object
motorIn1 = Pin(motorDriverDict[str(motorNum)]['IN1'], Pin.OUT) # Create Motor # motorNum In1 pin object
motorIn2 = Pin(motorDriverDict[str(motorNum)]['IN2'], Pin.OUT) # Create Motor # motorNum In2 pin object
motorPwm = PWM(Pin(motorDriverDict[str(motorNum)]['PWM'])) # Create Motor # motorNum Pwm pin object
motorEncode = Pin(motorDriverDict[str(motorNum)]['ENCODE'], Pin.IN, Pin.PULL_DOWN) # Create Motor # motorNum Encode pin object
motorPwmFreq = motorDriverDict[str(motorNum)]['DEFAULT_PWM_FREQ']
motorDutyCycle = motorDriverDict[str(motorNum)]['DEFAULT_DUTY_CYCLE']
motorEncodeIntCount = 0
motorConfigDict = {'StdBy': driverStandBy, 'In1': motorIn1, 'In2': motorIn2, 'Pwm': motorPwm, 'Encode': motorEncode}
motorConfigDict['StdBy'].high() # enable motor driver normal operation, (low = disable)
motorConfigDict['Pwm'].freq(motorPwmFreq) # setup frequency
motorConfigDict['Pwm'].duty_u16(int(65536 / 100) * motorDutyCycle) # and duty cycle
motorStateDict = {'PwmFreq': motorPwmFreq, 'DutyCycle': motorDutyCycle, 'MotorEncodeIntCount': motorEncodeIntCount}
motorDict = {'MOTOR_CONFIG_DICT': motorConfigDict, 'MOTOR_STATE_DICT': motorStateDict}
stopMotor(motorConfigDict)
return motorDict
def setupVehicleV2(vehicleNum):
print(' setupVehicle(), ...')
motorDriverDictNum = vehicleDictDict[str(vehicleNum)]['MOTOR_DRIVER_DICT_NUM']
frontLeftMotorDict = setupMotorV2(motorDriverDictNum, 1)
frontRightMotorDict = setupMotorV2(motorDriverDictNum, 2)
frontLeftMotorInterruptPin = frontLeftMotorDict['MOTOR_CONFIG_DICT']['Encode']
frontRightMotorInterruptPin = frontRightMotorDict['MOTOR_CONFIG_DICT']['Encode']
motorInterruptPinList = [frontLeftMotorInterruptPin, frontRightMotorInterruptPin]
vehicleDict = {'FRONT_LEFT_MOTOR': frontLeftMotorDict, 'FRONT_RIGHT_MOTOR': frontRightMotorDict, 'INTERRUPT_PIN_LIST': motorInterruptPinList}
return vehicleDict
def testSyncTwoVehicleWheels():
print('testSyncTwoVehicleWheels(), ...')
# *** This function reads one of the interrupt count list ***
def readMotorEncodeIntCount(countNum):
return motorEncodeIntCount[countNum]
# *** motorEncodeCallBack ***
# Notes:
# This callback function is a bit too clever to understand. All motor interrupt pins will trigger this callback.
# The callback will find which interrupt pin interrupts, then increment the corresponding element of the int count list.
def motorEncodeIntCallBack(pin):
index = interruptPinList.index(pin)
motorEncodeIntCountList[index] += 1
return
vehicleDict = setupVehicleV2(vehicleNum = 1)
vehicleDict['INTERRUPT_PIN_LIST'][0].irq(motorEncodeIntCallBack, Pin.IRQ_FALLING)
vehicleDict['INTERRUPT_PIN_LIST'][1].irq(motorEncodeIntCallBack, Pin.IRQ_FALLING)
#print(' motorEncodeIntServiceRoutine[2] =', motorEncodeIntCountList[2])
return
# *** Main Tests ***
#testMoveVehicleForwardBackwardTurnLeftTurnRight()
testSyncTwoVehicleWheels()
# End
I was jealous that PiTop4 can use mpu6050 gesture to control a robot. This morning I read how to do it. So I might try later to use my smart phone to control my smart robot, to say, first walk in a straight line.
Raspberry Pi Pico Controls Robot with Smartphone Accelerometer – Ash Hill, 2021sep07Tom’s Hardware – 6 Sep 21

Raspberry Pi Pico Controls Robot with Smartphone Accelerometer
It’s like Kirby Tilt and Tumble but without Kirby and your Game Boy is a phone.
Raspberry Pi: Python Libraries for I2C, SPI, UART – Sebastian Günther, 2021sep06DEV Community

Raspberry Pi: Python Libraries for I2C, SPI, UART
The Raspberry Pi is one of the most popular single board computers for hobbyists. Its 40 Pins support…
I feel jealous that some smart guy has a smart 4WD, while mine is only a stupid looking 2WD, which should damage my reputation. So I am stalling my 2WD project and go build a smart 4WD. Stay tuned. See you later.four_wheel_drive_2021sep07021192×751 229 KBReply
Categories: Uncategorized