Making a Rpi Pico Based Smart Vehicle

Calibrating TM310 motors speed vs PWM duty cycle

Now I am using pico’s GP0, 1, 2, 3 to output 4 PWM signals to the two TB6612FNG motor drivers’s 4 motor driving channels, and check out the corresponding motor speed by detecting the encoder’s A signals and do the pps (pulse per second) to rpm calculation by using Pico.


Notes:

  1. C = GP 0, 1, 2, 3 PWM output pins

  2. D = GP 4, 5, 6, 7 Interrupt input pins

  3. E = 4 x TM301 motor encoder A signals

  4. F = 4 x TB6612FNG PWM input control signals

  5. A, B = 2 x TB6612FNG’s other control signals manually jumpered to Vcc and Gnd.

  6. G, H = 2 x TB6612 motor driver modules


Testing PWM Duty Cycle 50%, 10%, 90% OK

I am using the following function calls to generate signals of duty cycle 50%, 10%, and 90% and found all is well. Next step is to calibrate duty cycle vs motor speed.

# testSetupPwmPinList(pwmDutyCycle = 50)
# testSetupPwmPinList(pwmDutyCycle = 10)
# testSetupPwmPinList(pwmDutyCycle = 90)


The full listing of code.

# *** pwm_int_37.py - pwm and interrupt testing, tlfong01, 2021oct03hkt2110 ***

from machine import Pin, PWM
import utime

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# Conents
#
# Part 1 - PWM Functions
#   1.1 Using PWM pin to fade in and fade out the system LED
#   1.2 Using GP 0, 1, 2, 3 pins' PWM signalsto control the speed of TB6612FNG driving TM310 DC motor

# Part 2 - Interrupt Functions
#   2.1 Using GP4, 5, 6, 7 input pins to detect and count mtor encoder A signals and calculate motor speed

# *** Part 1 - PWM Functions ***

def pwmSystemLed():
    systemLedPinNum = 25
    pwmPin = PWM(Pin(systemLedPinNum))
    pwmPin.freq(1000)
    for count in range(4):
        for dutyCycle in range(65025):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
        for dutyCycle in range(65025, 0, -1):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
            return           

def testPwmSystemLed():
    print('testPwmSystemLed(), ...')
    print('  System LED now fades in and out a couple of times')
    pwmSystemLed()
    print('  End of test.')
    return

# *** Sample Test ***
#testPwmSystemLed()

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Setup 4 PWM Pins ***
# Notes:
#   1. Setting up GP 0, 1, 2, 3 as pwm pins at 1 kHz, 50% duty cycle
#   2. Connecting the pwm pins to the pwm inputs of TB6612FNG move the DC motor TM310.

# *** Pwm Pin Numbers and List ***

pwmPinNum0 = 0
pwmPinNum1 = 1
pwmPinNum2 = 2
pwmPinNum3 = 3

pwmPinNumList = [pwmPinNum0, pwmPinNum1, pwmPinNum2, pwmPinNum3]

# *** Pwm Pin Objects and List ***

pwmPin0 = PWM(Pin(pwmPinNum0))
pwmPin1 = PWM(Pin(pwmPinNum1))
pwmPin2 = PWM(Pin(pwmPinNum2))
pwmPin3 = PWM(Pin(pwmPinNum3))

pwmPinList01 = [pwmPin0, pwmPin1, pwmPin2, pwmPin3]

# *** Defualt Frequency and Duty Cycle ***

defaultPwmFreq         = 1000
defaultPwmDutyCycle    = 50

# *** Initializing Pwm Pin Objects and List ***

def setPwmFreq(pwmPin, pwmFreq):
    pwmPin.freq(pwmFreq)
    return               

def setPwmDutyCycle(pwmPin, dutyCycle):
    u16DutyCycle = int((dutyCycle / 100) * 65536)  
    pwmPin.duty_u16(u16DutyCycle)
    return

def setupPwmPinList(pwmPinList, pwmFreq, pwmDutyCycle):
    print('  pwmFreq      =', pwmFreq)
    print('  pwmDutyCycle =', pwmDutyCycle)
    for pwmPin in pwmPinList:
        setPwmFreq(pwmPin, pwmFreq)
        setPwmDutyCycle(pwmPin, pwmDutyCycle)
    return            

def testSetupPwmPinList(pwmDutyCycle):
    setupPwmPinList(pwmPinList = pwmPinList01, pwmFreq = 1000, pwmDutyCycle = pwmDutyCycle) 
    return

# Sample test ***
#testSetupPwmPinList(pwmDutyCycle = 50)
#testSetupPwmPinList(pwmDutyCycle = 10)
testSetupPwmPinList(pwmDutyCycle = 90)

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# Interrupt functions for multiple (4) interrupt pins GP 4, 5, 6, 7 ***

intPinNum0 = 4
intPinNum1 = 5
intPinNum2 = 6
intPinNum3 = 7

intPinNumList = [intPinNum0, intPinNum1, intPinNum2, intPinNum3]

intPin0 = Pin(intPinNum0, Pin.IN, Pin.PULL_DOWN)
intPin1 = Pin(intPinNum1, Pin.IN, Pin.PULL_DOWN)
intPin2 = Pin(intPinNum2, Pin.IN, Pin.PULL_DOWN)
intPin3 = Pin(intPinNum3, Pin.IN, Pin.PULL_DOWN)

intPinDict = {
    '0': intPin0,
    '1': intPin1,
    '2': intPin2,
    '3': intPin3,
    }

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,
    }
    
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,    
    }

intPin0.irq(intCallBack0, Pin.IRQ_FALLING)
intPin1.irq(intCallBack1, Pin.IRQ_FALLING)
intPin2.irq(intCallBack2, Pin.IRQ_FALLING)
intPin3.irq(intCallBack3, Pin.IRQ_FALLING)

def measureIntPinIntSeconds(intPinNum, seconds):
    #intPin = intPinDict[str(intPinNum)]
    #intPin.irq(intCallBackDict[str(intPinNum)], Pin.IRQ_FALLING)

    global intCount0
    global intCount1
    global intCount2
    global intCount3
    
    intCount0 = 0
    intCount1 = 0
    intCount2 = 0
    intCount3 = 0

    utime.sleep(seconds)
 
    if intPinNum  == 0:
        newIntCount = intCount0
    elif intPinNum == 1:    
        newIntCount = intCount1
    elif intPinNum == 2:    
        newIntCount = intCount2
    else:    
        newIntCount = intCount3                
    return newIntCount    

def testMeasureIntPinIntSeconds(intPinNum, seconds):
    newIntCount = measureIntPinIntSeconds(intPinNum, seconds)
    
    print('\n', intPinNum, '          ',  end = '')
    print(newIntCount, '          ', end = '')
    print('{:.2f}'.format(newIntCount / 12), '          ', end = '')
    print('{:.2f}'.format((newIntCount / 12) / 90), '          ', end = '')    
    print('{:.2f}'.format(((newIntCount / 12) / 90) * 60), '          ', end = '')     
    return

def measureFourIntPinIntSeconds(intPinNumList):
    intCountList = [0, 0, 0, 0]   
    for count in range(len(intPinNumList)):
        intCountList[count] = measureIntPinIntSeconds(intPinNumList[count], 1)
    return intCountList

# *** Test functions ***

def testMeasureQuadInterrupts():
    print('\ntestMeasureQuadInterrupts(), ...')
    print('\n ------------------------------------------------------------------', end = '') 
    print('\n intPinNum   pps            1:1 rps          1:90 rps       rpm', end = '')
    print('\n ------------------------------------------------------------------', end = '')     
    testMeasureIntPinIntSeconds(intPinNum = 0, seconds = 1)
    testMeasureIntPinIntSeconds(intPinNum = 1, seconds = 1)
    testMeasureIntPinIntSeconds(intPinNum = 2, seconds = 1)
    testMeasureIntPinIntSeconds(intPinNum = 3, seconds = 1)
    print('\n ------------------------------------------------------------------', end = '')      
    return

def testMeasureFourInterrupts(intPinNumList):
    ppsList             = measureFourIntPinIntSeconds(intPinNumList)
    print('ppsList      =', ppsList)
    print('minimum      =', min(ppsList))
    print('maximum      =', max(ppsList))
    print('average      =', int(sum(ppsList) / len(ppsList)))
    
    rpmList             = ppsList.copy()
    for count in range(len(rpmList)):
        rpmList[count] = int(((rpmList[count] / 12) / 90) * 60)                         
    
    print('\nrpmList      =', rpmList)
    print('minimum      =', min(rpmList))
    print('maximum      =', max(rpmList))
    print('average      =', int(sum(rpmList) / len(rpmList)))
    
    dpsList             = ppsList.copy()
    for count in range(len(dpsList)):
        dpsList[count] = float(((dpsList[count] / 12) / 90) * 3.14 * 6.3)
        
    print('\ndpsList      =', (dpsList))
    print('minimum      =', '{:.2f}'.format(min(dpsList)))
    print('maximum      =', '{:.2f}'.format(max(dpsList)))
    print('average      =', '{:.2f}'.format(float(sum(dpsList) / len(dpsList))))        
    
    return

# *** Main Tests ***

#testMeasureFourInterrupts([4, 5, 6, 7])

# *** End ***

# *** Sample Output tlfong01  2021oct0201 ***
'''
'''
# *** End of Sample Output ***

Measuring 4 PWMs vs 4 Speeds OK

Now I am using the setPWM and MeasureInterrupts to do PWM vs Speed and found things more or less OK, except minor things such as one wheel does not turn at duty cycle at 10%. So 20% dc seems to be the smallest to do practical experiments.

#testSetupPwmPinList(pwmDutyCycle = 50)
#testSetupPwmPinList(pwmDutyCycle = 90)
testSetupPwmPinList(pwmDutyCycle = 20)
testMeasureFourInterrupts([4, 5, 6, 7])

Below is a summary of the results. Full result and code listing is shown after that.

>>> %Run -c $EDITOR_CONTENT
testSetupPwmPinList(), ... tlfong01  2021oct04hkt1025
pwmFreq      = 1000

pwmDutyCycle = 50
ppsList      = [2391, 2401, 2391, 2396]
rpmList      = [132, 133, 132, 133]
dpsList      = [43.79516, 43.97832, 43.79516, 43.88674]

pwmDutyCycle = 90
ppsList      = [2796, 2874, 2883, 2859]
rpmList      = [155, 159, 160, 158]
dpsList      = [51.2134, 52.64211, 52.80696, 52.36735]

>>> %Run -c $EDITOR_CONTENT
pwmDutyCycle = 20
ppsList      = [1631, 1505, 1631, 1613]
rpmList      = [90, 83, 90, 89]
dpsList      = [29.87449, 27.56658, 29.87449, 29.54479]

pwmDutyCycle = 10
ppsList      = [1295, 1019, 941, 967]
rpmList      = [71, 56, 52, 53]
dpsList      = [23.72008, 18.66468, 17.23598, 17.71222]

# *** pwm_int_40.py - pwm and interrupt testing, tlfong01, 2021oct04hkt1037 ***

from machine import Pin, PWM
import utime

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# Conents
#
# Part 1 - Interrupt Functions
#   1.1 Using GP4, 5, 6, 7 input pins to detect and count mtor encoder A signals and calculate motor speed

# Part 2 - PWM Functions
#   2.1 Using PWM pin to fade in and fade out the system LED
#   2.2 Using GP 0, 1, 2, 3 pins' PWM signalsto control the speed of TB6612FNG driving TM310 DC motor

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# Interrupt functions for multiple (4) interrupt pins GP 4, 5, 6, 7 ***

intPinNum0 = 4
intPinNum1 = 5
intPinNum2 = 6
intPinNum3 = 7

intPinNumList = [intPinNum0, intPinNum1, intPinNum2, intPinNum3]

intPin0 = Pin(intPinNum0, Pin.IN, Pin.PULL_DOWN)
intPin1 = Pin(intPinNum1, Pin.IN, Pin.PULL_DOWN)
intPin2 = Pin(intPinNum2, Pin.IN, Pin.PULL_DOWN)
intPin3 = Pin(intPinNum3, Pin.IN, Pin.PULL_DOWN)

intPinDict = {
    '0': intPin0,
    '1': intPin1,
    '2': intPin2,
    '3': intPin3,
    }

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,
    }
    
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,    
    }

intPin0.irq(intCallBack0, Pin.IRQ_FALLING)
intPin1.irq(intCallBack1, Pin.IRQ_FALLING)
intPin2.irq(intCallBack2, Pin.IRQ_FALLING)
intPin3.irq(intCallBack3, Pin.IRQ_FALLING)

def measureIntPinIntSeconds(intPinNum, seconds):
    #intPin = intPinDict[str(intPinNum)]
    #intPin.irq(intCallBackDict[str(intPinNum)], Pin.IRQ_FALLING)

    global intCount0
    global intCount1
    global intCount2
    global intCount3
    
    intCount0 = 0
    intCount1 = 0
    intCount2 = 0
    intCount3 = 0

    utime.sleep(seconds)
 
    if intPinNum  == 0:
        newIntCount = intCount0
    elif intPinNum == 1:    
        newIntCount = intCount1
    elif intPinNum == 2:    
        newIntCount = intCount2
    else:    
        newIntCount = intCount3                
    return newIntCount    

def testMeasureIntPinIntSeconds(intPinNum, seconds):
    newIntCount = measureIntPinIntSeconds(intPinNum, seconds)
    
    print('\n', intPinNum, '          ',  end = '')
    print(newIntCount, '          ', end = '')
    print('{:.2f}'.format(newIntCount / 12), '          ', end = '')
    print('{:.2f}'.format((newIntCount / 12) / 90), '          ', end = '')    
    print('{:.2f}'.format(((newIntCount / 12) / 90) * 60), '          ', end = '')     
    return

def measureFourIntPinIntSeconds(intPinNumList):
    intCountList = [0, 0, 0, 0]   
    for count in range(len(intPinNumList)):
        intCountList[count] = measureIntPinIntSeconds(intPinNumList[count], 1)
    return intCountList

# *** Test functions ***

def testMeasureQuadInterrupts():
    print('\ntestMeasureQuadInterrupts(), ...')
    print('\n ------------------------------------------------------------------', end = '') 
    print('\n intPinNum   pps            1:1 rps          1:90 rps       rpm', end = '')
    print('\n ------------------------------------------------------------------', end = '')     
    testMeasureIntPinIntSeconds(intPinNum = 0, seconds = 1)
    testMeasureIntPinIntSeconds(intPinNum = 1, seconds = 1)
    testMeasureIntPinIntSeconds(intPinNum = 2, seconds = 1)
    testMeasureIntPinIntSeconds(intPinNum = 3, seconds = 1)
    print('\n ------------------------------------------------------------------', end = '')      
    return

def testMeasureFourInterrupts(intPinNumList):
    ppsList             = measureFourIntPinIntSeconds(intPinNumList)
    print('ppsList      =', ppsList)
    print('minimum      =', min(ppsList))
    print('maximum      =', max(ppsList))
    print('average      =', int(sum(ppsList) / len(ppsList)))
    
    rpmList             = ppsList.copy()
    for count in range(len(rpmList)):
        rpmList[count] = int(((rpmList[count] / 12) / 90) * 60)                         
    
    print('\nrpmList      =', rpmList)
    print('minimum      =', min(rpmList))
    print('maximum      =', max(rpmList))
    print('average      =', int(sum(rpmList) / len(rpmList)))
    
    dpsList             = ppsList.copy()
    for count in range(len(dpsList)):
        dpsList[count] = float(((dpsList[count] / 12) / 90) * 3.14 * 6.3)
        
    print('\ndpsList      =', (dpsList))
    print('minimum      =', '{:.2f}'.format(min(dpsList)))
    print('maximum      =', '{:.2f}'.format(max(dpsList)))
    print('average      =', '{:.2f}'.format(float(sum(dpsList) / len(dpsList))))        
    
    return

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 2 - PWM Functions ***

def pwmSystemLed():
    systemLedPinNum = 25
    pwmPin = PWM(Pin(systemLedPinNum))
    pwmPin.freq(1000)
    for count in range(4):
        for dutyCycle in range(65025):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
        for dutyCycle in range(65025, 0, -1):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
            return           

def testPwmSystemLed():
    print('testPwmSystemLed(), ...')
    print('  System LED now fades in and out a couple of times')
    pwmSystemLed()
    print('  End of test.')
    return

# *** Sample Test ***
#testPwmSystemLed()

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Setup 4 PWM Pins ***
# Notes:
#   1. Setting up GP 0, 1, 2, 3 as pwm pins at 1 kHz, 50% duty cycle
#   2. Connecting the pwm pins to the pwm inputs of TB6612FNG move the DC motor TM310.

# *** Pwm Pin Numbers and List ***

pwmPinNum0 = 0
pwmPinNum1 = 1
pwmPinNum2 = 2
pwmPinNum3 = 3

pwmPinNumList = [pwmPinNum0, pwmPinNum1, pwmPinNum2, pwmPinNum3]

# *** Pwm Pin Objects and List ***

pwmPin0 = PWM(Pin(pwmPinNum0))
pwmPin1 = PWM(Pin(pwmPinNum1))
pwmPin2 = PWM(Pin(pwmPinNum2))
pwmPin3 = PWM(Pin(pwmPinNum3))

pwmPinList01 = [pwmPin0, pwmPin1, pwmPin2, pwmPin3]

# *** Defualt Frequency and Duty Cycle ***

defaultPwmFreq         = 1000
defaultPwmDutyCycle    = 50

# *** Initializing Pwm Pin Objects and List ***

def setPwmFreq(pwmPin, pwmFreq):
    pwmPin.freq(pwmFreq)
    return               

def setPwmDutyCycle(pwmPin, dutyCycle):
    u16DutyCycle = int((dutyCycle / 100) * 65536)  
    pwmPin.duty_u16(u16DutyCycle)
    return

def setupPwmPinList(pwmPinList, pwmFreq, pwmDutyCycle):
    print('    pwmFreq      =', pwmFreq)
    print('                          pwmDutyCycle =', pwmDutyCycle)
    for pwmPin in pwmPinList:
        setPwmFreq(pwmPin, pwmFreq)
        setPwmDutyCycle(pwmPin, pwmDutyCycle)
    return            

def testSetupPwmPinList(pwmDutyCycle):
    print('  testSetupPwmPinList(), ... tlfong01  2021oct04hkt1025')
    setupPwmPinList(pwmPinList = pwmPinList01, pwmFreq = 1000, pwmDutyCycle = pwmDutyCycle) 
    return

# Sample test ***
#testSetupPwmPinList(pwmDutyCycle = 50)
#testSetupPwmPinList(pwmDutyCycle = 10)
#testSetupPwmPinList(pwmDutyCycle = 90)

# *** Main Tests ***

#testSetupPwmPinList(pwmDutyCycle = 50)
#testSetupPwmPinList(pwmDutyCycle = 90)
testSetupPwmPinList(pwmDutyCycle = 20)
testMeasureFourInterrupts([4, 5, 6, 7])

# *** End ***

