Introduction
This is Part 2 of the Project with the same title.
Summary of Part 1
Part 1 microPython program now has 4 python modules:
-
Pico system Uart
-
HC12 RF xmit/recv
-
TB6612FNG 4WD motor driving
-
Pico system interrupt
# *** pico_4wd_v90.py - tlfong01, 2021nov19hkt1719 ***
# Brief Description
# 1. Smart 4WD based on Rpi Pico, TB6612FNG, DC/BLDC motors, 433MHz HC12, 2.6GHz BLE HC02, Androd smart phone with
# acceleromter and magnetometer
# Contents
# 1. Pico 4WD with TB6612 DC Motor Drivers and gear encoder motors N20, tt130, and TM310
# 1.1 Interrupt functions
# 1.2 DC motor function
# 2. Pico 4Wd with BLDC motors with built motor drivers (ie, TB6612FNG is not required
# 3. HC12 433MHz RF transceivers
# 3.1 uart loop back functions
# 3.2 HC12 transmit/receive echo functions
# 4. HC02 2.6GHz BLE slave modules
# 5. Integrating Parts 1, 2 with Parts 3, 4
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========
from machine import Pin, PWM
import utime
# *** Pico GP pin assignments ***
uart0TxDNum = 0 # HC12 #1 TxD
uart0RdDNum = 1 # HC12 #2 RxD
hc12Setup1 = 2 # Reserved for SPI0 Sck
hc12Setup2 = 3 # Reserved for SPI0 Tx
i2c0Sda = 4 # Reserved for SPI0 Rx
i2c0Scl = 5 # Reserved for SPI0 Csn
# *** PWM Pins ***
aPwmPinNum0 = 6 #0
bPwmPinNum0 = 7 #1
uart1TxdNum = 8 # HC12 #2 TxD
uart1RxdNum = 9 # HC12 #2 RxD
aPwmPinNum1 = 11 #2
bPwmPinNum1 = 10 #3
# *** Inrerrupt Pins ***
intPinNum0 = 12 #4
intPinNum1 = 13 #5
intPinNum2 = 14 #6
intPinNum3 = 15 #7
# *** Motor Driver Control Pins (TB6612FNG) ***
stdByPinNum0 = 16 #8
stdByPinNum1 = 17 #9
aIn1PinNum0 = 18 #10
aIn2PinNum0 = 19 #11
bIn1PinNum0 = 20 #12
bIn2PinNum0 = 21 #13
aIn1PinNum1 = 27 #14
aIn2PinNum1 = 28 #15
bIn1PinNum1 = 22 #16
bIn2PinNum1 = 26 #17
# *** Interrupt Pin Dicts ***
intGpPinNumDict = {'0': intPinNum0,
'1': intPinNum1,
'2': intPinNum2,
'3': intPinNum3,
}
intPinNumList = [intPinNum0, intPinNum1, intPinNum2, intPinNum3]
# Comments
# 1. There are 4 GP pins to read interrupts: intPinNum0, inPinNum1, intPinNum2, intPinNum3.
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========
# *** Sleep time dicts ***
secondsDict = {'OneSecond' : 1,
'TwoSeconds' : 2,
'FourSeconds' : 4,
'TenSeconds' : 10,
'SixtySeconds' : 60,
'ThreeMinutes' : 180,
}
def hold(secondsName):
utime.sleep(secondsDict[secondsName])
return
# Comments
# 1. Hold function is friendly version of utime.sleep.
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========
# *** Interrupt global variables and dicts ***
global intCount0
global intCount1
global intCount2
global intCount3
intCount0 = 0
intCount1 = 0
intCount2 = 0
intCount3 = 0
intCountDict = {
'0': intCount0,
'1': intCount1,
'2': intCount2,
'3': intCount3,
}
# Comments
# 1. There are four global variable to hold interrupt event counts.
# 2. For this 4WD, the four interrupt signals are the four motor's rotary encoder output signals.
# *** Interrupt Callback Functions ***
def intCallBack0(pin):
global intCount0
intCount0 = intCount0 + 1
return
def intCallBack1(pin):
global intCount1
intCount1 = intCount1 + 1
return
def intCallBack2(pin):
global intCount2
intCount2 = intCount2 + 1
return
def intCallBack3(pin):
global intCount3
intCount3 = intCount3 + 1
return
intCallBackDict = {
'0': intCallBack0,
'1': intCallBack1,
'2': intCallBack2,
'3': intCallBack3,
}
def countIntPinIntPeriod(intPinNum, countPeriod):
global intCount0
global intCount1
global intCount2
global intCount3
intCount0 = 0
intCount1 = 0
intCount2 = 0
intCount3 = 0
utime.sleep(countPeriod)
if intPinNum == 0:
intCount = intCount0
elif intPinNum == 1:
intCount = intCount1
elif intPinNum == 2:
intCount = intCount2
else:
intCount = intCount3
return intCount
def countIntPinNumListIntPeriod(intPinNumList, countPeriod):
intCountList = [0] * len(intPinNumList)
for index in range(len(intPinNumList)):
intCountList[index] = countIntPinIntPeriod(intPinNumList[index], countPeriod)
return intCountList
# Comments
# 1. countIntPinIntPeriod(intPinNum, countPeriod) is to count the number of interrupts at the interrupt pin denoted by the
# interrupt pin number.
# *** Test functions ***
def repeatCountIntPinNumListIntPeriod(intPinNumList, countPeriod, pauseTime, repeatTimes):
print('\n countIntPinNumListIntPeriod()')
intGpPinNumList = [0] * len(intPinNumList)
for index in range(len(intGpPinNumList)):
intGpPinNumList[index] = intGpPinNumDict[str(index)]
print(' intPinNumList =', intPinNumList)
print(' intGpPinNumList =', intGpPinNumList)
print(' countPeriod (seconds) =', countPeriod)
print(' pauseTime (seconds) =', pauseTime)
print(' repeat count times =', repeatTimes)
print('')
for count in range(repeatTimes):
ppsList = countIntPinNumListIntPeriod(intPinNumList, countPeriod)
print(' countList =', ppsList, end = '')
print(' , min ', min(ppsList), end = '')
print(' , max ', max(ppsList), end = '')
print(' , dif ', max(ppsList) - min(ppsList), end = '')
print(' , avg ', int(sum(ppsList) / len(ppsList)))
utime.sleep(pauseTime)
return
# Comments
# 1. repeatCountIntPinNumListIntPeriod(intPinNumList, countPeriod, pauseTime, repeatTimes)
# repeatedly counts and prints tinterrupt events in countPeriod and p
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========
# *** Part 3 - TB6612FNG Motor Driver Functions ***
# Comments
# 1. This 4WD uses two TB6612FNG DC motor drivers, each with two driver channels, with a total of 4 channels for four motors.
# 2. BLDC motor have built in motor drivers, therefor is not handled by TB6612 motor driver.
defaultDirection = 'Forward'
defaultSpeed = 'VertHighSpeed'
defaultPwmFreq = 1000
defaultDutyCycle = 90
dutyCycleDict = {
'VeryVerySlow' : 95,
'VeryFast' : 90,
'Fast' : 80,
'Normal' : 50,
'Slow' : 40,
'VerySlow' : 30,
'VeryVerySlow' : 25,
}
motorConfigDictDict = \
{
'0': {'MotorDriverNum': 0, 'ChannelNum': 0},
'1': {'MotorDriverNum': 0, 'ChannelNum': 1},
'2': {'MotorDriverNum': 1, 'ChannelNum': 0},
'3': {'MotorDriverNum': 1, 'ChannelNum': 1},
}
# Comment
# 1. There are four DC motors, each denoted/represented by a Motor Config Dictionary.
# 2. A motor config dict has two elementa:
# (a) MotorDriverNum which the the number of one of the two TB6612FNG motor drivers.
# (b) Channel Number, denoting each of the two channel of the motor driver.
# 3. motorConfigDictList01 = motorConfigDictList_00_01_10_11 = the list of all four motor confict dictionaries.
# 4. motorConfigDictListDict is the Dict of motorConfigDictLists (only one such dict list for now)
motorDriverGpPinNumDict = { \
'0': {'StdByPinNum' : stdByPinNum0,
'0' : {'In1PinNum' : aIn1PinNum0,
'In2PinNum' : aIn2PinNum0,
'PwmPinNum' : aPwmPinNum0,
'PwmFreq' : defaultPwmFreq,
'DutyCycle' : defaultDutyCycle,
'IntPinNum' : intPinNum0,
'IntPinCallBack' : intCallBack0,
},
'1' : {'In1PinNum' : bIn1PinNum0,
'In2PinNum' : bIn2PinNum0,
'PwmPinNum' : bPwmPinNum0,
'PwmFreq' : defaultPwmFreq,
'DutyCycle' : defaultDutyCycle,
'IntPinNum' : intPinNum1,
'IntPinCallBack' : intCallBack1,
},
},
'1': {'StdByPinNum' : stdByPinNum1,
'0' : {'In1PinNum' : aIn1PinNum1,
'In2PinNum' : aIn2PinNum1,
'PwmPinNum' : aPwmPinNum1,
'PwmFreq' : defaultPwmFreq,
'DutyCycle' : defaultDutyCycle,
'IntPinNum' : intPinNum2,
'IntPinCallBack' : intCallBack2,
},
'1' : {'In1PinNum' : bIn1PinNum1,
'In2PinNum' : bIn2PinNum1,
'PwmPinNum' : bPwmPinNum1,
'PwmFreq' : defaultPwmFreq,
'DutyCycle' : defaultDutyCycle,
'IntPinNum' : intPinNum3,
'IntPinCallBack' : intCallBack3
},
},
}
# Comment
# 1. motorDriverGpPinNumDict specifies
# (a) the GP pin numbers for the two TB6612FNG motor drivers ecah with two channels.
# (b) the default values such as PWM frequency, duty cycles
def setupMotor(motorNum):
motorConfigDict = motorConfigDictDict[str(motorNum)]
motorDriverNum = motorConfigDict['MotorDriverNum']
channelNum = motorConfigDict['ChannelNum']
stdByPinNum = motorDriverGpPinNumDict[str(motorDriverNum)]['StdByPinNum']
in1PinNum = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['In1PinNum']
in2PinNum = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['In2PinNum']
pwmPinNum = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmPinNum']
pwmFreq = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmFreq']
dutyCycle = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['DutyCycle']
intPinNum = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['IntPinNum']
intPinCallBack = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['IntPinCallBack']
# *** Motor Driver Control Pin Setup ***
stdByPin = Pin(stdByPinNum, Pin.OUT)
in1Pin = Pin(in1PinNum, Pin.OUT)
in2Pin = Pin(in2PinNum, Pin.OUT)
intPin = Pin(intPinNum, Pin.IN, Pin.PULL_DOWN)
stdByPin.high()
in1Pin.low()
in2Pin.low()
# *** PWM Pin Setup ***
pwmPin = PWM(Pin(pwmPinNum))
pwmPin.freq(pwmFreq)
u16DutyCycle = int((dutyCycle / 100) * 65536)
pwmPin.duty_u16(u16DutyCycle)
# *** Interrupt Pin Setup ***
intPin.irq(intPinCallBack, Pin.IRQ_FALLING)
# *** Motor Control Dict ***
motorControlDict = {'StdByPin': stdByPin,
'In1Pin' : in1Pin,
'In2Pin' : in2Pin,
'PwmPin' : pwmPin,
'IntPin' : intPin,
}
motorStatusDict = {'Direction' : defaultDirection,
'Speed' : defaultSpeed,
'PwmFrequency': defaultPwmFreq,
'DutyCycle' : defaultDutyCycle,
}
motorDict = {'MotorConfictDict' : motorConfigDict,
'MotorControlDict' : motorControlDict,
'MotorStatusDict' : motorStatusDict
}
return motorDict
# Comments
# 1. setupMotor(motorNum) perfroms the following things:
# 1.1 setup and intiralize control/pwm/interrupt pin objects from controlPinNum controlPin objects
# 1.2 setup interrupt call back functions
# 1.3 returns motorControlDict which is a dictionary of the motor's pin objects (stdBy, Input, Pwm, Interrupt)
def setupMotorList(motorNumList):
motorControlDictList = [0] * len(motorNumList)
for motorNum in motorNumList:
motorControlDict = setupMotor(motorNum)
motorControlDictList[motorNum] = motorControlDict
return motorControlDictList
def setupMotorDirection(motorControlDict, directionName):
if directionName =='Forward':
motorControlDict['In1Pin'].low()
motorControlDict['In2Pin'].high()
elif directionName == 'Backward':
motorControlDict['In1Pin'].high()
motorControlDict['In2Pin'].low()
return
def setupMotorSpeed(motorControlDict, speedName):
pwmPin = motorControlDict['PwmPin']
dutyCycle = dutyCycleDict[speedName]
pwmPin.duty_u16(int((dutyCycle / 100) * 65536) )
return
def moveMotorDirectionSpeed(motorControlDict, directionName, speedName):
moveMotorDirection(motorControlDict, directionName)
moveMotorSpeed(motorControlDict, speedName)
return
def moveMotorDirectionSpeedList(motorControlDictList, directionName, speedName):
for motorControlDict in motorControlDictList:
moveMotorDirectionSpeed(motorControlDict, directionName, speedName)
return
def stopMotor(motorControlDict):
motorControlDict['In1Pin'].low()
motorControlDict['In2Pin'].low()
return
def moveMotorForward(motorControlDict):
motorControlDict['In1Pin'].high()
motorControlDict['In2Pin'].low()
return
def stopMotorList(motorControlDictList):
for motorControlDict in motorControlDictList:
stopMotor(motorControlDict)
return
# *** Test setup/stop/move motor functions ***
def testSetupMotor(motorNum):
print('Begin testSetupMotor(), ', 'motorNum =', motorNum)
motorControlDict = setupMotor(motorNum)['MotorControlDict']
stopMotor(motorControlDict)
print('End testSetupMotor().')
return
def testSetupMotorList(motorNumList):
for motorNum in motorNumList:
testSetupMotor(motorNum)
return
def testSetupMoveMotor(motorNum, directionName, speedName, holdSecondsName):
print('Begiun testSetupMoveMotor(), ', 'motorNum =', motorNum)
motorDict = setupMotor(motorNum)
motorControlDict = motorDict['MotorControlDict']
stopMotor(motorControlDict)
setupMotorDirection(motorControlDict, directionName)
setupMotorSpeed(motorControlDict, speedName)
hold(holdSecondsName)
stopMotor(motorControlDict)
print('End testSetupMoveMotor().')
return
def testSetupMoveMotorList(motorNumList, directionName, speedName, holdSecondsName):
print('Begiun testSetupMoveMotorNumList(), ...')
for motorNum in motorNumList:
motorDict = setupMotor(motorNum)
motorControlDict = motorDict['MotorControlDict']
stopMotor(motorControlDict)
setupMotorDirection(motorControlDict, directionName)
setupMotorSpeed(motorControlDict, speedName)
hold(holdSecondsName)
stopMotor(motorControlDict)
print('End testSetupMoveMotorNumList().')
return
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
'''
# *** BLDC Config/Fuctnions ***
dutyCycleDictBldc = {
'VeryVerySlow' : 95,
'VeryFast' : 90,
'Fast' : 80,
'Normal' : 50,
'Slow' : 40,
'VerySlow' : 30,
'VeryVerySlow' : 25,
}
def changeBldcMotorSpeed(motorControlDict, speedName):
pwmPin = motorControlDict['PwmPin']
dutyCycle = dutyCycleDict[speedName]
pwmPin.duty_u16(int((dutyCycle / 100) * 65536) )
return
def setupBldcMotor(motorConfigDict):
motorDriverNum = motorConfigDict['MotorDriverNum']
channelNum = motorConfigDict['ChannelNum']
stdByPinNum = motorDriverGpPinNumDict[str(motorDriverNum)]['StdByPinNum']
in1PinNum = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['In1PinNum']
in2PinNum = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['In2PinNum']
pwmPinNum = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmPinNum']
pwmFreq = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmFreq']
dutyCycle = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['DutyCycle']
intPinNum = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['IntPinNum']
intPinCallBack = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['IntPinCallBack']
# *** Motor Driver Control Pin Setup ***
stdByPin = Pin(stdByPinNum, Pin.OUT)
in1Pin = Pin(in1PinNum, Pin.OUT)
in2Pin = Pin(in2PinNum, Pin.OUT)
intPin = Pin(intPinNum, Pin.IN, Pin.PULL_DOWN)
stdByPin.high()
in1Pin.low()
in2Pin.high()
# *** PWM Pin Setup ***
pwmPin = PWM(Pin(pwmPinNum))
pwmPin.freq(pwmFreq)
u16DutyCycle = int((dutyCycle / 100) * 65536)
pwmPin.duty_u16(u16DutyCycle)
# *** Interrupt Pin Setup ***
intPin.irq(intPinCallBack, Pin.IRQ_FALLING)
# *** Motor Control Dict ***
motorControlDictBldc = {'StdByPin': stdByPin,
'In1Pin' : in1Pin,
'In2Pin' : in2Pin,
'PwmPin' : pwmPin,
'IntPin' : intPin,
}
# Test functions
def testBldcMotor00():
print(' Begin testBldcMotor00(), ...')
motorConfigDict = {'MotorDriverNum': 0, 'ChannelNum': 0}
setupBldcMotor(motorConfigDict)
hold('TwoSeconds')
changeBldcMotorSpeed(motorConfigDict, 'VeryFast')
hold('TwoSeconds')
utime.sleep(2)
changeBldcMotorDirection(motorConfigDict, 'CCW')
utime.sleep(2)
changeBldcMotorDirection(motorConfigDict, 'CW')
changeBldcMotorSpeed(motorConfigDict, 'VerySlow')
utime.sleep(2)
print(' End testSetupMotor00(), ...')
return
# *** Sample test function call
#testBldcMotor00()
'''
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========
''' Old main test sample outputs
*** Sample Output tlfong01 2021oct11hkt1955 ***
>>> %Run -c $EDITOR_CONTENT
Begin testSetupMoveMotorList(), ...
After 2 seconds, ...
countIntPinNumListIntPeriod()
intPinNumList = [0, 1, 2, 3]
intGpPinNumList = [4, 5, 6, 7]
countPeriod (seconds) = 0.1
pauseTime (seconds) = 0.1
repeat count times = 10
countList = [296, 219, 291, 205] , min 205 , max 296 , dif 91 , avg 252
countList = [286, 215, 295, 208] , min 208 , max 295 , dif 87 , avg 251
countList = [288, 217, 300, 213] , min 213 , max 300 , dif 87 , avg 254
countList = [301, 223, 298, 207] , min 207 , max 301 , dif 94 , avg 257
countList = [271, 223, 308, 207] , min 207 , max 308 , dif 101 , avg 252
countList = [287, 223, 305, 203] , min 203 , max 305 , dif 102 , avg 254
countList = [277, 233, 306, 226] , min 226 , max 306 , dif 80 , avg 260
countList = [282, 240, 299, 222] , min 222 , max 299 , dif 77 , avg 260
countList = [294, 225, 307, 209] , min 209 , max 307 , dif 98 , avg 258
countList = [299, 223, 303, 229] , min 223 , max 303 , dif 80 , avg 263
End testSetupMoveMotorList(), ...
>>>
'''
# *** Main Test ***
# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========
# *** Main ***
#testSetupMotor(motorNum = 0)
#testSetupMotorList(motorNumList = [0, 1, 2, 3])
#testSetupMoveMotor(motorNum = 0, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')
#testSetupMoveMotor(motorNum = 1, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')
#testSetupMoveMotor(motorNum = 2, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')
#testSetupMoveMotor(motorNum = 3, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')
testSetupMoveMotorList([0, 1, 2, 3], 'Forward', 'VeryFast', 'TwoSeconds')
# *** End ***
'''
>>> %Run -c $EDITOR_CONTENT
Begiun testSetupMoveMotorNumList(), ...
End testSetupMoveMotorNumList().
>>>
'''
''' Sample output tlfong01 2021nov17hkt2033
>>> %Run -c $EDITOR_CONTENT
Begin setupMotor(), ... tlfong01 2021nov1701
Begin testSetupMoveMotorList(), ...
After 2 seconds, ...
countIntPinNumListIntPeriod()
intPinNumList = [0, 1, 2, 3]
intGpPinNumList = [12, 13, 14, 15]
countPeriod (seconds) = 0.1
pauseTime (seconds) = 0.1
repeat count times = 10
countList = [0, 0, 0, 0] , min 0 , max 0 , dif 0 , avg 0
countList = [0, 0, 0, 0] , min 0 , max 0 , dif 0 , avg 0
countList = [0, 0, 0, 0] , min 0 , max 0 , dif 0 , avg 0
countList = [0, 0, 0, 0] , min 0 , max 0 , dif 0 , avg 0
countList = [0, 0, 0, 0] , min 0 , max 0 , dif 0 , avg 0
countList = [0, 0, 0, 0] , min 0 , max 0 , dif 0 , avg 0
countList = [0, 0, 0, 0] , min 0 , max 0 , dif 0 , avg 0
countList = [0, 0, 0, 0] , min 0 , max 0 , dif 0 , avg 0
countList = [0, 0, 0, 0] , min 0 , max 0 , dif 0 , avg 0
countList = [0, 0, 0, 0] , min 0 , max 0 , dif 0 , avg 0
End testSetupMoveMotorList(), ...
End setupMotor(), ...
>>>
'''
/ to continue, …