# *** Sample Output tlfong01  2021oct0201 ***
'''
>>> %Run -c $EDITOR_CONTENT
  testSetupPwmPinList(), ... tlfong01  2021oct04hkt1025
    pwmFreq      = 1000
                          pwmDutyCycle = 50
ppsList      = [0, 0, 0, 0]
minimum      = 0
maximum      = 0
average      = 0

rpmList      = [0, 0, 0, 0]
minimum      = 0
maximum      = 0
average      = 0

dpsList      = [0.0, 0.0, 0.0, 0.0]
minimum      = 0.00
maximum      = 0.00
average      = 0.00
>>> %Run -c $EDITOR_CONTENT
  testSetupPwmPinList(), ... tlfong01  2021oct04hkt1025
    pwmFreq      = 1000
                          pwmDutyCycle = 50
ppsList      = [2391, 2401, 2391, 2396]
minimum      = 2391
maximum      = 2401
average      = 2394

rpmList      = [132, 133, 132, 133]
minimum      = 132
maximum      = 133
average      = 132

dpsList      = [43.79516, 43.97832, 43.79516, 43.88674]
minimum      = 43.80
maximum      = 43.98
average      = 43.86
>>> %Run -c $EDITOR_CONTENT
  testSetupPwmPinList(), ... tlfong01  2021oct04hkt1025
    pwmFreq      = 1000
                          pwmDutyCycle = 90
ppsList      = [2796, 2874, 2883, 2859]
minimum      = 2796
maximum      = 2883
average      = 2853

rpmList      = [155, 159, 160, 158]
minimum      = 155
maximum      = 160
average      = 158

dpsList      = [51.2134, 52.64211, 52.80696, 52.36735]
minimum      = 51.21
maximum      = 52.81
average      = 52.26
>>> %Run -c $EDITOR_CONTENT
  testSetupPwmPinList(), ... tlfong01  2021oct04hkt1025
    pwmFreq      = 1000
                          pwmDutyCycle = 10
ppsList      = [1295, 1019, 941, 967]
minimum      = 941
maximum      = 1295
average      = 1055

rpmList      = [71, 56, 52, 53]
minimum      = 52
maximum      = 71
average      = 58

dpsList      = [23.72008, 18.66468, 17.23598, 17.71222]
minimum      = 17.24
maximum      = 23.72
average      = 19.33
>>> %Run -c $EDITOR_CONTENT
  testSetupPwmPinList(), ... tlfong01  2021oct04hkt1025
    pwmFreq      = 1000
                          pwmDutyCycle = 20
ppsList      = [1631, 1505, 1631, 1613]
minimum      = 1505
maximum      = 1631
average      = 1595

rpmList      = [90, 83, 90, 89]
minimum      = 83
maximum      = 90
average      = 88

dpsList      = [29.87449, 27.56658, 29.87449, 29.54479]
minimum      = 27.57
maximum      = 29.87
average      = 29.22
>>> %Run -c $EDITOR_CONTENT
  testSetupPwmPinList(), ... tlfong01  2021oct04hkt1025
    pwmFreq      = 1000
                          pwmDutyCycle = 20
ppsList      = [1572, 1620, 1614, 1665]
minimum      = 1572
maximum      = 1665
average      = 1617

rpmList      = [87, 90, 89, 92]
minimum      = 87
maximum      = 92
average      = 89

dpsList      = [28.7938, 29.673, 29.5631, 30.49725]
minimum      = 28.79
maximum      = 30.50
average      = 29.63
>>> 
'''
# *** End of Sample Output ***

A shorter summary is this:

DutyCycle 90%, pps = 2853, rpm = 158
DutyCycle 50%, pps = 2394, rpm = 132
DutyCycle 20%, pps = 1595, rpm =  88
DutyCycle 10%, pps = 1055, rpm =  58

Excel shows that duty cycle vs rpm is more or less linear:

Actually it is not important for duty cycle vs speed to be linear, because to sync speeds, Pico will be adjusting duty cycles in real time.


The time has come to do the real thing: synchronizing the wheel speeds, which is necessary to move the 4WD in straight line, in a circle, in a square etc. Stay tuned. :grinning:


Setting up PWM and measuring motor speed as a list of 4 motors/pins

Now I have modified the code to process the four motors as a list. The code is again too long, hitting the 32k limit, so I am not listing it here. A summary of the tests is show below:

# *** Main Tests ***

setupPwmPinListV2(pwmPinNumList = [0, 1, 2, 3], pwmFreqList = [1000, 1000, 1000, 1000],
                  pwmDutyCycleList = [90, 90, 90, 90]) 
testMeasureIntPinNumListInt100Ms([0, 1, 2, 3])

# *** End ***

# *** Sample Output tlfong01  2021oct04hkt1657 ***
'''
>>> %Run -c $EDITOR_CONTENT
  testSetupPwmPinNumListV2(), ...
    pwmPinNumList    = [0, 1, 2, 3]
    pwmFreqList      = [1000, 1000, 1000, 1000]
    pwmDutyCycleList = [90, 90, 90, 90]

  testMeasureIntPinNumListInt100Ms()
    ppsList = [36, 34, 26, 33] , min = 26 , max = 36 , avg = 32
    rpmList = [20, 18, 14, 18] , min = 14 , max = 20 , avg = 17
>>> 
'''
# *** End of Sample Output ***

Cross Calibrating Speed of Four 4WD Motors

Now I have modified the program to do the following:

  1. Setup PWM frequency and PWM duty cycle of the list of 4 motors.

  2. Repeat count the interrupts (pps) and calculate the speed (rpm)

The following results shows how reliable or consistent are the speed of four motors at the same pwm frequency and duty cycle.

Next step is to try to adjust individual duty cycle to each motor so that they move the “same” speed.

# *** Sample Output tlfong01  2021oct04hkt1657 ***
'''
>>> %Run -c $EDITOR_CONTENT
  setupPwmPinNumList(), ...
    pwmPinNumList    = [0, 1, 2, 3]
    pwmFreqList      = [1000, 1000, 1000, 1000]
    pwmDutyCycleList = [50, 50, 50, 50]

  testCountIntPinNumListIntOneTenthSecond()
    ppsList = [32, 28, 26, 24] , min  24 , max  32 , avg  27 rpmList = [17, 15, 14, 13] , min  13 , max  17 , avg  14
    ppsList = [27, 24, 31, 34] , min  24 , max  34 , avg  29 rpmList = [15, 13, 17, 18] , min  13 , max  18 , avg  15
    ppsList = [31, 28, 27, 21] , min  21 , max  31 , avg  26 rpmList = [17, 15, 15, 11] , min  11 , max  17 , avg  14
    ppsList = [27, 27, 28, 30] , min  27 , max  30 , avg  28 rpmList = [15, 15, 15, 16] , min  15 , max  16 , avg  15
>>> %Run -c $EDITOR_CONTENT
  setupPwmPinNumList(), ...
    pwmPinNumList    = [0, 1, 2, 3]
    pwmFreqList      = [1000, 1000, 1000, 1000]
    pwmDutyCycleList = [25, 25, 25, 25]

  testCountIntPinNumListIntOneTenthSecond()
    ppsList = [32, 22, 24, 20] , min  20 , max  32 , avg  24 rpmList = [17, 12, 13, 11] , min  11 , max  17 , avg  13
    ppsList = [17, 16, 24, 20] , min  16 , max  24 , avg  19 rpmList = [9, 8, 13, 11] , min  8 , max  13 , avg  10
    ppsList = [21, 21, 22, 21] , min  21 , max  22 , avg  21 rpmList = [11, 11, 12, 11] , min  11 , max  12 , avg  11
    ppsList = [24, 22, 17, 27] , min  17 , max  27 , avg  22 rpmList = [13, 12, 9, 15] , min  9 , max  15 , avg  12
>>> %Run -c $EDITOR_CONTENT
  setupPwmPinNumList(), ...
    pwmPinNumList    = [0, 1, 2, 3]
    pwmFreqList      = [1000, 1000, 1000, 1000]
    pwmDutyCycleList = [20, 20, 20, 20]

  testCountIntPinNumListIntOneTenthSecond()
    ppsList = [21, 23, 19, 21] , min  19 , max  23 , avg  21 rpmList = [11, 12, 10, 11] , min  10 , max  12 , avg  11
    ppsList = [20, 19, 16, 18] , min  16 , max  20 , avg  18 rpmList = [11, 10, 8, 10] , min  8 , max  11 , avg  9
    ppsList = [21, 22, 14, 20] , min  14 , max  22 , avg  19 rpmList = [11, 12, 7, 11] , min  7 , max  12 , avg  10
    ppsList = [21, 23, 20, 15] , min  15 , max  23 , avg  19 rpmList = [11, 12, 11, 8] , min  8 , max  12 , avg  10
>>> %Run -c $EDITOR_CONTENT
  setupPwmPinNumList(), ...
    pwmPinNumList    = [0, 1, 2, 3]
    pwmFreqList      = [1000, 1000, 1000, 1000]
    pwmDutyCycleList = [90, 90, 90, 90]

  testCountIntPinNumListIntOneTenthSecond()
    ppsList = [71, 24, 21, 21] , min  21 , max  71 , avg  34 rpmList = [39, 13, 11, 11] , min  11 , max  39 , avg  18
    ppsList = [25, 41, 26, 31] , min  25 , max  41 , avg  30 rpmList = [13, 22, 14, 17] , min  13 , max  22 , avg  16
    ppsList = [29, 41, 24, 29] , min  24 , max  41 , avg  30 rpmList = [16, 22, 13, 16] , min  13 , max  22 , avg  16
    ppsList = [37, 37, 0, 35] , min  0 , max  37 , avg  27 rpmList = [20, 20, 0, 19] , min  0 , max  20 , avg  14
>>>
'''

Unreliable/unrepeatable speeds at duty cylcle 90%. Duty cycles in the range of 20% to 50% are more reliable.

So I will start experimenting with duty cycle 25%.

This reply is approaching the forum;s 32k words limit. So I will start a new reply.

/ to continue, …

Choosing an optimum duty cycle for calibration/benchmarking

I found low duty cycles like 20% and 25% not satisfactory, because one of the four motors sometimes gets stuck. A 50% duty cycle is more smooth and repeatable. A 50% measurement is shown below:

>>> %Run -c $EDITOR_CONTENT
  setupPwmPinNumList(), ...
    pwmPinNumList    = [0, 1, 2, 3]
    pwmFreqList      = [1000, 1000, 1000, 1000]
    pwmDutyCycleList = [50, 50, 50, 50]

  testCountIntPinNumListIntOneTenthSecond()
    ppsList = [32, 24, 28, 25] , min  24 , max  32 , dif  8 , avg  27
    ppsList = [39, 26, 29, 23] , min  23 , max  39 , dif  16 , avg  29
    ppsList = [31, 28, 28, 21] , min  21 , max  31 , dif  10 , avg  27
    ppsList = [31, 28, 26, 16] , min  16 , max  31 , dif  15 , avg  25
    ppsList = [31, 26, 34, 22] , min  22 , max  34 , dif  12 , avg  28
    ppsList = [29, 26, 27, 19] , min  19 , max  29 , dif  10 , avg  25
    ppsList = [28, 28, 24, 20] , min  20 , max  28 , dif  8 , avg  25
    ppsList = [30, 24, 24, 28] , min  24 , max  30 , dif  6 , avg  26
    ppsList = [33, 27, 18, 22] , min  18 , max  33 , dif  15 , avg  25
    ppsList = [31, 26, 24, 19] , min  19 , max  31 , dif  12 , avg  25
    ppsList = [28, 22, 25, 22] , min  22 , max  28 , dif  6 , avg  24
    ppsList = [32, 21, 27, 32] , min  21 , max  32 , dif  11 , avg  28
    ppsList = [34, 23, 27, 22] , min  22 , max  34 , dif  12 , avg  26
    ppsList = [28, 24, 25, 20] , min  20 , max  28 , dif  8 , avg  24
    ppsList = [36, 23, 31, 21] , min  21 , max  36 , dif  15 , avg  27
    ppsList = [32, 26, 26, 23] , min  23 , max  32 , dif  9 , avg  26
    ppsList = [32, 27, 23, 23] , min  23 , max  32 , dif  9 , avg  26
    ppsList = [32, 24, 26, 23] , min  23 , max  32 , dif  9 , avg  26
    ppsList = [30, 23, 30, 27] , min  23 , max  30 , dif  7 , avg  27
    ppsList = [33, 26, 28, 23] , min  23 , max  33 , dif  10 , avg  27
>>>
'''

This is a full listing of the code, with sample results.

# *** pwm_int_48.py - pwm and interrupt testing, tlfong01, 2021oct05hkt2031 ***

from machine import Pin, PWM
import utime

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# Conents
#
# Part 1 - Interrupt Functions
#   1.1 Using GP4, 5, 6, 7 input pins to detect and count mtor encoder A signals and calculate motor speed

# Part 2 - PWM Functions
#   2.1 Using PWM pin to fade in and fade out the system LED
#   2.2 Using GP 0, 1, 2, 3 pins' PWM signals to control the speed of TB6612FNG driving TM310 DC motor

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# Interrupt functions for multiple (4) interrupt pins GP 4, 5, 6, 7 ***

intPinNum0 = 4 #GP4
intPinNum1 = 5 #GP5
intPinNum2 = 6 #GP6
intPinNum3 = 7 #GP7

intPinNumDict = {'0': 4,
                 '1': 5,
                 '2': 6,
                 '3': 7,
                }

intPinNumList = [intPinNum0, intPinNum1, intPinNum2, intPinNum3]

intPin0 = Pin(intPinNum0, Pin.IN, Pin.PULL_DOWN)
intPin1 = Pin(intPinNum1, Pin.IN, Pin.PULL_DOWN)
intPin2 = Pin(intPinNum2, Pin.IN, Pin.PULL_DOWN)
intPin3 = Pin(intPinNum3, Pin.IN, Pin.PULL_DOWN)

intPinDict = {
    '0': intPin0,
    '1': intPin1,
    '2': intPin2,
    '3': intPin3,
    }

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,
    }
    
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,    
    }

intPin0.irq(intCallBack0, Pin.IRQ_FALLING)
intPin1.irq(intCallBack1, Pin.IRQ_FALLING)
intPin2.irq(intCallBack2, Pin.IRQ_FALLING)
intPin3.irq(intCallBack3, Pin.IRQ_FALLING)

def countIntPinIntCountTime(intPinNum, countTime):
    global intCount0
    global intCount1
    global intCount2
    global intCount3
    
    intCount0 = 0
    intCount1 = 0
    intCount2 = 0
    intCount3 = 0

    utime.sleep(countTime)
 
    if intPinNum  == 0:
        intCount = intCount0
    elif intPinNum == 1:    
        intCount = intCount1
    elif intPinNum == 2:    
        intCount = intCount2
    else:    
        intCount = intCount3                
    return intCount

def countIntPinIntOneTenthSecond(intPinNum):
    intCount = countIntPinIntCountTime(intPinNum = intPinNum, countTime = 0.01)
    return intCount

def countIntPinNumListIntOneTenthSecond(intPinNumList):
    intCountList = [0] * len(intPinNumList)
    for index in range(len(intPinNumList)):
        intCountList[index] = countIntPinIntOneTenthSecond(intPinNumList[index])                       
    return intCountList                                                

# *** Test functions ***

def repeatCountIntPinNumListIntOneTenthSecond(intPinNumList, repeatTimes, pauseTime):
    print('\n  testCountIntPinNumListIntOneTenthSecond()')
    
    for count in range(repeatTimes):
        ppsList             = countIntPinNumListIntOneTenthSecond(intPinNumList)
        print('    ppsList =', 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)))
    
        ''' 
        rpmList             = ppsList.copy()
        
        for index in range(len(rpmList)):
            rpmList[index] = int(((rpmList[index] / 12) / 90) * 10 * 60)                         
    
        print(' rpmList =', rpmList, end = '')
        print(' , min ', min(rpmList), end = '')
        print(' , max ', max(rpmList), end = '')    
        print(' , avg ', int(sum(rpmList) / len(rpmList)))
        '''
        
        utime.sleep(pauseTime)
    
    return

# *** Sample Test ***
#repeatCountIntPinNumListIntOneTenthSecond(intPinNumList = [0, 1, 2, 3], repeatTimes = 4, pauseTime = 0.5)

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 2 - PWM Functions ***

def pwmSystemLed():
    systemLedPinNum = 25
    pwmPin = PWM(Pin(systemLedPinNum))
    pwmPin.freq(1000)
    for count in range(4):
        for dutyCycle in range(65025):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
        for dutyCycle in range(65025, 0, -1):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
            return           

def testPwmSystemLed():
    print('testPwmSystemLed(), ...')
    print('  System LED now fades in and out a couple of times')
    pwmSystemLed()
    print('  End of test.')
    return

# *** Sample Test ***
#testPwmSystemLed()

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Setup 4 PWM Pins ***
# Notes:
#   1. Setting up GP 0, 1, 2, 3 as pwm pins at 1 kHz, 50% duty cycle
#   2. Connecting the pwm pins to the pwm inputs of TB6612FNG move the DC motor TM310.

# *** Pwm Pin Numbers and List ***

pwmPinNum0 = 0 #GP0
pwmPinNum1 = 1 #GP1
pwmPinNum2 = 2 #GP2
pwmPinNum3 = 3 #GP3

pwmPinNumList = [pwmPinNum0, pwmPinNum1, pwmPinNum2, pwmPinNum3]

pwmPinNumDict = {
                '0': 0,
                '1': 1,
                '2': 2,
                '3': 3,
                }

# *** Pwm Pin Objects and List ***

pwmPin0 = PWM(Pin(pwmPinNum0))
pwmPin1 = PWM(Pin(pwmPinNum1))
pwmPin2 = PWM(Pin(pwmPinNum2))
pwmPin3 = PWM(Pin(pwmPinNum3))

pwmPinList01 = [pwmPin0, pwmPin1, pwmPin2, pwmPin3]

pwmPinDict = {'0': pwmPin0,
              '1': pwmPin1,
              '2': pwmPin2,
              '3': pwmPin3,
              }

# *** Defualt Frequency and Duty Cycle ***

defaultPwmFreq         = 1000
defaultPwmDutyCycle    = 50

# *** Initializing Pwm Pin Objects and List ***

def setPwmFreq(pwmPin, pwmFreq):
    pwmPin.freq(pwmFreq)
    return               

def setPwmDutyCycle(pwmPin, dutyCycle):
    u16DutyCycle = int((dutyCycle / 100) * 65536)  
    pwmPin.duty_u16(u16DutyCycle)
    return

def setupPwmPinNumList(pwmPinNumList, pwmFreqList, pwmDutyCycleList):
    print('  setupPwmPinNumList(), ...')
    print('    pwmPinNumList    =', pwmPinNumList)
    print('    pwmFreqList      =', pwmFreqList)
    print('    pwmDutyCycleList =', pwmDutyCycleList)
    for index in range(len(pwmPinNumList)):
        pwmPin = pwmPinDict[str(index)]
        setPwmFreq(pwmPin, pwmFreqList[index])
        setPwmDutyCycle(pwmPin, pwmDutyCycleList[index])    
    return

def testSetupPwmPinNumList():
    setupPwmPinNumList(pwmPinNumList = [0, 1, 2, 3], pwmFreqList = [1000, 1000, 1000, 1000],
                      pwmDutyCycleList = [90, 90, 90, 90]) 
    return

# Sample test ***
#testSetupPwmPinNumList()

# *** Main Tests ***

setupPwmPinNumList(pwmPinNumList    = [0, 1, 2, 3],
                   pwmFreqList      = [1000, 1000, 1000, 1000],
                   pwmDutyCycleList = [50, 50, 50, 50])
                   
repeatCountIntPinNumListIntOneTenthSecond(intPinNumList = [0, 1, 2, 3], repeatTimes = 20, pauseTime = 0.2)

# *** End ***

# *** Sample Output tlfong01  2021oct04hkt1657 ***
'''
>>> %Run -c $EDITOR_CONTENT
  setupPwmPinNumList(), ...
    pwmPinNumList    = [0, 1, 2, 3]
    pwmFreqList      = [1000, 1000, 1000, 1000]
    pwmDutyCycleList = [50, 50, 50, 50]

  testCountIntPinNumListIntOneTenthSecond()
    ppsList = [32, 24, 28, 25] , min  24 , max  32 , dif  8 , avg  27
    ppsList = [39, 26, 29, 23] , min  23 , max  39 , dif  16 , avg  29
    ppsList = [31, 28, 28, 21] , min  21 , max  31 , dif  10 , avg  27
    ppsList = [31, 28, 26, 16] , min  16 , max  31 , dif  15 , avg  25
    ppsList = [31, 26, 34, 22] , min  22 , max  34 , dif  12 , avg  28
    ppsList = [29, 26, 27, 19] , min  19 , max  29 , dif  10 , avg  25
    ppsList = [28, 28, 24, 20] , min  20 , max  28 , dif  8 , avg  25
    ppsList = [30, 24, 24, 28] , min  24 , max  30 , dif  6 , avg  26
    ppsList = [33, 27, 18, 22] , min  18 , max  33 , dif  15 , avg  25
    ppsList = [31, 26, 24, 19] , min  19 , max  31 , dif  12 , avg  25
    ppsList = [28, 22, 25, 22] , min  22 , max  28 , dif  6 , avg  24
    ppsList = [32, 21, 27, 32] , min  21 , max  32 , dif  11 , avg  28
    ppsList = [34, 23, 27, 22] , min  22 , max  34 , dif  12 , avg  26
    ppsList = [28, 24, 25, 20] , min  20 , max  28 , dif  8 , avg  24
    ppsList = [36, 23, 31, 21] , min  21 , max  36 , dif  15 , avg  27
    ppsList = [32, 26, 26, 23] , min  23 , max  32 , dif  9 , avg  26
    ppsList = [32, 27, 23, 23] , min  23 , max  32 , dif  9 , avg  26
    ppsList = [32, 24, 26, 23] , min  23 , max  32 , dif  9 , avg  26
    ppsList = [30, 23, 30, 27] , min  23 , max  30 , dif  7 , avg  27
    ppsList = [33, 26, 28, 23] , min  23 , max  33 , dif  10 , avg  27
>>>
'''
# *** End of Sample Output ***

Pico Running Out of Pins

Pico is now running out of pins. I need to consider using GPIO Extenders, such as MCP23017, MCP23s17 etc.

pwmPinNum0 = 0 #GP0
pwmPinNum1 = 1 #GP1
pwmPinNum2 = 2 #GP2
pwmPinNum3 = 3 #GP3

intPinNum0 = 4 #GP4
intPinNum1 = 5 #GP5
intPinNum2 = 6 #GP6
intPinNum3 = 7 #GP7

picoMotorDriverGpPinNumDict = { \
    '0': {'StdByPinNum1': 8,    #GP 8
          'StdByPinNum2': 9,    #GP 9
          'AinPinNum1'   : 10,  #GP 10
          'AinPinNum2'   : 11,  #GP 11
          'PwmPinNum1'   : 12,  #GP 12
          'BinPinNum1'   : 13,  #GP 13
          'BinPinNum2'   : 14,  #GP 14
          'PwmPinNum2'   : 15,  #GP 15
          }                   
    '1': {'StdByPinNum1': 16,   #GP 16
          'StdByPinNum2': 17,   #GP 17
          'AinPinNum1'   : 18,  #GP 18
          'AinPinNum2'   : 19,  #GP 19
          'PwmPinNum1'   : 20,  #GP 20
          'BinPinNum1'   : 21,  #GP 21
          'BinPinNum2'   : 22,  #GP 22
          'PwmPinNum2'   : 26,  #GP 23
          },
    }

Complete Program Listing

# *** pwm_int_49.py - pwm and interrupt testing, tlfong01, 2021oct07hkt1542 ***

from machine import Pin, PWM
import utime

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# Conents
#
# Part 1 - Interrupt Functions
#   1.1 Using GP4, 5, 6, 7 input pins to detect and count mtor encoder A signals and calculate motor speed

# Part 2 - PWM Functions
#   2.1 Using PWM pin to fade in and fade out the system LED
#   2.2 Using GP 0, 1, 2, 3 pins' PWM signals to control the speed of TB6612FNG driving TM310 DC motor

# Part 3 - TB6612FNG MotorDriver Functions
#   3.1 Setting up TB6612FNG motor drivers

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 1 - Interrupt Functions ***

# Interrupt functions for multiple (4) interrupt pins GP 4, 5, 6, 7 ***

intPinNum0 = 4 #GP4
intPinNum1 = 5 #GP5
intPinNum2 = 6 #GP6
intPinNum3 = 7 #GP7

picoIntGpPinNumDict = {'0': 4, # GP4
                       '1': 5, # GP5
                       '2': 6, # GP6
                       '3': 7, # GP7
                      }

intPinNumList = [intPinNum0, intPinNum1, intPinNum2, intPinNum3]

intPin0 = Pin(intPinNum0, Pin.IN, Pin.PULL_DOWN)
intPin1 = Pin(intPinNum1, Pin.IN, Pin.PULL_DOWN)
intPin2 = Pin(intPinNum2, Pin.IN, Pin.PULL_DOWN)
intPin3 = Pin(intPinNum3, Pin.IN, Pin.PULL_DOWN)

intPinDict = {
    '0': intPin0,
    '1': intPin1,
    '2': intPin2,
    '3': intPin3,
    }

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,
    }
    
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,    
    }

intPin0.irq(intCallBack0, Pin.IRQ_FALLING)
intPin1.irq(intCallBack1, Pin.IRQ_FALLING)
intPin2.irq(intCallBack2, Pin.IRQ_FALLING)
intPin3.irq(intCallBack3, Pin.IRQ_FALLING)

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                                                

# *** Test functions ***

def repeatCountIntPinNumListIntPeriod(intPinNumList, countPeriod, pauseTime, repeatTimes):
    print('\n  countIntPinNumListIntPeriod()')
    picoIntGpPinNumList = [0] * len(intPinNumList)
    for index in range(len(picoIntGpPinNumList)):
        picoIntGpPinNumList[index]     = picoIntGpPinNumDict[str(index)]
    print('    intPinNumList           =', intPinNumList)
    print('    picoIntGpPinNumList     =', picoIntGpPinNumList)
    print('    countPeriod (seconds)   =', countPeriod)
    print('    pauseTime (seconds)     =', pauseTime)    
    print('    repeat count times      =', repeatTimes)
    print('')
    
    for count in range(repeatTimes):
        ppsList             = countIntPinNumListIntPeriod(intPinNumList, countPeriod)
        print('    ppsList =', 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)))
    
        ''' 
        rpmList             = ppsList.copy()
        
        for index in range(len(rpmList)):
            rpmList[index] = int(((rpmList[index] / 12) / 90) * 10 * 60)                         
    
        print(' rpmList =', rpmList, end = '')
        print(' , min ', min(rpmList), end = '')
        print(' , max ', max(rpmList), end = '')    
        print(' , avg ', int(sum(rpmList) / len(rpmList)))
        '''
        
        utime.sleep(pauseTime)
    
    return

# *** Sample Test ***
# ...

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 2 - PWM Functions ***

def pwmSystemLed():
    systemLedPinNum = 25
    pwmPin = PWM(Pin(systemLedPinNum))
    pwmPin.freq(1000)
    for count in range(4):
        for dutyCycle in range(65025):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
        for dutyCycle in range(65025, 0, -1):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
            return           

def testPwmSystemLed():
    print('testPwmSystemLed(), ...')
    print('  System LED now fades in and out a couple of times')
    pwmSystemLed()
    print('  End of test.')
    return

# *** Sample Test ***
#testPwmSystemLed()

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Setup 4 PWM Pins ***
# Notes:
#   1. Setting up GP 0, 1, 2, 3 as pwm pins at 1 kHz, 50% duty cycle
#   2. Connecting the pwm pins to the pwm inputs of TB6612FNG move the DC motor TM310.

# *** Pwm Pin Numbers and List ***

pwmPinNum0 = 0 #GP0
pwmPinNum1 = 1 #GP1
pwmPinNum2 = 2 #GP2
pwmPinNum3 = 3 #GP3

pwmPinNumList = [pwmPinNum0, pwmPinNum1, pwmPinNum2, pwmPinNum3]

picoPwmGpPinNumDict = {
                '0': 0,
                '1': 1,
                '2': 2,
                '3': 3,
                }

# *** Pwm Pin Objects and List ***

pwmPin0 = PWM(Pin(pwmPinNum0))
pwmPin1 = PWM(Pin(pwmPinNum1))
pwmPin2 = PWM(Pin(pwmPinNum2))
pwmPin3 = PWM(Pin(pwmPinNum3))

pwmPinList01 = [pwmPin0, pwmPin1, pwmPin2, pwmPin3]

pwmPinDict = {'0': pwmPin0,
              '1': pwmPin1,
              '2': pwmPin2,
              '3': pwmPin3,
              }

# *** Defualt Frequency and Duty Cycle ***

defaultPwmFreq         = 1000
defaultPwmDutyCycle    = 50

# *** Initializing Pwm Pin Objects and List ***

def setPwmFreq(pwmPin, pwmFreq):
    pwmPin.freq(pwmFreq)
    return               

def setPwmDutyCycle(pwmPin, dutyCycle):
    u16DutyCycle = int((dutyCycle / 100) * 65536)  
    pwmPin.duty_u16(u16DutyCycle)
    return

def setupPwmPinNumList(pwmPinNumList, pwmFreqList, pwmDutyCycleList):
    picoPwmGpPinNumList = [0] * len(pwmPinNumList)
    for index in range(len(picoPwmGpPinNumList)):
        picoPwmGpPinNumList[index] = picoPwmGpPinNumDict[str(index)]
    
    print('  setupPwmPinNumList(), ...')
    print('    pwmPinNumList        =', pwmPinNumList)
    print('    Pico GP pin num list =', picoPwmGpPinNumList) 
    print('    pwmFreqList          =', pwmFreqList)
    print('    pwmDutyCycleList     =', pwmDutyCycleList)
    for index in range(len(pwmPinNumList)):
        pwmPin = pwmPinDict[str(index)]
        setPwmFreq(pwmPin, pwmFreqList[index])
        setPwmDutyCycle(pwmPin, pwmDutyCycleList[index])    
    return

def testSetupPwmPinNumList():
    setupPwmPinNumList(pwmPinNumList = [0, 1, 2, 3], pwmFreqList = [1000, 1000, 1000, 1000],
                      pwmDutyCycleList = [90, 90, 90, 90]) 
    return

# Sample test ***
#testSetupPwmPinNumList()

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 3 - TB6612FNG Motor Driver Functions ***

picoMotorDriverGpPinNumDict = { \
    '0': {'StdByPinNum1': 8,    #GP 8
          'StdByPinNum2': 9,    #GP 9
          'AinPinNum1'   : 10,  #GP 10
          'AinPinNum2'   : 11,  #GP 11
          'PwmPinNum1'   : 12,  #GP 12
          'BinPinNum1'   : 13,  #GP 13
          'BinPinNum2'   : 14,  #GP 14
          'PwmPinNum2'   : 15,  #GP 15
          }                   
    '1': {'StdByPinNum1': 16,   #GP 16
          'StdByPinNum2': 17,   #GP 17
          'AinPinNum1'   : 18,  #GP 18
          'AinPinNum2'   : 19,  #GP 19
          'PwmPinNum1'   : 20,  #GP 20
          'BinPinNum1'   : 21,  #GP 21
          'BinPinNum2'   : 22,  #GP 22
          'PwmPinNum2'   : 26,  #GP 23
          },
    }
 
# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Old Main Tests ***

# *** Old Tests V1 2021oct07hkt1545 ***

def moveFourMotorsV1():
    setupPwmPinNumList(pwmPinNumList    = [0, 1, 2, 3],
                       pwmFreqList      = [1000, 1000, 1000, 1000],
                       pwmDutyCycleList = [50, 50, 50, 50])
    return
          
def checkFourMotorsV1():          
    repeatCountIntPinNumListIntPeriod(intPinNumList = [0, 1, 2, 3],
                                countPeriod   = 0.1,
                                pauseTime     = 0.2,
                                repeatTimes   = 4,)
    return

# ***Old tests ***

moveFourMotorsV1()
checkFourMotorsV1()

# *** Main Tests ***

#testSetupMotorDriverList(motorDriverNumList)


# *** End ***

# *** Sample Output tlfong01  2021oct04hkt1657 ***

# *** End of Sample Output ***

Moving and Stopping 4 Motors

Now I have written functions to move and start 4 motors.

def testStartAndStopMovingFourMotors():
    print('Start moving 4 motors, ...')
    setupMotorDriverChannel(motorDriverNum = 0, channelNum = 0)
    setupMotorDriverChannel(motorDriverNum = 0, channelNum = 1)
    setupMotorDriverChannel(motorDriverNum = 1, channelNum = 0)
    setupMotorDriverChannel(motorDriverNum = 1, channelNum = 1)

    utime.sleep(4)

    print('Stop  moving 4 motors.')
    stopMotorDriverChannel(motorDriverNum = 0, channelNum = 0)
    stopMotorDriverChannel(motorDriverNum = 0, channelNum = 1)
    stopMotorDriverChannel(motorDriverNum = 1, channelNum = 0)
    stopMotorDriverChannel(motorDriverNum = 1, channelNum = 1)

    return

And this is the partial listing of the code.

# *** pico_4wd_v61.py - tlfong01, 2021oct09hkt1534 ***

from machine import Pin, PWM
import utime

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# Conents
#
# Part 1 - Measure 4WD Motor Speeds
#   1.1 Using GP4, 5, 6, 7 input pins to detect and count mtor encoder A signals and calculate motor speed

# Part 2 - Change 4WD Speed and Direction
#   2.1 Using PWM pin to fade in and fade out the system LED
#   2.2 Using GP 0, 1, 2, 3 pins' PWM signals to control the speed of TB6612FNG driving TM310 DC motor

# Part 3 - Setup 4WD Motor Drivers
#   3.1 Setting up TB6612FNG motor drivers

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 3 - TB6612FNG Motor Driver Functions ***

stdByPinNum0 = 8
stdByPinNum1 = 9

aIn1PinNum0  = 10
aIn2PinNum0  = 11
aPwmPinNum0  = 0

bIn1PinNum0  = 12
bIn2PinNum0  = 13
bPwmPinNum0  = 1

aIn1PinNum1  = 14
aIn2PinNum1  = 15
aPwmPinNum1  = 2

bIn1PinNum1  = 16
bIn2PinNum1  = 17
bPwmPinNum1  = 3

motorDriverGpPinNumDict = { \
    '0': {'StdByPinNum'  : stdByPinNum0,             
          '0' : {'In1PinNum' : aIn1PinNum0,  
                 'In2PinNum' : aIn2PinNum0,  
                 'PwmPinNum' : aPwmPinNum0,
                },
          '1' : {'In1PinNum' : bIn1PinNum0,  
                 'In2PinNum' : bIn2PinNum0,  
                 'PwmPinNum' : bPwmPinNum0,
                },  
          },                   
    '1': {'StdByPinNum'  : stdByPinNum1,             
          '0' : {'In1PinNum' : aIn1PinNum1,  
                 'In2PinNum' : aIn2PinNum1,  
                 'PwmPinNum' : aPwmPinNum1,
                },
          '1' : {'In1PinNum' : bIn1PinNum1,  
                 'In2PinNum' : bIn2PinNum1,  
                 'PwmPinNum' : bPwmPinNum1,
                },  
          }, 
    }

def setupMotorDriverChannel(motorDriverNum, 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']    
    
    stdByPin    = Pin(stdByPinNum, Pin.OUT)
    in1Pin      = Pin(in1PinNum, Pin.OUT)    
    in2Pin      = Pin(in2PinNum, Pin.OUT)
    pwmPin      = Pin(pwmPinNum, Pin.OUT)      
    
    stdByPin.high()      
    in1Pin.low()
    in2Pin.high()
    pwmPin.high()
    return

def stopMotorDriverChannel(motorDriverNum, 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']    
    
    stdByPin    = Pin(stdByPinNum, Pin.OUT)
    in1Pin      = Pin(in1PinNum, Pin.OUT)    
    in2Pin      = Pin(in2PinNum, Pin.OUT)
    pwmPin      = Pin(pwmPinNum, Pin.OUT)      
    
    stdByPin.high()      
    in1Pin.high()
    in2Pin.high()
    pwmPin.high()
    return

def testStartAndStopMovingFourMotors():
    print('Start moving 4 motors, ...')
    setupMotorDriverChannel(motorDriverNum = 0, channelNum = 0)
    setupMotorDriverChannel(motorDriverNum = 0, channelNum = 1)
    setupMotorDriverChannel(motorDriverNum = 1, channelNum = 0)
    setupMotorDriverChannel(motorDriverNum = 1, channelNum = 1)

    utime.sleep(4)

    print('Stop  moving 4 motors.')
    stopMotorDriverChannel(motorDriverNum = 0, channelNum = 0)
    stopMotorDriverChannel(motorDriverNum = 0, channelNum = 1)
    stopMotorDriverChannel(motorDriverNum = 1, channelNum = 0)
    stopMotorDriverChannel(motorDriverNum = 1, channelNum = 1)

    return

# ***
testStartAndStopMovingFourMotors()

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Old Main Tests ***

# *** Old Tests V1 2021oct07hkt1545 ***

def pwmChange4MotorSpeeds():
    setupPwmPinNumList(pwmPinNumList    = [0, 1, 2, 3],
                       pwmFreqList      = [1000, 1000, 1000, 1000],
                       pwmDutyCycleList = [50, 50, 50, 50])
    return
          
def intMeasure4MotorSpeeds():          
    repeatCountIntPinNumListIntPeriod(intPinNumList = [0, 1, 2, 3],
                                countPeriod   = 0.1,
                                pauseTime     = 0.2,
                                repeatTimes   = 4,)
    return

# ***Sample Tests ***

#pwmChange4MotorSpeeds()
#intMeasure4MotorSpeeds()

# *** Main Tests ***

testStartAndStopMovingFourMotors()

#utime.sleep(2)

# *** End ***

# *** Sample Output tlfong01  2021oct04hkt1657 ***

# *** End of Sample Output ***

/ to continue, …

I am hitting the forum’s 32k words limit, therefore another reply.

My code can do something like this.

def testStartAndStopMovingFourMotors():
    print('Start moving 4 motors, ...')
    setupMotorDriverChannel(motorDriverNum = 0, channelNum = 0)
    setupMotorDriverChannel(motorDriverNum = 0, channelNum = 1)
    setupMotorDriverChannel(motorDriverNum = 1, channelNum = 0)
    setupMotorDriverChannel(motorDriverNum = 1, channelNum = 1)

    utime.sleep(4)

    print('Stop  moving 4 motors.')
    stopMotorDriverChannel(motorDriverNum = 0, channelNum = 0)
    stopMotorDriverChannel(motorDriverNum = 0, channelNum = 1)
    stopMotorDriverChannel(motorDriverNum = 1, channelNum = 0)
    stopMotorDriverChannel(motorDriverNum = 1, channelNum = 1)

    return

The video


The coomplete listing

# *** pico_4wd_v61.py - tlfong01, 2021oct09hkt1534 ***

from machine import Pin, PWM
import utime

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# Conents
#
# Part 1 - Measure 4WD Motor Speeds
#   1.1 Using GP4, 5, 6, 7 input pins to detect and count mtor encoder A signals and calculate motor speed

# Part 2 - Change 4WD Speed and Direction
#   2.1 Using PWM pin to fade in and fade out the system LED
#   2.2 Using GP 0, 1, 2, 3 pins' PWM signals to control the speed of TB6612FNG driving TM310 DC motor

# Part 3 - Setup 4WD Motor Drivers
#   3.1 Setting up TB6612FNG motor drivers

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 1 - Measure 4WD Motor Speeds ***

intPinNum0 = 4 #GP4
intPinNum1 = 5 #GP5
intPinNum2 = 6 #GP6
intPinNum3 = 7 #GP7

intGpPinNumDict = {'0': 4, # GP4
                   '1': 5, # GP5
                   '2': 6, # GP6
                   '3': 7, # GP7
                  }

intPinNumList = [intPinNum0, intPinNum1, intPinNum2, intPinNum3]

intPin0 = Pin(intPinNum0, Pin.IN, Pin.PULL_DOWN)
intPin1 = Pin(intPinNum1, Pin.IN, Pin.PULL_DOWN)
intPin2 = Pin(intPinNum2, Pin.IN, Pin.PULL_DOWN)
intPin3 = Pin(intPinNum3, Pin.IN, Pin.PULL_DOWN)

intPinDict = {
    '0': intPin0,
    '1': intPin1,
    '2': intPin2,
    '3': intPin3,
    }

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,
    }
    
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,    
    }

intPin0.irq(intCallBack0, Pin.IRQ_FALLING)
intPin1.irq(intCallBack1, Pin.IRQ_FALLING)
intPin2.irq(intCallBack2, Pin.IRQ_FALLING)
intPin3.irq(intCallBack3, Pin.IRQ_FALLING)

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                                                

# *** 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('    ppsList =', 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)))
    
        ''' 
        rpmList             = ppsList.copy()
        
        for index in range(len(rpmList)):
            rpmList[index] = int(((rpmList[index] / 12) / 90) * 10 * 60)                         
    
        print(' rpmList =', rpmList, end = '')
        print(' , min ', min(rpmList), end = '')
        print(' , max ', max(rpmList), end = '')    
        print(' , avg ', int(sum(rpmList) / len(rpmList)))
        '''
        
        utime.sleep(pauseTime)
    
    return

# *** Sample Test ***
# ...

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 2 - PWM Functions ***

def pwmSystemLed():
    systemLedPinNum = 25
    pwmPin = PWM(Pin(systemLedPinNum))
    pwmPin.freq(1000)
    for count in range(4):
        for dutyCycle in range(65025):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
        for dutyCycle in range(65025, 0, -1):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
            return           

def testPwmSystemLed():
    print('testPwmSystemLed(), ...')
    print('  System LED now fades in and out a couple of times')
    pwmSystemLed()
    print('  End of test.')
    return

# *** Sample Test ***
#testPwmSystemLed()

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Setup 4 PWM Pins ***
# Notes:
#   1. Setting up GP 0, 1, 2, 3 as pwm pins at 1 kHz, 50% duty cycle
#   2. Connecting the pwm pins to the pwm inputs of TB6612FNG move the DC motor TM310.

# *** Pwm Pin Numbers and List ***

pwmPinNum0 = 0 #GP0
pwmPinNum1 = 1 #GP1
pwmPinNum2 = 2 #GP2
pwmPinNum3 = 3 #GP3

pwmPinNumList = [pwmPinNum0, pwmPinNum1, pwmPinNum2, pwmPinNum3]

picoPwmGpPinNumDict = {
                '0': 0,
                '1': 1,
                '2': 2,
                '3': 3,
                }

# *** Pwm Pin Objects and List ***

pwmPin0 = PWM(Pin(pwmPinNum0))
pwmPin1 = PWM(Pin(pwmPinNum1))
pwmPin2 = PWM(Pin(pwmPinNum2))
pwmPin3 = PWM(Pin(pwmPinNum3))

pwmPinList01 = [pwmPin0, pwmPin1, pwmPin2, pwmPin3]

pwmPinDict = {'0': pwmPin0,
              '1': pwmPin1,
              '2': pwmPin2,
              '3': pwmPin3,
              }

# *** Defualt Frequency and Duty Cycle ***

defaultPwmFreq         = 1000
defaultPwmDutyCycle    = 50

# *** Initializing Pwm Pin Objects and List ***

def setPwmFreq(pwmPin, pwmFreq):
    pwmPin.freq(pwmFreq)
    return               

def setPwmDutyCycle(pwmPin, dutyCycle):
    u16DutyCycle = int((dutyCycle / 100) * 65536)  
    pwmPin.duty_u16(u16DutyCycle)
    return

def setupPwmPinNumList(pwmPinNumList, pwmFreqList, pwmDutyCycleList):
    picoPwmGpPinNumList = [0] * len(pwmPinNumList)
    for index in range(len(picoPwmGpPinNumList)):
        picoPwmGpPinNumList[index] = picoPwmGpPinNumDict[str(index)]
    
    print('  setupPwmPinNumList(), ...')
    print('    pwmPinNumList        =', pwmPinNumList)
    print('    Pico GP pin num list =', picoPwmGpPinNumList) 
    print('    pwmFreqList          =', pwmFreqList)
    print('    pwmDutyCycleList     =', pwmDutyCycleList)
    for index in range(len(pwmPinNumList)):
        pwmPin = pwmPinDict[str(index)]
        setPwmFreq(pwmPin, pwmFreqList[index])
        setPwmDutyCycle(pwmPin, pwmDutyCycleList[index])    
    return

def testSetupPwmPinNumList():
    setupPwmPinNumList(pwmPinNumList = [0, 1, 2, 3], pwmFreqList = [1000, 1000, 1000, 1000],
                      pwmDutyCycleList = [90, 90, 90, 90]) 
    return

# Sample test ***
#testSetupPwmPinNumList()

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 3 - TB6612FNG Motor Driver Functions ***

stdByPinNum0 = 8
stdByPinNum1 = 9

aIn1PinNum0  = 10
aIn2PinNum0  = 11
aPwmPinNum0  = 0

bIn1PinNum0  = 12
bIn2PinNum0  = 13
bPwmPinNum0  = 1

aIn1PinNum1  = 14
aIn2PinNum1  = 15
aPwmPinNum1  = 2

bIn1PinNum1  = 16
bIn2PinNum1  = 17
bPwmPinNum1  = 3

motorDriverGpPinNumDict = { \
    '0': {'StdByPinNum'  : stdByPinNum0,             
          '0' : {'In1PinNum' : aIn1PinNum0,  
                 'In2PinNum' : aIn2PinNum0,  
                 'PwmPinNum' : aPwmPinNum0,
                },
          '1' : {'In1PinNum' : bIn1PinNum0,  
                 'In2PinNum' : bIn2PinNum0,  
                 'PwmPinNum' : bPwmPinNum0,
                },  
          },                   
    '1': {'StdByPinNum'  : stdByPinNum1,             
          '0' : {'In1PinNum' : aIn1PinNum1,  
                 'In2PinNum' : aIn2PinNum1,  
                 'PwmPinNum' : aPwmPinNum1,
                },
          '1' : {'In1PinNum' : bIn1PinNum1,  
                 'In2PinNum' : bIn2PinNum1,  
                 'PwmPinNum' : bPwmPinNum1,
                },  
          }, 
    }

def setupMotorDriverChannel(motorDriverNum, 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']    
    
    stdByPin    = Pin(stdByPinNum, Pin.OUT)
    in1Pin      = Pin(in1PinNum, Pin.OUT)    
    in2Pin      = Pin(in2PinNum, Pin.OUT)
    pwmPin      = Pin(pwmPinNum, Pin.OUT)      
    
    stdByPin.high()      
    in1Pin.low()
    in2Pin.high()
    pwmPin.high()
    return

def stopMotorDriverChannel(motorDriverNum, 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']    
    
    stdByPin    = Pin(stdByPinNum, Pin.OUT)
    in1Pin      = Pin(in1PinNum, Pin.OUT)    
    in2Pin      = Pin(in2PinNum, Pin.OUT)
    pwmPin      = Pin(pwmPinNum, Pin.OUT)      
    
    stdByPin.high()      
    in1Pin.high()
    in2Pin.high()
    pwmPin.high()
    return

def testStartAndStopMovingFourMotors():
    print('Start moving 4 motors, ...')
    setupMotorDriverChannel(motorDriverNum = 0, channelNum = 0)
    setupMotorDriverChannel(motorDriverNum = 0, channelNum = 1)
    setupMotorDriverChannel(motorDriverNum = 1, channelNum = 0)
    setupMotorDriverChannel(motorDriverNum = 1, channelNum = 1)

    utime.sleep(4)

    print('Stop  moving 4 motors.')
    stopMotorDriverChannel(motorDriverNum = 0, channelNum = 0)
    stopMotorDriverChannel(motorDriverNum = 0, channelNum = 1)
    stopMotorDriverChannel(motorDriverNum = 1, channelNum = 0)
    stopMotorDriverChannel(motorDriverNum = 1, channelNum = 1)

    return

# ***
testStartAndStopMovingFourMotors()

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Old Main Tests ***

# *** Old Tests V1 2021oct07hkt1545 ***

def pwmChange4MotorSpeeds():
    setupPwmPinNumList(pwmPinNumList    = [0, 1, 2, 3],
                       pwmFreqList      = [1000, 1000, 1000, 1000],
                       pwmDutyCycleList = [50, 50, 50, 50])
    return
          
def intMeasure4MotorSpeeds():          
    repeatCountIntPinNumListIntPeriod(intPinNumList = [0, 1, 2, 3],
                                countPeriod   = 0.1,
                                pauseTime     = 0.2,
                                repeatTimes   = 4,)
    return

# ***Sample Tests ***

#pwmChange4MotorSpeeds()
#intMeasure4MotorSpeeds()

# *** Main Tests ***

testStartAndStopMovingFourMotors()

#utime.sleep(2)

# *** End ***

# *** Sample Output tlfong01  2021oct04hkt1657 ***

# *** End of Sample Output ***

Setup and move a list of 4 motors

Now I have modified the 4WD program to do list processing. For example:

def testSetupMoveMotorList(motorConfigDictList):
    motorControlDictList = setupMotorList(motorConfigDictList)
    moveMotorList(motorControlDictList)          
    utime.sleep(2)       
    stopMotorList(motorControlDictList)        
    return     

testSetupMoveMotorList(motorConfigDictList_00_01_10_11)

Below is the complete code listing.

# *** pico_4wd_v66.py - tlfong01, 2021oct10hkt1644 ***

from machine import Pin, PWM
import utime

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# Conents
#
# Part 1 - Measure 4WD Motor Speeds
#   1.1 Using GP4, 5, 6, 7 input pins to detect and count mtor encoder A signals and calculate motor speed

# Part 2 - Change 4WD Speed and Direction
#   2.1 Using PWM pin to fade in and fade out the system LED
#   2.2 Using GP 0, 1, 2, 3 pins' PWM signals to control the speed of TB6612FNG driving TM310 DC motor

# Part 3 - Setup 4WD Motor Drivers
#   3.1 Setting up TB6612FNG motor drivers

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 1 - Measure 4WD Motor Speeds ***

intPinNum0 = 4 #GP4
intPinNum1 = 5 #GP5
intPinNum2 = 6 #GP6
intPinNum3 = 7 #GP7

intGpPinNumDict = {'0': 4, # GP4
                   '1': 5, # GP5
                   '2': 6, # GP6
                   '3': 7, # GP7
                  }

intPinNumList = [intPinNum0, intPinNum1, intPinNum2, intPinNum3]

intPin0 = Pin(intPinNum0, Pin.IN, Pin.PULL_DOWN)
intPin1 = Pin(intPinNum1, Pin.IN, Pin.PULL_DOWN)
intPin2 = Pin(intPinNum2, Pin.IN, Pin.PULL_DOWN)
intPin3 = Pin(intPinNum3, Pin.IN, Pin.PULL_DOWN)

intPinDict = {
    '0': intPin0,
    '1': intPin1,
    '2': intPin2,
    '3': intPin3,
    }

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,
    }
    
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,    
    }

intPin0.irq(intCallBack0, Pin.IRQ_FALLING)
intPin1.irq(intCallBack1, Pin.IRQ_FALLING)
intPin2.irq(intCallBack2, Pin.IRQ_FALLING)
intPin3.irq(intCallBack3, Pin.IRQ_FALLING)

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                                                

# *** 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('    ppsList =', 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)))
    
        ''' 
        rpmList             = ppsList.copy()
        
        for index in range(len(rpmList)):
            rpmList[index] = int(((rpmList[index] / 12) / 90) * 10 * 60)                         
    
        print(' rpmList =', rpmList, end = '')
        print(' , min ', min(rpmList), end = '')
        print(' , max ', max(rpmList), end = '')    
        print(' , avg ', int(sum(rpmList) / len(rpmList)))
        '''
        
        utime.sleep(pauseTime)
    
    return

# *** Sample Test ***
# ...

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 2 - PWM Functions ***

def pwmSystemLed():
    systemLedPinNum = 25
    pwmPin = PWM(Pin(systemLedPinNum))
    pwmPin.freq(1000)
    for count in range(4):
        for dutyCycle in range(65025):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
        for dutyCycle in range(65025, 0, -1):
            pwmPin.duty_u16(dutyCycle)
            utime.sleep(0.0001)
            return           

def testPwmSystemLed():
    print('testPwmSystemLed(), ...')
    print('  System LED now fades in and out a couple of times')
    pwmSystemLed()
    print('  End of test.')
    return

# *** Sample Test ***
#testPwmSystemLed()

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Setup 4 PWM Pins ***
# Notes:
#   1. Setting up GP 0, 1, 2, 3 as pwm pins at 1 kHz, 50% duty cycle
#   2. Connecting the pwm pins to the pwm inputs of TB6612FNG move the DC motor TM310.

# *** Pwm Pin Numbers and List ***

pwmPinNum0 = 0 #GP0
pwmPinNum1 = 1 #GP1
pwmPinNum2 = 2 #GP2
pwmPinNum3 = 3 #GP3

pwmPinNumList = [pwmPinNum0, pwmPinNum1, pwmPinNum2, pwmPinNum3]

picoPwmGpPinNumDict = {
                '0': 0,
                '1': 1,
                '2': 2,
                '3': 3,
                }

# *** Pwm Pin Objects and List ***

pwmPin0 = PWM(Pin(pwmPinNum0))
pwmPin1 = PWM(Pin(pwmPinNum1))
pwmPin2 = PWM(Pin(pwmPinNum2))
pwmPin3 = PWM(Pin(pwmPinNum3))

pwmPinList01 = [pwmPin0, pwmPin1, pwmPin2, pwmPin3]

pwmPinDict = {'0': pwmPin0,
              '1': pwmPin1,
              '2': pwmPin2,
              '3': pwmPin3,
              }

# *** Defualt Frequency and Duty Cycle ***

defaultPwmFreq         = 1000
defaultPwmDutyCycle    = 50

# *** Initializing Pwm Pin Objects and List ***

def setPwmFreq(pwmPin, pwmFreq):
    pwmPin.freq(pwmFreq)
    return               

def setPwmDutyCycle(pwmPin, dutyCycle):
    u16DutyCycle = int((dutyCycle / 100) * 65536)  
    pwmPin.duty_u16(u16DutyCycle)
    return

def setupPwmPinNumList(pwmPinNumList, pwmFreqList, pwmDutyCycleList):
    picoPwmGpPinNumList = [0] * len(pwmPinNumList)
    for index in range(len(picoPwmGpPinNumList)):
        picoPwmGpPinNumList[index] = picoPwmGpPinNumDict[str(index)]
    
    print('  setupPwmPinNumList(), ...')
    print('    pwmPinNumList        =', pwmPinNumList)
    print('    Pico GP pin num list =', picoPwmGpPinNumList) 
    print('    pwmFreqList          =', pwmFreqList)
    print('    pwmDutyCycleList     =', pwmDutyCycleList)
    for index in range(len(pwmPinNumList)):
        pwmPin = pwmPinDict[str(index)]
        setPwmFreq(pwmPin, pwmFreqList[index])
        setPwmDutyCycle(pwmPin, pwmDutyCycleList[index])    
    return

def testSetupPwmPinNumList():
    setupPwmPinNumList(pwmPinNumList = [0, 1, 2, 3], pwmFreqList = [1000, 1000, 1000, 1000],
                      pwmDutyCycleList = [90, 90, 90, 90]) 
    return

# Sample test ***
#testSetupPwmPinNumList()

def pwmChange4MotorSpeeds():
    setupPwmPinNumList(pwmPinNumList    = [0, 1, 2, 3],
                       pwmFreqList      = [1000, 1000, 1000, 1000],
                       pwmDutyCycleList = [50, 50, 50, 50])
    return
          
def intMeasure4MotorSpeeds():          
    repeatCountIntPinNumListIntPeriod(intPinNumList = [0, 1, 2, 3],
                                countPeriod   = 0.1,
                                pauseTime     = 0.2,
                                repeatTimes   = 4,)
    return

# ***Sample Tests ***

#pwmChange4MotorSpeeds()
#intMeasure4MotorSpeeds()

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Part 3 - TB6612FNG Motor Driver Functions ***

stdByPinNum0 = 8
stdByPinNum1 = 9

aIn1PinNum0  = 10
aIn2PinNum0  = 11
aPwmPinNum0  = 0

bIn1PinNum0  = 12
bIn2PinNum0  = 13
bPwmPinNum0  = 1

aIn1PinNum1  = 14
aIn2PinNum1  = 15
aPwmPinNum1  = 2

bIn1PinNum1  = 16
bIn2PinNum1  = 17
bPwmPinNum1  = 3

motorConfigDict00 = {'MotorDriverNum': 0, 'ChannelNum': 0}
motorConfigDict01 = {'MotorDriverNum': 0, 'ChannelNum': 1}
motorConfigDict10 = {'MotorDriverNum': 1, 'ChannelNum': 0}
motorConfigDict11 = {'MotorDriverNum': 1, 'ChannelNum': 1}

motorConfigDictList_00_01_10_11 = [motorConfigDict00, motorConfigDict01, motorConfigDict10, motorConfigDict11]

motorDriverGpPinNumDict = { \
    '0': {'StdByPinNum'  : stdByPinNum0,             
          '0' : {'In1PinNum' : aIn1PinNum0,  
                 'In2PinNum' : aIn2PinNum0,  
                 'PwmPinNum' : aPwmPinNum0,
                },
          '1' : {'In1PinNum' : bIn1PinNum0,  
                 'In2PinNum' : bIn2PinNum0,  
                 'PwmPinNum' : bPwmPinNum0,
                },  
          },                   
    '1': {'StdByPinNum'  : stdByPinNum1,             
          '0' : {'In1PinNum' : aIn1PinNum1,  
                 'In2PinNum' : aIn2PinNum1,  
                 'PwmPinNum' : aPwmPinNum1,
                },
          '1' : {'In1PinNum' : bIn1PinNum1,  
                 'In2PinNum' : bIn2PinNum1,  
                 'PwmPinNum' : bPwmPinNum1,
                },  
          }, 
    }

def setupMotor(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']    
    
    stdByPin    = Pin(stdByPinNum, Pin.OUT)
    in1Pin      = Pin(in1PinNum, Pin.OUT)    
    in2Pin      = Pin(in2PinNum, Pin.OUT)
    pwmPin      = Pin(pwmPinNum, Pin.OUT)
    
    motorControlDict = {'StdByPin': stdByPin,
                        'In1Pin'  : in1Pin,
                        'In2Pin'  : in2Pin,
                        'PwmPin'  : pwmPin,
                       }
    return motorControlDict

def setupMotorList(motorConfigDictList):
    motorControlDictList = [0] * len(motorConfigDictList)        
    for index in range(len(motorConfigDictList)):
        motorControlDict = setupMotor(motorConfigDictList[index])
        motorControlDictList[index] = motorControlDict
    return motorControlDictList       

def moveMotor(motorControlDict):
    motorControlDict['StdByPin'].high()
    motorControlDict['In1Pin'].low()
    motorControlDict['In2Pin'].high()
    motorControlDict['PwmPin'].high()    
    return

def moveMotorList(motorControlDictList):
    for motorControlDict in motorControlDictList:
        moveMotor(motorControlDict)
    return    

def stopMotor(motorControlDict):
    motorControlDict['In1Pin'].low()
    motorControlDict['In2Pin'].low()
    return

def stopMotorList(motorControlDictList):
    for motorControlDict in motorControlDictList:
        stopMotor(motorControlDict)
    return
  
def testSetupMoveMotorList(motorConfigDictList):
    motorControlDictList = setupMotorList(motorConfigDictList)
    moveMotorList(motorControlDictList)          
    utime.sleep(2)       
    stopMotorList(motorControlDictList)        
    return     
    
# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

testSetupMoveMotorList(motorConfigDictList_00_01_10_11)

# *** End ***

Newbie friendly version of this Pico 4WD program

Now I have written some higher abstract level functions to make using the program user friendly. Below is an example of how to use the high level functions as two commands to setup and move 4 motors.

testSetupMoveMotorDirectionSpeedList(‘FourMotorsList’, ‘Forward’, ‘VerySlow’, ‘TwoSeconds’)

testSetupMoveMotorDirectionSpeedList(‘FourMotorsList’, ‘Backward’, ‘VeryFast’, ‘FourSeconds’)


I am hitting the 32k words limit again. So I am making a new reply to list the TLDR program.

/ to continue, …

Example commands to move 4 motors

testSetupMoveMotorDirectionSpeedList(‘FourMotorsList’, ‘Forward’, ‘VerySlow’, ‘TwoSeconds’)
testSetupMoveMotorDirectionSpeedList(‘FourMotorsList’, ‘Backward’, ‘VeryFast’, ‘FourSeconds’)



A complete listing of the previous 4WD program.

# *** pico_4wd_v70.py - tlfong01, 2021oct10hkt2039 ***

from machine import Pin, PWM
import utime

secondsDict = {'TwoSeconds': 2,
               'FourSeconds': 4,
              }

# *** Part 1 - Measure 4WD Motor Speeds ***

intPinNum0 = 4 #GP4
intPinNum1 = 5 #GP5
intPinNum2 = 6 #GP6
intPinNum3 = 7 #GP7

intGpPinNumDict = {'0': 4, # GP4
                   '1': 5, # GP5
                   '2': 6, # GP6
                   '3': 7, # GP7
                  }

intPinNumList = [intPinNum0, intPinNum1, intPinNum2, intPinNum3]

intPin0 = Pin(intPinNum0, Pin.IN, Pin.PULL_DOWN)
intPin1 = Pin(intPinNum1, Pin.IN, Pin.PULL_DOWN)
intPin2 = Pin(intPinNum2, Pin.IN, Pin.PULL_DOWN)
intPin3 = Pin(intPinNum3, Pin.IN, Pin.PULL_DOWN)

intPinDict = {
    '0': intPin0,
    '1': intPin1,
    '2': intPin2,
    '3': intPin3,
    }

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,
    }
    
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,    
    }

intPin0.irq(intCallBack0, Pin.IRQ_FALLING)
intPin1.irq(intCallBack1, Pin.IRQ_FALLING)
intPin2.irq(intCallBack2, Pin.IRQ_FALLING)
intPin3.irq(intCallBack3, Pin.IRQ_FALLING)

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                                                

# *** 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('    ppsList =', 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)))
    
        ''' 
        rpmList             = ppsList.copy()
        
        for index in range(len(rpmList)):
            rpmList[index] = int(((rpmList[index] / 12) / 90) * 10 * 60)                         
    
        print(' rpmList =', rpmList, end = '')
        print(' , min ', min(rpmList), end = '')
        print(' , max ', max(rpmList), end = '')    
        print(' , avg ', int(sum(rpmList) / len(rpmList)))
        '''
        
        utime.sleep(pauseTime)
    
    return

# *** Part 3 - TB6612FNG Motor Driver Functions ***

stdByPinNum0 = 8
stdByPinNum1 = 9

aIn1PinNum0  = 10
aIn2PinNum0  = 11
aPwmPinNum0  = 0

bIn1PinNum0  = 12
bIn2PinNum0  = 13
bPwmPinNum0  = 1

aIn1PinNum1  = 14
aIn2PinNum1  = 15
aPwmPinNum1  = 2

bIn1PinNum1  = 16
bIn2PinNum1  = 17
bPwmPinNum1  = 3

motorConfigDict00 = {'MotorDriverNum': 0, 'ChannelNum': 0}
motorConfigDict01 = {'MotorDriverNum': 0, 'ChannelNum': 1}
motorConfigDict10 = {'MotorDriverNum': 1, 'ChannelNum': 0}
motorConfigDict11 = {'MotorDriverNum': 1, 'ChannelNum': 1}

motorConfigDictList_00_01_10_11 = [motorConfigDict00, motorConfigDict01, motorConfigDict10, motorConfigDict11]
motorConfigDictList01 = motorConfigDictList_00_01_10_11

motorConfigDictListDict = {'FourMotorsList' : motorConfigDictList01,
                }

motorDriverGpPinNumDict = { \
    '0': {'StdByPinNum'  : stdByPinNum0,             
          '0' : {'In1PinNum' : aIn1PinNum0,  
                 'In2PinNum' : aIn2PinNum0,  
                 'PwmPinNum' : aPwmPinNum0,
                 'PwmFreq'   : 1000,
                 'DutyCycle' : 20,
                },
          '1' : {'In1PinNum' : bIn1PinNum0,  
                 'In2PinNum' : bIn2PinNum0,  
                 'PwmPinNum' : bPwmPinNum0,
                 'PwmFreq'   : 1000,
                 'DutyCycle' : 20,                 
                },  
          },                   
    '1': {'StdByPinNum'  : stdByPinNum1,             
          '0' : {'In1PinNum' : aIn1PinNum1,  
                 'In2PinNum' : aIn2PinNum1,  
                 'PwmPinNum' : aPwmPinNum1,
                 'PwmFreq'   : 1000,
                 'DutyCycle' : 20,                 
                },
          '1' : {'In1PinNum' : bIn1PinNum1,  
                 'In2PinNum' : bIn2PinNum1,  
                 'PwmPinNum' : bPwmPinNum1,
                 'PwmFreq'   : 1000,
                 'DutyCycle' : 20,                 
                },  
          }, 
    }

def setupMotorBasic(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']
    
    stdByPin    = Pin(stdByPinNum, Pin.OUT)
    in1Pin      = Pin(in1PinNum, Pin.OUT)    
    in2Pin      = Pin(in2PinNum, Pin.OUT)

    pwmPinNum   = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmPinNum']
    pwmFreq     = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmFreq']    
    dutyCycle   = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['DutyCycle']      
    
    pwmPin      = PWM(Pin(pwmPinNum))
    pwmPin.freq(pwmFreq)
    u16DutyCycle = int((dutyCycle / 100) * 65536)  
    pwmPin.duty_u16(u16DutyCycle)
    
    motorControlDict = {'StdByPin': stdByPin,
                        'In1Pin'  : in1Pin,
                        'In2Pin'  : in2Pin,
                        'PwmPin'  : pwmPin,
                       }
    return motorControlDict

dutyCycleDict = {
    'VeryVerySlow' : 95,
    'VeryFast'     : 90,
    'Fast'         : 80,
    'Normal'       : 50,
    'Slow'         : 40,
    'VerySlow'     : 30,
    'VeryVerySlow' : 25,
    }

def setupMotorList(motorConfigDictList):
    motorControlDictList = [0] * len(motorConfigDictList)        
    for index in range(len(motorConfigDictList)):
        motorControlDict = setupMotorBasic(motorConfigDictList[index])
        motorControlDictList[index] = motorControlDict
    return motorControlDictList

def moveMotorDirectionSpeedList(motorControlDictList, directionName, speedName):
    for motorControlDict in motorControlDictList:
        moveMotorDirectionSpeed(motorControlDict, directionName, speedName)
    return

def moveMotorDirectionSpeed(motorControlDict, directionName, speedName):
    moveMotorDirection(motorControlDict, directionName)
    moveMotorSpeed(motorControlDict, speedName)
    return

def moveMotorDirection(motorControlDict, directionName):
    if directionName =='Forward':
        motorControlDict['In1Pin'].low()
        motorControlDict['In2Pin'].high()
    elif directionName == 'Backward':
        motorControlDict['In1Pin'].high()
        motorControlDict['In2Pin'].low()       
    return
    
def moveMotorSpeed(motorControlDict, speedName):
    pwmPin = motorControlDict['PwmPin']
    dutyCycle = dutyCycleDict[speedName]
    pwmPin.duty_u16(int((dutyCycle / 100) * 65536) )
    return

def stopMotor(motorControlDict):
    motorControlDict['In1Pin'].low()
    motorControlDict['In2Pin'].low()
    return

def stopMotorList(motorControlDictList):
    for motorControlDict in motorControlDictList:
        stopMotor(motorControlDict)
    return
  
def testSetupMoveMotorDirectionSpeedList(motorConfigDictListName, directionName, speedName, secondsName):
    print('Begin testSetupMoveMotorList(), ...')
    motorConfigDictList = motorConfigDictListDict[motorConfigDictListName]
    motorControlDictList1 = setupMotorList(motorConfigDictList)
    moveMotorDirectionSpeedList(motorControlDictList1, directionName, speedName)
    utime.sleep(secondsDict[secondsName])       
    stopMotorList(motorControlDictList1)
    print('End   testSetupMoveMotorList(), ...')    
    return     
    
# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Main ***

testSetupMoveMotorDirectionSpeedList('FourMotorsList', 'Forward',  'VerySlow', 'TwoSeconds')
testSetupMoveMotorDirectionSpeedList('FourMotorsList', 'Backward', 'VeryFast', 'FourSeconds')

# *** End ***

Merging PWM and Interrupt Functions into Main Motor Control Functions

PWM functions have been merged and tested OK. Interrupt functions are to be tested.

Penzu complete listing of code: https://penzu.com/p/56eb8c7c


Interrupt count measuring OK (https://penzu.com/p/b176e88b)

>>> %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 = [294, 220, 300, 215] , min  215 , max  300 , dif  85 , avg  257
    countList = [267, 226, 300, 210] , min  210 , max  300 , dif  90 , avg  250
    countList = [284, 231, 301, 214] , min  214 , max  301 , dif  87 , avg  257
    countList = [273, 229, 299, 213] , min  213 , max  299 , dif  86 , avg  253
    countList = [290, 219, 301, 218] , min  218 , max  301 , dif  83 , avg  257
    countList = [280, 224, 298, 217] , min  217 , max  298 , dif  81 , avg  254
    countList = [302, 231, 298, 212] , min  212 , max  302 , dif  90 , avg  260
    countList = [276, 216, 304, 216] , min  216 , max  304 , dif  88 , avg  253
    countList = [295, 215, 298, 203] , min  203 , max  298 , dif  95 , avg  252
    countList = [292, 214, 293, 210] , min  210 , max  293 , dif  83 , avg  252
End   testSetupMoveMotorList(), ...
>>> 

Scaling up 4WD with DC Motor x 4 to 6WD with BLDC Motor x 6

Now I am thinking of upgrading my 4WD to 6WD with BLDC motors. The BLDC motor has built in controllers, so there is no need to use any motor controllers. Some newbie is asking a question of testing BLDC motors, and I took the opportunity to do a little research and found it easy to expand the dictionaries for BLDC motors.

Brushless DC motor with built in controller - EESE, Asked 2021oct13


Part 5 - Using Rpi Pico and MicroPython to PWM control BLDC motor speed

Video = https://youtu.be/-omE34cMXj4

Test function =

```
def testBldcMotorV1():
    print('  Begin testBldcMotor(), ...')
    motorConfigDict = {'MotorDriverNum': 2, 'ChannelNum': 0}
    motorControlDict = setupBldcMotor(motorConfigDict)
    print('    Now start fast, ...')
    hold('FourSeconds')
    changeBldcMotorSpeed(motorControlDict, 'Normal')
    print('    Now normal, ...')
    hold('FourSeconds')
    changeBldcMotorSpeed(motorControlDict, 'Slow')
    print('    Now slow, ...')    
    hold('FourSeconds')
    changeBldcMotorSpeed(motorControlDict, 'Fast')
    print('    Now fast again, ...')
    hold('FourSeconds')
    changeBldcMotorSpeed(motorControlDict, 'Slow')
    print('    Now slow again, ...')
    hold('FourSeconds')    
    
    print('  End   testSetupMotor(), ...')
    return

```

Program listing and sample output = https://penzu.com/p/95b30513


Pico 6WD using BLDC motors

I found it easy to expand my 4WD DC motor project to 6WD using BLDC motor. So I am starting off with an A4 size acrylic plate as car body, and Aslong 2535 BLDC motors.



I read my post of the result of careless wiring of BLDC motors, just to remind myself.

Brushless DC motor with built in controller - Asked 2021Oct13

Part 6 - Aslong BLDC Postmortem


There you go, BLDC 6WD



Testing 4WD, to be scaled up to 6WD

For prototyping, I am testing just 4 motors, instead of 6, so maximum risk is frying 4 motors, instead of 6.

The testing video: https://youtu.be/fKe3huM2Qqc


4WD BLDC motors encoder signals (FG)

Now I am checking out the encoder signals (FG) of the 4 BLDC motors. I powered the four motor with the same 12V PSU and use my quad channel scope to display the encoder output waveforms, as show below. I know the motor speed is 107 rpm. I need to work back the pulses per revolution.



Calibrating 4WD BLDC - Speed vs PWM duty cycle

Notes

  1. 4 motors with only power, no PWM, tested OK.

  2. Now going to test PWM duty cycle vs speed, for one motor only.


IEEE Spectrum Smart Cars Than Think

I have been reading the above IEEE Spectrum articles for a couple of years, thinking that I might borrow ideas from them.

IEEE Cars That Think - IEEE Spectrum


Big Aslong BLDC Motor Control Signals and PWM vs Speed Calibration



Aslong BLDC JGB37-2525 Spec

Now I am studying the BLDC spec, before calibrating things.



Calibrating PWM duty cycle vs mot speed (FG (encoder) pulses per second)

Now I am using PWM 1kHz 90% duty cycle to measure the speed of 19 pulses per second


Range of duty cycle when controlling Aslong BLDC motor speed

I found the range is approximately 37% to 100%. I think 99% or 100% should be the same as DC without PWM (to verify later). I also found that the motor slows down as duty cycle goes low.

At around 40%, the motor moves very slowly, and at 37%, the motor comes to stand still.

Again, I need to read the FG (encoder pulses) to get the precise motor speed.


433MHz RF Communication among Pico 4WDs

Now I am thinking of letting the Pico 4WDs to talk to each other using 433MHz transmitter (FS1000A) and receivers (MX05V) The feasibility study is satisfactory. The Pico sends a text message through GP0 (uart0 TxD) and received from GP1 (uart0 RxD). The hardware setup is shown below:


4WD 433MHz FS1000A/MX05V RF Communication References

Transmitting and Receiving messages through RF433 using Raspberry Pico - RpiSE, Asked 2021oct21

Chat: https://chat.stackexchange.com/rooms/130758/discussion-between-tlfong01-and-antifa

Q&E https://raspberrypi.stackexchange.com/questions/132771/transmitting-and-receiving-messages-through-rf433-using-raspberry-pico


HC12 UART 433MHz transceiver testing notes

JBtek Windows 8 Supported Debug Cable for Raspberry Pi USB Programming USB to TTL Serial Cable - Amazon US$7

PL2303XHD Datasheet - Prolific 2023
http://www.prolific.com.tw/UserFiles/files/ds_pl2303HXD_v1_4_4.pdf

The power pin provides 500mA directly from the USB port and the RX/TX pins are 3.3V level for interfacing with the most common 3.3V logic level chipsets
Windows XP/Vista/7 & Windows 8 supported, MacOS X; PL2303 TA. drivers on your computer and connect with a terminal program at 115200 baud

Red cable    : +5V
Black cable  : GND
Green cable  : TXD
White cable  : RXD

Yellow cable : RTS
Blue cable   : CTS


RealTerm Configuring HC12 433MHz Transceiver Record


Pico 4WD BLDC Quad HC12 433MHz RF Transceiver Setup Notes


Dual HC12 RF transceiver setup notes


HC12 at RealTerm COM10 transceiving to/from HC12 at RealTerm COM9 Tested OK



Testing HC12 #1 at Pico 1’s uart0 transceiving HC12 #2 at same Pico 1’s uart1

Now I am going to test if two HC12’s (on the same bread board, separated by 1 cm), controlled by two UART’s (uart0, uart1) of the same Pico can transmit/receive at RF 433MHz without any problem.

Testing Plan

1. I first use RealTerm to check out that the two HC12's are set up with the same configuration as summarized below:

RealTerm COM10 

AT+RX                                                                        
OK+B9600                                                                      
OK+RC001                                                                      
OK+RP:+20dBm                                                                  
OK+FU3

---

RealTerm COM9

AT+RX                                                                         
OK+B9600                                                                      
OK+RC001                                                                      
OK+RP:+20dBm                                                                  
OK+FU3

  1. Then I will disconnect the two Windows UART to TTL adaptors (at COM10, COM9) from the two HC12’s.

  2. I will now connect the same Pico’s uart0, uart1 wires to the two HC12s.

  3. I will first test if Pico microPython can also setup/config the HC12’s

  4. Then I will send “Hello World” from HC12 #0 at uart0 and see if this message can transmit in air at 433MHz to HC #2 at uart1.



HC12 Testing Program v22 Complete Listing

# hc12_test_v22.py  tlfong01  2021nov04hkt1705
#
# Pico GP Pin Assignment
#   GP0 = UART0 TxD - connect to HC12 #0 RxD    
#   GP1 = UART0 RxD - connect to HC12 #0 TxD
#   GP4 = UART0 TxD - connect to HC12 #1 RxD    
#   GP5 = UART0 RxD - connect to HC12 #1 TxD
#   GP2 = TC12 #0 set pin - connect to HC12 #0 setPin
#   GP3 = TC12 #1 set pin - connect to HC12 #1 setPin

# Setup notes
#   1. To test UART serialloop back, short TxD pin to RxD pin
#   2. To test HC12 #0, (1) Connect uart0 TxD to HC12 RxD, (2) Connect uart0 RxD to HC12 #0 TxD
#   3. To set TC12 partmeters, connect SET pin to Low,
#   4. To perform normal transmit/receive half duplex communcation, connect SET pin to High

# References
#   1. MicroPython Class UART – duplex serial communication bus
#        https://docs.micropython.org/en/latest/library/machine.UART.html
#   2. General information about the RP2xxx port
#        https://docs.micropython.org/en/latest/rp2/general.html
#   3. Understanding and Implementing the HC-12 Wireless Transceiver Module - Mark Hughes, AllAboutCircuits, 2016nov02
#      https://www.allaboutcircuits.com/projects/understanding-and-implementing-the-hc-12-wireless-transceiver-module/
#   4. HC-12 vs nRF24L01 modules - Robin66, AllAboutCircuits, 2019may08
#      https://forum.allaboutcircuits.com/threads/hc-12-vs-nrf24l01-modules.159540/
#   5. HC-12 433MHz Transceiver 1km serial (Si4438) (Product Sheet, Tutorial) - ¥34
#      https://item.taobao.com/item.htm?spm=a1z1r.7974869.0.0.269c3ad4pAu1MO&id=636694630080
#   6. HC Tech (汇承) Official Web Site - HC Tech
#      http://www.hc01.com/home
#   7. HC12 Datasheet/User Manual v2.6 - HCTech 2018jul11
#      http://www.hc01.com/downloads/HC-12%20english%20datasheets.pdf
#   8. HC-12 433MHz RF Transciver Module (SI4438, 433MHZ, 1KM) - SmartPrototyping, US$12
#      https://www.smart-prototyping.com/HC-12-Wireless-Transceiver-Module-SI4438-433MHz-1km - US$12
#   9. Si4438 Transceiver Datasheet - Silicon Labs
#      https://www.silabs.com/documents/public/data-sheets/Si4438.pdf

# ========= ========= ========= ========= ========= ========= ========= ========= 

from machine import UART, Pin
import utime

uart0 = UART(0, baudrate = 9600, tx=Pin(0), rx=Pin(1))
uart1 = UART(1, baudrate = 9600, tx=Pin(4), rx=Pin(5))

uartPortDict = \
    {
     '0': uart0,
     '1': uart1,
    }

def uartWrite(uartPortNum, writeBytes):
    uartPort = uartPortDict[str(uartPortNum)]
    uartPort.write(writeBytes)
    return 

def uartReadOld(uartPortNum, lengthReadBytes):
    uartPort = uartPortDict[str(uartPortNum)]
    readBytes = uartPort.read(lengthReadBytes)
    return readBytes

def uartRead(uartPortNum):
    uartPort = uartPortDict[str(uartPortNum)]
    readBytes = uartPort.read()
    return readBytes

def testUartLoopBackV09(uartPortNum):
    print('  Begin testUartLoopBackV09(), ...')
    print('    Remember to short TxD and RxD!!!')
    print('    uartPortNum      =', uartPortNum)
        
    writeBytes = 'Hello World'
    uartPortNum = 0    
    uartWrite(uartPortNum, writeBytes)
    print('    writeBytes       =', writeBytes)    
     
    utime.sleep(0.5)
    
    readBytes = uartRead(uartPortNum)     
    print('    readBytes        =', readBytes)
    
    print('  End   testUartLoopBackV09().')
    return

def testUartListLoopBackV09(uartPortNumList):
    print('  Begin testUartLoopBackV09(), ...')
    print('    Remember to short TxD and RxD!!!')
    
    for uartPortNum in uartPortNumList:
        print('    uartPortNum      =', uartPortNum)
        
        writeBytes = 'Hello World'
        uartPortNum = 0    
        uartWrite(uartPortNum, writeBytes)
        print('    writeBytes       =', writeBytes)    
     
        utime.sleep(0.5)
    
        readBytes = uartRead(uartPortNum)     
        print('    readBytes        =', readBytes)
    
    print('  End   testUartLoopBackV09().')
    return

def testHc12ConfigV09(uartPortNum):
    print('Begin testHc12ConfigV09(), ...')    
    testUartLoopBackV09(uartPortNum)
    print('End   testHc12ConfigV09(), ...')     
    return

def testHc12ListConfigV09(uartPortNumList):
    print('Begin testHc12ListConfigV09(), ...')    
    testUartListLoopBackV09(uartPortNumList)    
    print('End   testHc12ListConfigV09(), ...')     
    return  

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Main ***

#testUartListLoopBackV09([0, 1])
testHc12ListConfigV09([0, 1])

# .END

''' *** Sample output tlfong01  2021nov04hkt1704 ***
>>> %Run -c $EDITOR_CONTENT
Begin testHc12ListConfigV09(), ...
  Begin testUartLoopBackV09(), ...
    Remember to short TxD and RxD!!!
    uartPortNum      = 0
    writeBytes       = Hello World
    readBytes        = b'Hello World'
    uartPortNum      = 1
    writeBytes       = Hello World
    readBytes        = b'Hello World'
  End   testUartLoopBackV09().
End   testHc12ListConfigV09(), ...
>>> 

'''

# *** End of sample output **

HC12 Parameter Setting Troubleshooting Notes

So I wrote the I thought a simple microPython program to test the following:

  1. Write ‘AT’ to GP0 (uart0 TxD),
  2. Read ‘OK’ from GP1 (uart0 RxD),

Surprisingly, I always read ‘None’ from GP1. I thought the input format was wrong. So I tried things like b’AT’, ‘AT’, bytes(‘AT’, utf_8) etc, but no luck. After spending a couple of hours trials and errors, reading manuals, I gave up, and decide to return to RealTerm which did smoothly write ‘AT’, and get back ‘OK’. So I recorded the RealTerm procedure and capture the one shot scope captures, as shown below:


Looking at the scope displays, I think one thing I missed is that I was not aware the there was a time lag between ‘AT’ and ‘OK’, so perhaps that is the reason the program missed the ‘OK’ return message.


/ to continue, …

Exceeding forum’s 32k work limit, therefore another reply.

# ========= ========= ========= ========= ========= ========= ========= ========= 

from machine import Pin, UART
import utime

# *** UART GP pin assignment and setup/configuration ***

uart0 = UART(0, baudrate = 9600, tx=Pin(0), rx=Pin(1))
uart1 = UART(1, baudrate = 9600, tx=Pin(8), rx=Pin(9)) # Warning: GP 4, 5 seem broken

uartPortDict = \
    {
     '0': uart0,
     '1': uart1,
    }

# HC12 GP pin assignment and setup/configuration ***

hc12SetPinNum0 = 2
hc12SetPinNum1 = 3

hc12SetPin0 = Pin(hc12SetPinNum0, Pin.OUT) 
hc12SetPin1 = Pin(hc12SetPinNum1, Pin.OUT)

def uartWrite(uartPortNum, writeBytes):
    uartPort = uartPortDict[str(uartPortNum)]
    uartPort.write(writeBytes)
    return 

def uartRead(uartPortNum):
    uartPort = uartPortDict[str(uartPortNum)]
    readBytes = uartPort.read()
    return readBytes

def testUartLoopBack(uartPortNum, writeBytes):
    print('\n    Begin testUartLoopBack(), ...')
    print('      uartPortNum        =', uartPortNum)       
    
    uartWrite(uartPortNum, writeBytes)
    print('        writeBytes       =', writeBytes)    
     
    utime.sleep(0.5)
    
    readBytes = uartRead(uartPortNum)     
    print('        readBytes        =', readBytes)
    
    print('    End   testUartLoopBack().')
    return

def testUartListLoopBack(uartPortNumList, writeBytes):
    print('  Begin testUartLoopBack(), ...')
    print('    Remember to short TxD and RxD!!!')
    
    for uartPortNum in uartPortNumList:
        testUartLoopBack(uartPortNum, writeBytes)       

    print('  End   testUartLoopBack().')
    return

def testHc12Config(uartPortNum, writeBytes):
    print('Begin testHc12Config(), ...')    
    testUartLoopBack(uartPortNum, writeBytes)
    print('End   testHc12Config(), ...')     
    return

def testHc12ListConfig(uartPortNumList, writeBytes):
    print('Begin testHc12ListConfig(), ...')    
    testHc12ListLoopBack(uartPortNumList, writeBytes)    
    print('End   testHc12ListConfig(), ...')     
    return  

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Main ***

#testUartListLoopBack([0, 1], bytes('Hello World', 'utf-8'))
#testHc12ListConfig([0, 1], bytes('AT', 'utf-8'))
testUartListLoopBack([0, 1], b'\0x41\0x54\r\n')

# .END

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

''' *** Sample output tlfong01  2021nov05hkt0925 ***

MicroPython v1.16 on 2021-06-18; Raspberry Pi Pico with RP2040

Type "help()" for more information.

>>> %Run -c $EDITOR_CONTENT
  Begin testUartLoopBack(), ...
    Remember to short TxD and RxD!!!

    Begin testUartLoopBack(), ...
      uartPortNum        = 0
        writeBytes       = b'\x00x41\x00x54\r\n'
        readBytes        = None
    End   testUartLoopBack().

    Begin testUartLoopBack(), ...
      uartPortNum        = 1
        writeBytes       = b'\x00x41\x00x54\r\n'
        readBytes        = None
    End   testUartLoopBack().
  End   testUartLoopBack().
>>>
'''

# *** End of sample output **

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

Pico HC12 Debugging Notes

  1. I found Pico GP 0, 1, and GP 16, 17 for uart0 always works. However GP14, 15 for uart0 does not work.

  2. I also found nothing works for uart1 (GP 4, 5, or GP 8, 9)

  3. I need to find another Pico to verify my test results.


# hc12_test_v28.py  tlfong01  2021nov05hkt1614
#
# Setup notes
#   1. To test UART serialloop back, short TxD pin to RxD pin
#   2. To test HC12 #0, (1) Connect uart0 TxD to HC12 RxD, (2) Connect uart0 RxD to HC12 #0 TxD
#   3. To set TC12 partmeters, connect SET pin to Low,
#   4. To perform normal transmit/receive half duplex communcation, connect SET pin to High

# References
#   1. MicroPython Class UART – duplex serial communication bus
#        https://docs.micropython.org/en/latest/library/machine.UART.html
#   2. General information about the RP2xxx port
#        https://docs.micropython.org/en/latest/rp2/general.html
#   3. Understanding and Implementing the HC-12 Wireless Transceiver Module - Mark Hughes, AllAboutCircuits, 2016nov02
#      https://www.allaboutcircuits.com/projects/understanding-and-implementing-the-hc-12-wireless-transceiver-module/
#   4. HC-12 vs nRF24L01 modules - Robin66, AllAboutCircuits, 2019may08
#      https://forum.allaboutcircuits.com/threads/hc-12-vs-nrf24l01-modules.159540/
#   5. HC-12 433MHz Transceiver 1km serial (Si4438) (Product Sheet, Tutorial) - ¥34
#      https://item.taobao.com/item.htm?spm=a1z1r.7974869.0.0.269c3ad4pAu1MO&id=636694630080
#   6. HC Tech (汇承) Official Web Site - HC Tech
#      http://www.hc01.com/home
#   7. HC12 Datasheet/User Manual v2.6 - HCTech 2018jul11
#      http://www.hc01.com/downloads/HC-12%20english%20datasheets.pdf
#   8. HC-12 433MHz RF Transciver Module (SI4438, 433MHZ, 1KM) - SmartPrototyping, US$12
#      https://www.smart-prototyping.com/HC-12-Wireless-Transceiver-Module-SI4438-433MHz-1km - US$12
#   9. Si4438 Transceiver Datasheet - Silicon Labs
#      https://www.silabs.com/documents/public/data-sheets/Si4438.pdf

# ========= ========= ========= ========= ========= ========= ========= ========= 

from machine import Pin, UART
import utime

# *** UART GP pin assignment and setup/configuration ***

uart0 = UART(0, baudrate = 9600, tx=Pin(0), rx=Pin(1))    # good
#uart0 = UART(0, baudrate = 9600, tx=Pin(16), rx=Pin(17)) # good
#uart0 = UART(0, baudrate = 9600, tx=Pin(12), rx=Pin(13)) # bad

uart1 = UART(1, baudrate = 9600, tx=Pin(4), rx=Pin(5))   # bad
#uart1 = UART(1, baudrate = 9600, tx=Pin(8), rx=Pin(9))   # bad

uartPortDict = \
    {
     '0': uart0,
     '1': uart1,
    }

# HC12 GP pin assignment and setup/configuration ***

hc12SetPinNum0 = 2
hc12SetPinNum1 = 3

hc12SetPin0 = Pin(hc12SetPinNum0, Pin.OUT) 
hc12SetPin1 = Pin(hc12SetPinNum1, Pin.OUT)

def uartWrite(uartPortNum, writeBytes):
    uartPort = uartPortDict[str(uartPortNum)]
    uartPort.write(writeBytes)
    return 

def uartRead(uartPortNum):
    uartPort = uartPortDict[str(uartPortNum)]    
    utime.sleep(0.1)
    uartAny = uartPort.any()
    print('        uartAny          =', uartAny)
    readBytes = uartPort.read()
    return readBytes

def testUartLoopBack(uartPortNum, writeBytes):
    print('\n    Begin testUartLoopBack(), ...')
    print('      uartPortNum        =', uartPortNum)       
    
    uartWrite(uartPortNum, writeBytes)
    print('        writeBytes       =', writeBytes)    
     
    utime.sleep(0.5)
    
    readBytes = uartRead(uartPortNum)     
    print('        readBytes        =', readBytes)
    
    print('    End   testUartLoopBack().\n')
    return

def testUartListLoopBack(uartPortNumList, writeBytes):
    print('\nBegin testUartLoopBack(), ...')
    print('    Remember to short TxD and RxD!!!')
    
    for uartPortNum in uartPortNumList:
        testUartLoopBack(uartPortNum, writeBytes)       

    print('End   testUartLoopBack().')
    return

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Main ***

testUartListLoopBack([0], 'AT')      # 'AT' without \r\n works
testUartListLoopBack([0], 'AT\r\n')  # 'AT' with    \r\n also works

# .END

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

''' *** Sample output tlfong01  2021nov05hkt0925 ***
>>> %Run -c $EDITOR_CONTENT

Begin testUartLoopBack(), ...
    Remember to short TxD and RxD!!!

    Begin testUartLoopBack(), ...
      uartPortNum        = 0
        writeBytes       = AT
        uartAny          = 4
        readBytes        = b'OK\r\n'
    End   testUartLoopBack().

End   testUartLoopBack().

Begin testUartLoopBack(), ...
    Remember to short TxD and RxD!!!

    Begin testUartLoopBack(), ...
      uartPortNum        = 0
        writeBytes       = AT

        uartAny          = 4
        readBytes        = b'OK\r\n'
    End   testUartLoopBack().

End   testUartLoopBack().
>>> 
'''

# *** End of sample output **

# ========= ========= ========= ========= ========= ========= ========= =========/
# ========= ========= ========= ========= ========= ========= ========= =========

AT+RX Also OK

readBytes = b’OK+B9600\r\nOK+RC001\r\nOK+RP:+20dBm\r\nOK+FU3\r\n’


Begin testUartLoopBack(), ...
    Remember to short TxD and RxD!!!

    Begin testUartLoopBack(), ...
      uartPortNum        = 0
        writeBytes       = AT+RX

        uartAny          = 42
        readBytes        = b'OK+B9600\r\nOK+RC001\r\nOK+RP:+20dBm\r\nOK+FU3\r\n'
    End   testUartLoopBack().

End   testUartLoopBack().

HC12 uart1 GP4, 5, GP 8,9 not working problem solved!!!

So I setup another Pico at COM7 and tried everything again. This time all is well,
uart1, using GP4,5 or GP8,9 work smoothly.

So I concluded that the first Pico’s GP4,5, GP8,9 are faulty.


# hc12_test_v30.py  tlfong01  2021nov06hkt1501
#
# Pico GP Pin Assignment
#   GP0 = UART0 TxD - connect to HC12 #0 RxD    
#   GP1 = UART0 RxD - connect to HC12 #0 TxD
#   GP4 = UART0 TxD - connect to HC12 #1 RxD     
#   GP5 = UART0 RxD - connect to HC12 #1 TxD 
#   GP8 = UART0 TxD - connect to HC12 #1 RxD    
#   GP9 = UART0 RxD - connect to HC12 #1 TxD
#   GP2 = TC12 #0 set pin - connect to HC12 #0 setPin
#   GP3 = TC12 #1 set pin - connect to HC12 #1 setPin

# Setup notes
#   1. To test UART serialloop back, short TxD pin to RxD pin
#   2. To test HC12 #0, (1) Connect uart0 TxD to HC12 RxD, (2) Connect uart0 RxD to HC12 #0 TxD
#   3. To set TC12 partmeters, connect SET pin to Low,
#   4. To perform normal transmit/receive half duplex communcation, connect SET pin to High

# References
#   1. MicroPython Class UART – duplex serial communication bus
#        https://docs.micropython.org/en/latest/library/machine.UART.html
#   2. General information about the RP2xxx port
#        https://docs.micropython.org/en/latest/rp2/general.html
#   3. Understanding and Implementing the HC-12 Wireless Transceiver Module - Mark Hughes, AllAboutCircuits, 2016nov02
#      https://www.allaboutcircuits.com/projects/understanding-and-implementing-the-hc-12-wireless-transceiver-module/
#   4. HC-12 vs nRF24L01 modules - Robin66, AllAboutCircuits, 2019may08
#      https://forum.allaboutcircuits.com/threads/hc-12-vs-nrf24l01-modules.159540/
#   5. HC-12 433MHz Transceiver 1km serial (Si4438) (Product Sheet, Tutorial) - ¥34
#      https://item.taobao.com/item.htm?spm=a1z1r.7974869.0.0.269c3ad4pAu1MO&id=636694630080
#   6. HC Tech (汇承) Official Web Site - HC Tech
#      http://www.hc01.com/home
#   7. HC12 Datasheet/User Manual v2.6 - HCTech 2018jul11
#      http://www.hc01.com/downloads/HC-12%20english%20datasheets.pdf
#   8. HC-12 433MHz RF Transciver Module (SI4438, 433MHZ, 1KM) - SmartPrototyping, US$12
#      https://www.smart-prototyping.com/HC-12-Wireless-Transceiver-Module-SI4438-433MHz-1km - US$12
#   9. Si4438 Transceiver Datasheet - Silicon Labs
#      https://www.silabs.com/documents/public/data-sheets/Si4438.pdf

# ========= ========= ========= ========= ========= ========= ========= ========= 

from machine import Pin, UART
import utime

# *** UART GP pin assignment and setup/configuration ***

uart0 = UART(0, baudrate = 9600, tx=Pin(0), rx=Pin(1))
#uart1 = UART(1, baudrate = 9600, tx=Pin(4), rx=Pin(5)) 
uart1 = UART(1, baudrate = 9600, tx=Pin(8), rx=Pin(9)) 

uartPortDict = \
    {
     '0': uart0,
     '1': uart1,
    }

# HC12 GP pin assignment and setup/configuration ***

hc12SetPinNum0 = 2
hc12SetPinNum1 = 3

hc12SetPin0 = Pin(hc12SetPinNum0, Pin.OUT) 
hc12SetPin1 = Pin(hc12SetPinNum1, Pin.OUT)

def uartWrite(uartPortNum, writeBytes):
    uartPort = uartPortDict[str(uartPortNum)]
    uartPort.write(writeBytes)
    return 

def uartRead(uartPortNum):
    uartPort = uartPortDict[str(uartPortNum)]
    uartAny = uartPort.any()
    print('        uartAny =', uartAny)
    readBytes = uartPort.read()
    return readBytes

def testUartLoopBack(uartPortNum, writeBytes):
    print('\n    Begin testUartLoopBack(), ...')
    print('      uartPortNum        =', uartPortNum)       
    
    uartWrite(uartPortNum, writeBytes)
    print('        writeBytes       =', writeBytes)    
     
    utime.sleep(0.5)
    
    readBytes = uartRead(uartPortNum)     
    print('        readBytes        =', readBytes)
    
    print('    End   testUartLoopBack().')
    return

def testUartListLoopBack(uartPortNumList, writeBytes):
    print('  Begin testUartLoopBack(), ...')
    print('    Remember to short TxD and RxD!!!')
    
    for uartPortNum in uartPortNumList:
        testUartLoopBack(uartPortNum, writeBytes)       

    print('  End   testUartLoopBack().')
    return

def testHc12Config(uartPortNum, writeBytes):
    print('Begin testHc12Config(), ...')    
    testUartLoopBack(uartPortNum, writeBytes)
    print('End   testHc12Config(), ...')     
    return

def testHc12ListConfig(uartPortNumList, writeBytes):
    print('Begin testHc12ListConfig(), ...')    
    testHc12ListLoopBack(uartPortNumList, writeBytes)    
    print('End   testHc12ListConfig(), ...')     
    return  

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Main ***

testUartListLoopBack([0, 1], 'AT')

# .END

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

''' *** Sample output tlfong01 2021nov06hkt1501 ***

>>> %Run -c $EDITOR_CONTENT
  Begin testUartLoopBack(), ...
    Remember to short TxD and RxD!!!

    Begin testUartLoopBack(), ...
      uartPortNum        = 0
        writeBytes       = AT
        uartAny = 4
        readBytes        = b'OK\r\n'
    End   testUartLoopBack().

    Begin testUartLoopBack(), ...
      uartPortNum        = 1
        writeBytes       = AT
        uartAny = 4
        readBytes        = b'OK\r\n'
    End   testUartLoopBack().
  End   testUartLoopBack().
>>> 

'''

# *** End of sample output **

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

Pico #2 uart0 (GP0, 1) , uart1 (GP 4,5, GP 8,9) HC12 #1, #2 Testing OK notes


Testing OK a new Pico uart0 (GP0,1) uart1 (GP8,9) and 4 HC12’s



Switch mode power supply unit (SMPSU) 12V in 3V3 2A out for the Pico 4WD



Now that testing sending “AT” receives “OK”, means the HC12 transceiver talks with Pico without any problem, next step is to write function to do the following things:

  1. Assign channel number, so that HC12’s can communcate with one another, or broadcast to HC12’s set to the same channle number.

  2. Test if two Pico with its own HC12 (and 4WD) can do serial half duplex communcation with simple test messages such as

    “Everybody on this 433MHz Channel #007 go forward”,

    “Everybody on this 433MHz Channel #004 stops” etc.


Functions to set HC12 configuration tested OK

Example call:

testHc12ListConfigV02([0], ‘SetChannel#2’)


Full program listing (comments removed) with sample output


# hc12_test_v36.py  tlfong01  2021nov08hkt1029

# ========= ========= ========= ========= ========= ========= ========= ========= 

from machine import Pin, UART
import utime

# *** UART GP pin assignment and setup/configuration ***

uart0 = UART(0, baudrate = 9600, tx=Pin(0), rx=Pin(1))
#uart1 = UART(1, baudrate = 9600, tx=Pin(4), rx=Pin(5)) ### often not working, avoid this for uart1
uart1 = UART(1, baudrate = 9600, tx=Pin(8), rx=Pin(9)) 

uartPortDict = \
    {
     '0': uart0,
     '1': uart1,
    }

# HC12 GP pin assignment and setup/configuration ***

hc12SetPinNum0 = 2
hc12SetPinNum1 = 3

hc12SetPin0 = Pin(hc12SetPinNum0, Pin.OUT) 
hc12SetPin1 = Pin(hc12SetPinNum1, Pin.OUT)

def uartWrite(uartPortNum, writeBytes):
    uartPort = uartPortDict[str(uartPortNum)]
    uartPort.write(writeBytes)
    return 

def uartRead(uartPortNum):
    uartPort = uartPortDict[str(uartPortNum)]
    uartAny = uartPort.any()
    print('        uartAny =', uartAny)
    readBytes = uartPort.read()
    return readBytes

def testUartLoopBack(uartPortNum, writeBytes):
    print('    Begin testUartLoopBack(), ...')
    print('      uartPortNum        =', uartPortNum)       
    
    uartWrite(uartPortNum, writeBytes)
    print('        writeBytes       =', writeBytes)    
     
    utime.sleep(0.5)
    
    readBytes = uartRead(uartPortNum)     
    print('        readBytes        =', readBytes)
    
    print('    End   testUartLoopBack().')
    return

def testUartListLoopBack(uartPortNumList, writeBytes):
    print('  Begin testUartLoopBack(), ...')
    print('    Remember to short TxD and RxD!!!')
    
    for uartPortNum in uartPortNumList:
        testUartLoopBack(uartPortNum, writeBytes)       

    print('  End   testUartLoopBack().')
    return

def testHc12Config(uartPortNum, writeBytes):
    print('Begin testHc12Config(), ...')    
    testUartLoopBack(uartPortNum, writeBytes)
    print('End   testHc12Config(), ...')     
    return

def testHc12ListConfig(uartPortNumList, writeBytes):
    print('Begin testHc12ListConfig(), ...  hc12_test_v35_2021nov0601.py tlfong01  2021nov07hkt2148')       
    for uartPortNum in uartPortNumList:
        testHc12Config(uartPortNum, writeBytes)       
    print('End   testHc12ListConfig().')
    return

def testHc12ListConfigV02(uartPortNumList, configParameterName):   
    print('Begin testHc12ListConfig(), ...  hc12_test_v35_2021nov0601.py tlfong01  2021nov07hkt2148')
    
    writeBytes = hc12ConfigParameterDict[configParameterName]
    print('configParameterName =', configParameterName)
    
    for uartPortNum in uartPortNumList:
        testHc12Config(uartPortNum, writeBytes)       
    print('End   testHc12ListConfig().')
    return

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

hc12ConfigParameterDict = \
    {
        'CheckAtReply'           : 'AT',
        'CheckAllConfigSetting'  : 'AT+RX',
        'SetChannel#1'           : 'AT+C001',
        'SetChannel#2'           : 'AT+C002',        
    }        


# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Main ***

# ***
#testUartListLoopBack([0], 'AT')    ### Only test uart0 for HC12 #0
#testUartListLoopBack([0, 1], 'AT')  ### Test both uart0 for HC12 #0, and uart1 for HC12 #1

#testHc12Config(0, 'AT')
#testHc12ListConfig([0, 1], 'AT')

#testHc12ListConfig([0, 1], 'AT+RX')

testHc12ListConfigV02([0], 'CheckAtReply')
testHc12ListConfigV02([0], 'CheckAllConfigSetting')
testHc12ListConfigV02([0], 'SetChannel#1')
testHc12ListConfigV02([0], 'SetChannel#2')

# .END

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

''' *** Sample output tlfong01 2021nov08hkt1049 ***
>>> %Run -c $EDITOR_CONTENT
Begin testHc12ListConfig(), ...  hc12_test_v35_2021nov0601.py tlfong01  2021nov07hkt2148
configParameterName = CheckAtReply
Begin testHc12Config(), ...
    Begin testUartLoopBack(), ...
      uartPortNum        = 0
        writeBytes       = AT
        uartAny = 4
        readBytes        = b'OK\r\n'
    End   testUartLoopBack().
End   testHc12Config(), ...
End   testHc12ListConfig().
Begin testHc12ListConfig(), ...  hc12_test_v35_2021nov0601.py tlfong01  2021nov07hkt2148
configParameterName = CheckAllConfigSetting
Begin testHc12Config(), ...
    Begin testUartLoopBack(), ...
      uartPortNum        = 0
        writeBytes       = AT+RX
        uartAny = 42
        readBytes        = b'OK+B9600\r\nOK+RC002\r\nOK+RP:+20dBm\r\nOK+FU3\r\n'
    End   testUartLoopBack().
End   testHc12Config(), ...
End   testHc12ListConfig().
Begin testHc12ListConfig(), ...  hc12_test_v35_2021nov0601.py tlfong01  2021nov07hkt2148
configParameterName = SetChannel#1
Begin testHc12Config(), ...
    Begin testUartLoopBack(), ...
      uartPortNum        = 0
        writeBytes       = AT+C001
        uartAny = 9
        readBytes        = b'OK+C001\r\n'
    End   testUartLoopBack().
End   testHc12Config(), ...
End   testHc12ListConfig().
Begin testHc12ListConfig(), ...  hc12_test_v35_2021nov0601.py tlfong01  2021nov07hkt2148
configParameterName = SetChannel#2
Begin testHc12Config(), ...
    Begin testUartLoopBack(), ...
      uartPortNum        = 0
        writeBytes       = AT+C002
        uartAny = 9
        readBytes        = b'OK+C002\r\n'
    End   testUartLoopBack().
End   testHc12Config(), ...
End   testHc12ListConfig().
>>> 

'''

# *** End of sample output **

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

Second Pico smart car’s HC12 433MHz transceiver pair also tested OK

Second Pico smart car’s HC12 pair tested OK. The refactored wiring is simple and easy. Next step is to config each HC12 transceiver pair and see if they can talk serial half duplex 9600bd81over 433MHz channel.



(2 x Pico) + (4 x HC12) 433MHz Xmit/Recv Test Plan V0.1

Now I planning to test two Pico 4WDs together communicating to each other using HT12 433MHz transcvivers. Each Pico 4WD with HC12 has been tested OK on parameter setting mode, using microPython. RF 433MHz communication has also been tested, using RealCom. Next is to use Thonny MicroPython to do both parameter setting, and RF communication.



4WD with GPS and LIDAR

I jealously read this morning that some guys are building a food delivery robot are building a robot car with GPS and LIDAR. I am thinking of also adding similar stuff to my not so smart robot, so not to loose too much face.

Local engineer helps develop food delivery robot - Morrowcountysentinel, 2021nov10


Dual Pico, Quad HC12 Communication Testing Notes

Now I have the following setup:

  1. Two Pico’s, one controlled by Windows Thonny MicroPython COM7, the other COM11.

  2. Each Pico controls two HC12’s, one by uart0, the other by uart1.

  3. Now my testing is in two steps:

3.1 Using Pico #2 only, transmit a text message to HC12 #3 (uart0), and see if HC#4 (uart1), over the same 433MHz Channel #1, can receive it.

3.2. Using two Pico’s: Pico #1 sends a text message to HC#1, and see if Pcio #2 HC #3 can receive the message.

Test results for 3.1 is OK. Next test is 3.2.



/ to continue, …

Test 3.1 program listing with sample output

# hc12_test_v46.py  tlfong01  2021nov12hkt1740
#
# Pico GP Pin Assignment
#   GP0 = UART0 TxD - connect to HC12 #0 RxD    
#   GP1 = UART0 RxD - connect to HC12 #0 TxD
#   GP8 = UART0 TxD - connect to HC12 #1 RxD    
#   GP9 = UART0 RxD - connect to HC12 #1 TxD
#   GP2 = TC12 #0 set pin - connect to HC12 #0 setPin
#   GP3 = TC12 #1 set pin - connect to HC12 #1 setPin

#   Debugging notes
#   GP4, GP5 for uart0 never works

# Setup notes
#   1. To test UART serialloop back, short TxD pin to RxD pin
#   2. To test HC12 #0, (1) Connect uart0 TxD to HC12 RxD, (2) Connect uart0 RxD to HC12 #0 TxD
#   3. To set TC12 partmeters, connect SET pin to Low,
#   4. To perform normal transmit/receive half duplex communcation, connect SET pin to High

# Troubleshooting notes
#   1. Use RealTerm (or miniCom etc) to do offline testing, without Pico
#   2. Remember to short Pico ground with HC12 ground get make a COMMON GROUND

# References
#   1. MicroPython Class UART – duplex serial communication bus
#        https://docs.micropython.org/en/latest/library/machine.UART.html
#   2. General information about the RP2xxx port
#        https://docs.micropython.org/en/latest/rp2/general.html
#   3. Understanding and Implementing the HC-12 Wireless Transceiver Module - Mark Hughes, AllAboutCircuits, 2016nov02
#      https://www.allaboutcircuits.com/projects/understanding-and-implementing-the-hc-12-wireless-transceiver-module/
#   4. HC-12 vs nRF24L01 modules - Robin66, AllAboutCircuits, 2019may08
#      https://forum.allaboutcircuits.com/threads/hc-12-vs-nrf24l01-modules.159540/
#   5. HC-12 433MHz Transceiver 1km serial (Si4438) (Product Sheet, Tutorial) - ¥34
#      https://item.taobao.com/item.htm?spm=a1z1r.7974869.0.0.269c3ad4pAu1MO&id=636694630080
#   6. HC Tech (汇承) Official Web Site - HC Tech
#      http://www.hc01.com/home
#   7. HC12 Datasheet/User Manual v2.6 - HCTech 2018jul11
#      http://www.hc01.com/downloads/HC-12%20english%20datasheets.pdf
#   8. HC-12 433MHz RF Transciver Module (SI4438, 433MHZ, 1KM) - SmartPrototyping, US$12
#      https://www.smart-prototyping.com/HC-12-Wireless-Transceiver-Module-SI4438-433MHz-1km - US$12
#   9. Si4438 Transceiver Datasheet - Silicon Labs
#      https://www.silabs.com/documents/public/data-sheets/Si4438.pdf

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= ========= 

from machine import Pin, UART
import utime

# *** UART GP pin assignment and setup/configuration ***

uart0 = UART(0, baudrate = 9600, tx=Pin(0), rx=Pin(1))
uart1 = UART(1, baudrate = 9600, tx=Pin(8), rx=Pin(9))

uartPortDict = \
    {
     '0': uart0,
     '1': uart1,
    }

# HC12 GP pin assignment and setup/configuration ***

hc12SetupPinNum0 = 2
hc12SetupPinNum1 = 3

hc12SetupPin0 = Pin(hc12SetupPinNum0, Pin.OUT) 
hc12SetupPin1 = Pin(hc12SetupPinNum1, Pin.OUT)

hc12SetupPinDict = \
    {
        '0': hc12SetupPin0,
        '1': hc12SetupPin1,
    }

hc12ConfigParameterDict = \
    {
        'CheckAtReply'           : 'AT',
        'CheckAllConfigSetting'  : 'AT+RX',
        'SetChannel#1'           : 'AT+C001',
        'SetChannel#2'           : 'AT+C002',        
    }

hc12TextMsgDict = \
    {
        'HelloWorld'             : 'Hello World',
        'HelloPico0'             : 'Hello Pico #0',
        'HelloPico1'             : 'Hello Pico #1',
        'MoveForward'            : 'Move Forward',
        'MoveBackward'           : 'Move Backward',
        'Stop'                   : 'Stop'
    }     
        

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= ========= 

# *** Uart Functions ***

def uartWrite(uartPortNum, writeBytes):
    uartPort = uartPortDict[str(uartPortNum)]
    uartPort.write(writeBytes)
    return 

def uartRead(uartPortNum):
    uartPort = uartPortDict[str(uartPortNum)]
    uartAny = uartPort.any()
    print('    uartAny                     =', uartAny)
    readBytes = uartPort.read()
    return readBytes

# *** test uart loopback functions ***

def testUartLoopBack(uartPortNum, writeBytes):
    print('    Begin testUartLoopBack(), ...')
    print('      uartPortNum        =', uartPortNum)       
    
    uartWrite(uartPortNum, writeBytes)
    print('        writeBytes       =', writeBytes)    
     
    utime.sleep(0.5)
    
    readBytes = uartRead(uartPortNum)     
    print('        readBytes        =', readBytes)
    
    print('    End   testUartLoopBack().')
    return

def testUartListLoopBack(uartPortNumList, writeBytes):
    print('  Begin testUartLoopBack(), ...')
    print('    Remember to short TxD and RxD!!!')
    
    for uartPortNum in uartPortNumList:
        testUartLoopBack(uartPortNum, writeBytes)       

    print('  End   testUartLoopBack().')
    return

# *** Test Functions ***

#testUartListLoopBack([0], 'AT')    ### Only test uart0 for HC12 #0
#testUartListLoopBack([0, 1], 'AT')  ### Test both uart0 for HC12 #0, and uart1 for HC12 #1

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

# *** HC12 Functions ***

def setHc12ConfigMode(uartPortNum):
    hc12SetupPin = hc12SetupPinDict[str(uartPortNum)]
    hc12SetupPin.low()
    return

def setHc12CommunicationMode(uartPortNum):
    hc12SetupPin = hc12SetupPinDict[str(uartPortNum)]
    hc12SetupPin.high()
    return

# *** HC12 Test Functions ***

def testHc12Config(uartPortNum, writeBytes):
    print('Begin testHc12Config(), ...')    
    testUartLoopBack(uartPortNum, writeBytes)
    print('End   testHc12Config(), ...')     
    return

def testHc12ListConfig(uartPortNumList, writeBytes):
    print('Begin testHc12ListConfigOperation(), ...')       
    for uartPortNum in uartPortNumList:
        setHc12ConfigMode(uartPortNum)               
        testHc12Config(uartPortNum, writeBytes)       
    print('End   testHc12ListConfigOperation().')
    return

def testDualHc12Loopback(xmitUartPortNum, recvUartPortNum, testXmitMsg):
    print('Begin testHc12Communication(), ...')

    # *** Set both HC12 communication mode, ...')
    print('  Begin set both HC12s communication mode, ...')
    setHc12CommunicationMode(xmitUartPortNum)
    setHc12CommunicationMode(recvUartPortNum)
    print('  End   set both HC12s communication mode.')
    
    print('  Begin transmit message, ...')
    print('    xmitBytes to xmitUartPort   =', testXmitMsg)
    uartWrite(xmitUartPortNum, testXmitMsg)    
    print('  End transmit message.')        
    
    # *** uart1 recv test message ***
    print('  Begin receive message, ...')
    utime.sleep(0.1)    
    recvBytes = uartRead(recvUartPortNum)
    print('    recvBytes from receUartPort =', recvBytes)
    print('  End   receive msaages.')
    print('End   testHc12Communication(), ...')     
    return

# *** Sample Tests ***

#testHc12Config(0, 'AT')
#testHc12ListConfig([0, 1], 'AT')
#testHc12ListConfig([0, 1], 'AT+RX')
#testHc12ListConfigV02([0], 'CheckAtReply')
#testHc12ListConfigV02([0], 'CheckAllConfigSetting')
#testHc12ListConfigV02([0], 'SetChannel#1')
#testHc12ListConfigV02([0], 'SetChannel#2')

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Main ***

#testHc12ListConfig([0, 1], 'AT')

testDualHc12Loopback(xmitUartPortNum = 0, recvUartPortNum = 1, testXmitMsg = 'Hello Pico #2')

# .END

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

''' *** Sample output tlfong01 2021nov12hkt1739 ***
>>> %Run -c $EDITOR_CONTENT
Begin testHc12Communication(), ...
  Begin set both HC12s communication mode, ...
  End   set both HC12s communication mode.
  Begin transmit message, ...
    xmitBytes to xmitUartPort   = Hello Pico #2
  End transmit message.
  Begin receive message, ...
    uartAny                     = 13
    recvBytes from receUartPort = b'Hello Pico #2'
  End   receive msaages.
End   testHc12Communication(), ...
>>> 
'''

# *** End of sample output **

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

Pico #1 sends message to Pico #2 through same 433MHz Channel

Now I am going to test Pico #1 sending a text message to Pico #2 on the same 433MHz channel. I need to change the Thonny > Tools > Option >

> Disable > Allow only single Thonny instance

thonny_two_windows_2021nov1201


Testing Pico #1 and Pico #2 at the same time, both doing uart0 sending, uart1 receiving. Results = OK.



Testing Pico #1 transmitting text message to Pico #2 OK

Transmit program


# hc12_v50.py  tlfong01  2021nov13hkt1752
#
# Pico GP Pin Assignment
#   GP0 = UART0 TxD - connect to HC12 #0 RxD    
#   GP1 = UART0 RxD - connect to HC12 #0 TxD
#   GP8 = UART0 TxD - connect to HC12 #1 RxD    
#   GP9 = UART0 RxD - connect to HC12 #1 TxD
#   GP2 = TC12 #0 set pin - connect to HC12 #0 setPin
#   GP3 = TC12 #1 set pin - connect to HC12 #1 setPin

#   Debugging notes
#   GP4, GP5 for uart0 never works

# Setup notes
#   1. To test UART serialloop back, short TxD pin to RxD pin
#   2. To test HC12 #0, (1) Connect uart0 TxD to HC12 RxD, (2) Connect uart0 RxD to HC12 #0 TxD
#   3. To set TC12 partmeters, connect SET pin to Low,
#   4. To perform normal transmit/receive half duplex communcation, connect SET pin to High

# Troubleshooting notes
#   1. Use RealTerm (or miniCom etc) to do offline testing, without Pico
#   2. Remember to short Pico ground with HC12 ground get make a COMMON GROUND

# References
#   1. MicroPython Class UART – duplex serial communication bus
#        https://docs.micropython.org/en/latest/library/machine.UART.html
#   2. General information about the RP2xxx port
#        https://docs.micropython.org/en/latest/rp2/general.html
#   3. Understanding and Implementing the HC-12 Wireless Transceiver Module - Mark Hughes, AllAboutCircuits, 2016nov02
#      https://www.allaboutcircuits.com/projects/understanding-and-implementing-the-hc-12-wireless-transceiver-module/
#   4. HC-12 vs nRF24L01 modules - Robin66, AllAboutCircuits, 2019may08
#      https://forum.allaboutcircuits.com/threads/hc-12-vs-nrf24l01-modules.159540/
#   5. HC-12 433MHz Transceiver 1km serial (Si4438) (Product Sheet, Tutorial) - ¥34
#      https://item.taobao.com/item.htm?spm=a1z1r.7974869.0.0.269c3ad4pAu1MO&id=636694630080
#   6. HC Tech (汇承) Official Web Site - HC Tech
#      http://www.hc01.com/home
#   7. HC12 Datasheet/User Manual v2.6 - HCTech 2018jul11
#      http://www.hc01.com/downloads/HC-12%20english%20datasheets.pdf
#   8. HC-12 433MHz RF Transciver Module (SI4438, 433MHZ, 1KM) - SmartPrototyping, US$12
#      https://www.smart-prototyping.com/HC-12-Wireless-Transceiver-Module-SI4438-433MHz-1km - US$12
#   9. Si4438 Transceiver Datasheet - Silicon Labs
#      https://www.silabs.com/documents/public/data-sheets/Si4438.pdf

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= ========= 

from machine import Pin, UART
import utime

# *** UART GP pin assignment and setup/configuration ***

uart0 = UART(0, baudrate = 9600, tx=Pin(0), rx=Pin(1))
uart1 = UART(1, baudrate = 9600, tx=Pin(8), rx=Pin(9))

uartPortDict = \
    {
     '0': uart0,
     '1': uart1,
    }

# HC12 GP pin assignment and setup/configuration ***

hc12SetupPinNum0 = 2
hc12SetupPinNum1 = 3

hc12SetupPin0 = Pin(hc12SetupPinNum0, Pin.OUT) 
hc12SetupPin1 = Pin(hc12SetupPinNum1, Pin.OUT)

hc12SetupPinDict = \
    {
        '0': hc12SetupPin0,
        '1': hc12SetupPin1,
    }

hc12ConfigParameterDict = \
    {
        'CheckAtReply'           : 'AT',
        'CheckAllConfigSetting'  : 'AT+RX',
        'SetChannel#1'           : 'AT+C001',
        'SetChannel#2'           : 'AT+C002',        
    }

hc12TextMsgDict = \
    {
        'HelloWorld'             : 'Hello World',
        'HelloPico0'             : 'Hello Pico #0',
        'HelloPico1'             : 'Hello Pico #1',
        'MoveForward'            : 'Move Forward',
        'MoveBackward'           : 'Move Backward',
        'Stop'                   : 'Stop'
    }     
        

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= ========= 

# *** Uart Functions ***

def uartWrite(uartPortNum, writeBytes):
    uartPort = uartPortDict[str(uartPortNum)]
    uartPort.write(writeBytes)
    return 

def uartRead(uartPortNum):
    uartPort = uartPortDict[str(uartPortNum)]
    uartAny = uartPort.any()
    print('    uartAny   =', uartAny)
    readBytes = uartPort.read()
    return readBytes

# *** test uart loopback functions ***

def testUartLoopBack(uartPortNum, writeBytes):
    print('    Begin testUartLoopBack(), ...')
    print('      uartPortNum        =', uartPortNum)       
    
    uartWrite(uartPortNum, writeBytes)
    print('        writeBytes       =', writeBytes)    
     
    utime.sleep(0.5)
    
    readBytes = uartRead(uartPortNum)     
    print('        readBytes        =', readBytes)
    
    print('    End   testUartLoopBack().')
    return

def testUartListLoopBack(uartPortNumList, writeBytes):
    print('  Begin testUartLoopBack(), ...')
    print('    Remember to short TxD and RxD!!!')
    
    for uartPortNum in uartPortNumList:
        testUartLoopBack(uartPortNum, writeBytes)       

    print('  End   testUartLoopBack().')
    return

# *** Test Functions ***

#testUartListLoopBack([0], 'AT')    ### Only test uart0 for HC12 #0
#testUartListLoopBack([0, 1], 'AT')  ### Test both uart0 for HC12 #0, and uart1 for HC12 #1

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

# *** HC12 Functions ***

def setHc12ConfigMode(uartPortNum):
    hc12SetupPin = hc12SetupPinDict[str(uartPortNum)]
    hc12SetupPin.low()
    return

def setHc12CommMode(uartPortNum):
    hc12SetupPin = hc12SetupPinDict[str(uartPortNum)]
    hc12SetupPin.high()
    return

# *** HC12 Test Functions ***

def testHc12Config(uartPortNum, writeBytes):
    print('Begin testHc12Config(), ...')    
    testUartLoopBack(uartPortNum, writeBytes)
    print('End   testHc12Config(), ...')     
    return

def testHc12ListConfig(uartPortNumList, writeBytes):
    print('Begin testHc12ListConfigOperation(), ...')       
    for uartPortNum in uartPortNumList:
        setHc12ConfigMode(uartPortNum)               
        testHc12Config(uartPortNum, writeBytes)       
    print('End   testHc12ListConfigOperation().')
    return

def testDualHc12Loopback(xmitUartPortNum, recvUartPortNum, testXmitMsg):
    print('Begin testHc12Communication(), ...')

    # *** Set both HC12 communication mode, ...')
    print('  Begin set both HC12s communication mode, ...')
    setHc12CommMode(xmitUartPortNum)
    setHc12CommMode(recvUartPortNum)
    print('  End   set both HC12s communication mode.')
    
    print('  Begin transmit message, ...')
    print('    xmitBytes =', testXmitMsg)
    uartWrite(xmitUartPortNum, testXmitMsg)    
    print('  End transmit message.')        
    
    # *** uart1 recv test message ***
    print('  Begin receive message, ...')
    utime.sleep(0.1)    
    recvBytes = uartRead(recvUartPortNum)
    print('    recvBytes =', recvBytes)
    print('  End   receive msaages.')
    print('End   testHc12Communication(), ...')     
    return

def testPico1TransmitTextMsgEverySecond():
    print('Begin testPico1TransmitTextMsgEverySecond(), ...')

    # *** Set both HC12 communication mode, ...')
    print('  Begin set HC12 #1 communication mode, ...')
    uartPortNum = 0
    setHc12CommMode(uartPortNum = 0)
    print('  End   set HC12 #1 communication mode.')
    
    print('  Begin transmit message, ...')
    
    for count in range(100000):
        testXmitMsg = str(count) + ' Pico #1 HC12 #1 (uart0) transmit this msg'
        print('    xmitBytes =', testXmitMsg)
        uartWrite(uartPortNum, testXmitMsg)
        utime.sleep(1)
    print('  End   transmit message.')
    print('End   testPico1TransmitTextMsgEverySecond(), ...')    
    
    return

# *** Sample Tests ***

#testHc12Config(0, 'AT')
#testHc12ListConfig([0, 1], 'AT')
#testHc12ListConfig([0, 1], 'AT+RX')
#testHc12ListConfigV02([0], 'CheckAtReply')
#testHc12ListConfigV02([0], 'CheckAllConfigSetting')
#testHc12ListConfigV02([0], 'SetChannel#1')
#testHc12ListConfigV02([0], 'SetChannel#2')

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Main ***

#testHc12ListConfig([0, 1], 'AT')

#testDualHc12Loopback(xmitUartPortNum = 0, recvUartPortNum = 1, \
#    testXmitMsg = 'Pico #1 at COM 11, uart0 transmitting, ...')

testPico1TransmitTextMsgEverySecond()

# .END

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

''' Sample output  tlfong  1021nov13hkt1930
xmitBytes = 990 Pico #1 HC12 #1 (uart0) transmit this msg
    xmitBytes = 991 Pico #1 HC12 #1 (uart0) transmit this msg
    xmitBytes = 992 Pico #1 HC12 #1 (uart0) transmit this msg
    xmitBytes = 993 Pico #1 HC12 #1 (uart0) transmit this msg
    xmitBytes = 994 Pico #1 HC12 #1 (uart0) transmit this msg
    xmitBytes = 995 Pico #1 HC12 #1 (uart0) transmit this msg
    xmitBytes = 996 Pico #1 HC12 #1 (uart0) transmit this msg
    xmitBytes = 997 Pico #1 HC12 #1 (uart0) transmit this msg
    xmitBytes = 998 Pico #1 HC12 #1 (uart0) transmit this msg
    xmitBytes = 999 Pico #1 HC12 #1 (uart0) transmit this msg
    xmitBytes = 1000 Pico #1 HC12 #1 (uart0) transmit this msg
# *** End of sample output **
'''

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ==

Receive Program


# *** HC12 Functions ***

def setHc12ConfigMode(uartPortNum):
    hc12SetupPin = hc12SetupPinDict[str(uartPortNum)]
    hc12SetupPin.low()
    return

def setHc12CommMode(uartPortNum):
    hc12SetupPin = hc12SetupPinDict[str(uartPortNum)]
    hc12SetupPin.high()
    return

# *** HC12 Test Functions ***

def testHc12Config(uartPortNum, writeBytes):
    print('Begin testHc12Config(), ...')    
    testUartLoopBack(uartPortNum, writeBytes)
    print('End   testHc12Config(), ...')     
    return

def testHc12ListConfig(uartPortNumList, writeBytes):
    print('Begin testHc12ListConfigOperation(), ...')       
    for uartPortNum in uartPortNumList:
        setHc12ConfigMode(uartPortNum)               
        testHc12Config(uartPortNum, writeBytes)       
    print('End   testHc12ListConfigOperation().')
    return

def testDualHc12Loopback(xmitUartPortNum, recvUartPortNum, testXmitMsg):
    print('Begin testHc12Communication(), ...')

    # *** Set both HC12 communication mode, ...')
    print('  Begin set both HC12s communication mode, ...')
    setHc12CommMode(xmitUartPortNum)
    setHc12CommMode(recvUartPortNum)
    print('  End   set both HC12s communication mode.')
    
    print('  Begin transmit message, ...')
    print('    xmitBytes =', testXmitMsg)
    uartWrite(xmitUartPortNum, testXmitMsg)    
    print('  End transmit message.')        
    
    # *** uart1 recv test message ***
    print('  Begin receive message, ...')
    utime.sleep(0.1)    
    recvBytes = uartRead(recvUartPortNum)
    print('    recvBytes =', recvBytes)
    print('  End   receive msaages.')
    print('End   testHc12Communication(), ...')     
    return

def testPico2ReceiveTextMsgEverySecond():
    print('Begin testPico2ReceiveTextMsgEverySecond(), ...')

    # *** Set both HC12 communication mode, ...')
    print('  Begin set HC12 #1 communication mode, ...')
    uartPortNum = 0
    setHc12CommMode(uartPortNum = 0)
    print('  End   set HC12 #1 communication mode.')
    
    print('  Begin receive message, ...')
    
    for count in range(100000):
        recvMsg = uartRead(uartPortNum)
        print('    recvBytes =', recvMsg)
        utime.sleep(1)
    print('  End   transmit message.')
    print('End   testPico2ReceiveTextMsgEverySecond(), ...')    
    
    return

# *** Sample Tests ***

#testHc12Config(0, 'AT')
#testHc12ListConfig([0, 1], 'AT')
#testHc12ListConfig([0, 1], 'AT+RX')
#testHc12ListConfigV02([0], 'CheckAtReply')
#testHc12ListConfigV02([0], 'CheckAllConfigSetting')
#testHc12ListConfigV02([0], 'SetChannel#1')
#testHc12ListConfigV02([0], 'SetChannel#2')

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

# *** Main ***

#testHc12ListConfig([0, 1], 'AT')

#testDualHc12Loopback(xmitUartPortNum = 0, recvUartPortNum = 1, \
#    testXmitMsg = 'Pico #2 at COM 7, uart0 transmitting, ...')

testPico2ReceiveTextMsgEverySecond()

# .END

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

''' Sample output  tlfong01  2021nov13hkt1932
 recvBytes = b'1075 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 46
    recvBytes = b'1076 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 46
    recvBytes = b'1077 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 46
    recvBytes = b'1078 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 43
    recvBytes = b'0 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 43
    recvBytes = b'1 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 43
    recvBytes = b'2 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 43
    recvBytes = b'3 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 43
    recvBytes = b'4 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 43
    recvBytes = b'5 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 43
    recvBytes = b'6 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 43
    recvBytes = b'7 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 43
    recvBytes = b'8 Pico #1 HC12 #1 (uart0) transmit this msg'
    uartAny   = 43

'''

# *** End of sample output **

# ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= =========

BlueTooth Android Phone Accelerometer 4WD

So I more or less completed the task of using HC12 433MHz transceiver to let my three Pico 4WD to talk to each other. But then this morning I read MagPi that a guy using an Android phone with built in accelerometer to control a 4WD with BlueTooth module. I am getting jealous again. So I will also do that - using BleuTooth! :slight_smile:

[BlueTooth] Raspberry Pi Pico robot - 12th Nov 2021 Ashley Whittaker

[Youtube] Raspberry Pi Pico robot - 12th Nov 2021 Ashley Whittaker



Now I am reading the TB6612FNG’s cheat sheet, before wiring it up to Pico #1 with HC12 433MHz transceiver.




Intergration of Pico MCU, HC12 RF Transceiver, TB6612FNG DC Motor Driver



TB6612FNG DC Motor Driver Test


Pico # 1 + HC12 x 2 + TB6612FNG x 2 Pin Assignment

Pico has barely enough GP pins for 4WD. For 6WD, I need to use GPIO expanders, such as MCP23017



The jealous guy, ie, me read the following PC Mag article this morning.


Refactoring old Pico 4WD TB6612FNG program to merge HC12 functions

Note - hitting 32k words limit, need new reply


/ to continue, …

BlueTooth UART Modules for Pico Smart 4WD

Now I am adding two BlueTooth UART slave modules to the smart 4WD, so I can use an Android smart phone with built in accelerometer and magnetometer to play with the 2WD through 2.4GHz BlueTooth.



# *** pico_4wd_v85.py - tlfong01, 2021nov17hkt1937 ***

# 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  = 10 #2
bPwmPinNum1  = 11 #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  = 22 #14
aIn2PinNum1  = 23 #15
bIn1PinNum1  = 27 #16
bIn2PinNum1  = 28 #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.

defaultPwmFreq   = 1000
defaultDutyCycle = 90

dutyCycleDict = {
    'VeryVerySlow' : 95,
    'VeryFast'     : 90,
    'Fast'         : 80,
    'Normal'       : 50,
    'Slow'         : 40,
    'VerySlow'     : 30,
    'VeryVerySlow' : 25,
    }


'''
motorConfigDict00 = {'MotorDriverNum': 0, 'ChannelNum': 0}
motorConfigDict01 = {'MotorDriverNum': 0, 'ChannelNum': 1}
motorConfigDict10 = {'MotorDriverNum': 1, 'ChannelNum': 0}
motorConfigDict11 = {'MotorDriverNum': 1, 'ChannelNum': 1}

motorConfigDictList_00_01_10_11 = [motorConfigDict00, motorConfigDict01, motorConfigDict10, motorConfigDict11]
motorConfigDictList01 = motorConfigDictList_00_01_10_11

motorConfigDictListDict = {'FourMotorsList' : motorConfigDictList01,
                }
'''

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 setupMotorOld(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 ***
    
    motorControlDict = {'StdByPin': stdByPin,
                        'In1Pin'  : in1Pin,
                        'In2Pin'  : in2Pin,
                        'PwmPin'  : pwmPin,
                        'IntPin'  : intPin,
                       }
    return motorControlDict

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.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 ***
    
    motorControlDict = {'StdByPin': stdByPin,
                        'In1Pin'  : in1Pin,
                        'In2Pin'  : in2Pin,
                        'PwmPin'  : pwmPin,
                        'IntPin'  : intPin,
                       }
    return motorControlDict

# 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 moveMotorDirection(motorControlDict, directionName):
    if directionName =='Forward':
        motorControlDict['In1Pin'].low()
        motorControlDict['In2Pin'].high()
    elif directionName == 'Backward':
        motorControlDict['In1Pin'].high()
        motorControlDict['In2Pin'].low()       
    return
    
def moveMotorSpeed(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 stopMotorList(motorControlDictList):
    for motorControlDict in motorControlDictList:
        stopMotor(motorControlDict)
    return

# *** Test functions ***

def testSetupMoveMotorDirectionSpeedList(motorNumList, directionName, speedName, secondsName):
    print('Begin testSetupMoveMotorList(), ...')  
    motorControlDictList = setupMotorList(motorNumList)
    moveMotorDirectionSpeedList(motorControlDictList, directionName, speedName) # move motor list driection and speed
    utime.sleep(2)
    print('After 2 seconds, ...')  
    repeatCountIntPinNumListIntPeriod(intPinNumList = [0, 1, 2, 3], countPeriod = 0.1, pauseTime = 0.1, repeatTimes = 10)    
    utime.sleep(1)       
    stopMotorList(motorControlDictList)
    print('End   testSetupMoveMotorList(), ...')    
    return

# *** Sample test functions calls ***
#testSetupMoveMotorDirectionSpeedList([0, 1, 2, 3], 'Forward',  'VerySlow', 'FourSeconds')
#testSetupMoveMotorDirectionSpeedList([0, 1, 2, 3], 'Backward', 'VeryFast', 'FourSeconds')
#testSetupMoveMotorDirectionSpeedList([0, 1, 2, 3], 'Forward',  'Normal',   'TwoSeconds')
#testSetupMoveMotorDirectionSpeedList([0, 1, 2, 3], 'Forward',  'Normal',   'SixtySeconds')
#testSetupMoveMotorDirectionSpeedList([0, 1, 2, 3], 'Forward',  'Normal',   'ThreeMinutes')
#testSetupMoveMotorDirectionSpeedList([0, 1, 2, 3], 'Forward',  'VerySlow', 'TenSeconds')
#testSetupMoveMotorDirectionSpeedList([0, 1, 2, 3], 'Forward',  'Normal',   'FourSeconds')

# ========= ========= ========= ========= ========= ========= ========= ========= 
# ========= ========= ========= ========= ========= ========= ========= =========

'''
# *** 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 ***

print('Begin setupMotor(), ...  tlfong01 2021nov1701')
testSetupMoveMotorDirectionSpeedList([0, 1, 2, 3], 'Forward',  'Normal', 'TwoSeconds')
print('End   setupMotor(), ...')

# *** End ***

''' 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(), ...
>>>
'''

HC12 References

HC-02 bluetooth serial port uart 3.3v TTL Datasheet

http://www.hc01.com/downloads/HC-02%20english%20datasheet.pdf



Edge Impulse and TinyML References

Build TinyML Models Using Your Mobile Phone TINYML - Jan Jongboom 2020apr11

Machine Learning Using Your Mobile Phone with Edge Impulse - 2020apr03

What Is Edge Impulse and tinyML? - 2020nov20

Top 5 Projects on Raspberry Pi Pico - Abhishek Jadhav 2021nov16

Pico Motor Driver


Kitronix Zoom Tech Talks - Motor Driver/Robotics Board For Raspberry Pi Pico - 2021may14


Now I am looking into TinyML. I have almost made up my mind to try it on my Pico 4WD.

Why TinyML Is Such A Big Deal - Bryon Moyer 2021sep02

About tinyML

tinyML Vision Challenge – Winners October 08, 2021


The Ultimate pi-top Holiday Gift Guide

https://www.pi-top.com/diypromo?hsCtaTracking=6c196cb8-ea4c-4eab-8683-edcff62b4c19|41e68e3b-99a6-4bdf-b312-84d3d2ad56f3


Pico Smart 4WD Part 2

My part 1 project blog is getting too long for the forum’s editor to handle, so the response time is now unbearingly long. So I need to end this TLDR part 1 and start Part 2.

Update 2021nov23hkt1219 - I opened the project’s Part 2 as a new topic but found the forum’s editor is also very long. So I am using offline Penzu editing to save time and space.

/ to continue in Part 2, …

The tcbscabs is notable for having a large selection of books and novels spanning a wide range of genres. Literature enthusiasts looking for a digital haven for exploration often turn to the platform because of its dedication to providing high-quality scans and a vast selection of literary content.