Making a Rpi Pico Based Smart Vehicle - Part 2

Introduction

This is Part 2 of the Project with the same title.



Summary of Part 1

Part 1 microPython program now has 4 python modules:

  1. Pico system Uart

  2. HC12 RF xmit/recv

  3. TB6612FNG 4WD motor driving

  4. Pico system interrupt


# *** pico_4wd_v90.py - tlfong01, 2021nov19hkt1719 ***

# Brief Description
# 1. Smart 4WD based on Rpi Pico, TB6612FNG, DC/BLDC motors, 433MHz HC12, 2.6GHz BLE HC02, Androd smart phone with
#    acceleromter and magnetometer

# Contents
# 1. Pico 4WD with TB6612 DC Motor Drivers and gear encoder motors N20, tt130, and TM310
#    1.1 Interrupt functions
#    1.2 DC motor function
# 2. Pico 4Wd with BLDC motors with built motor drivers (ie, TB6612FNG is not required
# 3. HC12 433MHz RF transceivers
#    3.1  uart loop back functions
#    3.2  HC12 transmit/receive echo functions
# 4. HC02 2.6GHz BLE slave modules
# 5. Integrating Parts 1, 2 with Parts 3, 4

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

from machine import Pin, PWM
import utime

# *** Pico GP pin assignments ***

uart0TxDNum  = 0 # HC12 #1 TxD
uart0RdDNum  = 1 # HC12 #2 RxD

hc12Setup1   = 2 # Reserved for SPI0 Sck
hc12Setup2   = 3 # Reserved for SPI0 Tx
i2c0Sda      = 4 # Reserved for SPI0 Rx
i2c0Scl      = 5 # Reserved for SPI0 Csn  

# *** PWM Pins ***

aPwmPinNum0  = 6 #0
bPwmPinNum0  = 7 #1

uart1TxdNum  = 8 # HC12 #2 TxD
uart1RxdNum  = 9 # HC12 #2 RxD

aPwmPinNum1  = 11 #2
bPwmPinNum1  = 10 #3

# *** Inrerrupt Pins ***

intPinNum0 = 12 #4 
intPinNum1 = 13 #5 
intPinNum2 = 14 #6 
intPinNum3 = 15 #7 

# *** Motor Driver Control Pins (TB6612FNG) ***

stdByPinNum0 = 16 #8
stdByPinNum1 = 17 #9

aIn1PinNum0  = 18 #10
aIn2PinNum0  = 19 #11
bIn1PinNum0  = 20 #12
bIn2PinNum0  = 21 #13

aIn1PinNum1  = 27 #14
aIn2PinNum1  = 28 #15
bIn1PinNum1  = 22 #16
bIn2PinNum1  = 26 #17

# *** Interrupt Pin Dicts ***

intGpPinNumDict = {'0': intPinNum0, 
                   '1': intPinNum1, 
                   '2': intPinNum2, 
                   '3': intPinNum3, 
                  }

intPinNumList = [intPinNum0, intPinNum1, intPinNum2, intPinNum3]

# Comments
# 1. There are 4 GP pins to read interrupts: intPinNum0, inPinNum1, intPinNum2, intPinNum3.

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

# *** Sleep time dicts ***

secondsDict = {'OneSecond'    :   1,
               'TwoSeconds'   :   2,
               'FourSeconds'  :   4,
               'TenSeconds'   :  10,               
               'SixtySeconds' :  60,
               'ThreeMinutes' : 180,
              }

def hold(secondsName):
    utime.sleep(secondsDict[secondsName])
    return

# Comments
# 1. Hold function is friendly version of utime.sleep.

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

# *** Interrupt global variables and dicts ***

global intCount0 
global intCount1
global intCount2
global intCount3

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

intCountDict = {
    '0': intCount0,
    '1': intCount1,
    '2': intCount2,
    '3': intCount3,
    }

# Comments
# 1. There are four global variable to hold interrupt event counts.
# 2. For this 4WD, the four interrupt signals are the four motor's rotary encoder output signals.
    
# *** Interrupt Callback Functions ***   

def intCallBack0(pin):
    global intCount0
    intCount0 = intCount0 + 1    
    return

def intCallBack1(pin):
    global intCount1
    intCount1 = intCount1 + 1    
    return

def intCallBack2(pin):
    global intCount2
    intCount2 = intCount2 + 1    
    return

def intCallBack3(pin):
    global intCount3
    intCount3 = intCount3 + 1    
    return

intCallBackDict = {
    '0': intCallBack0,
    '1': intCallBack1,
    '2': intCallBack2,
    '3': intCallBack3,    
    }

def countIntPinIntPeriod(intPinNum, countPeriod):
    global intCount0
    global intCount1
    global intCount2
    global intCount3
    
    intCount0 = 0
    intCount1 = 0
    intCount2 = 0
    intCount3 = 0

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

def countIntPinNumListIntPeriod(intPinNumList, countPeriod):
    intCountList = [0] * len(intPinNumList)
    for index in range(len(intPinNumList)):
        intCountList[index] = countIntPinIntPeriod(intPinNumList[index], countPeriod)                       
    return intCountList

# Comments
# 1. countIntPinIntPeriod(intPinNum, countPeriod) is to count the number of interrupts at the interrupt pin denoted by the
#      interrupt pin number.

# *** Test functions ***

def repeatCountIntPinNumListIntPeriod(intPinNumList, countPeriod, pauseTime, repeatTimes):
    print('\n  countIntPinNumListIntPeriod()')
    intGpPinNumList = [0] * len(intPinNumList)
    for index in range(len(intGpPinNumList)):
        intGpPinNumList[index]     = intGpPinNumDict[str(index)]
    print('    intPinNumList           =', intPinNumList)
    print('    intGpPinNumList         =', intGpPinNumList)
    print('    countPeriod (seconds)   =', countPeriod)
    print('    pauseTime (seconds)     =', pauseTime)    
    print('    repeat count times      =', repeatTimes)
    print('')
    
    for count in range(repeatTimes):
        ppsList             = countIntPinNumListIntPeriod(intPinNumList, countPeriod)
        print('    countList =', ppsList, end = '')
        print(' , min ', min(ppsList), end = '')
        print(' , max ', max(ppsList), end = '')
        print(' , dif ', max(ppsList) - min(ppsList), end = '')
        print(' , avg ', int(sum(ppsList) / len(ppsList)))      
        utime.sleep(pauseTime)    
    return

# Comments
# 1. repeatCountIntPinNumListIntPeriod(intPinNumList, countPeriod, pauseTime, repeatTimes)
#      repeatedly counts and prints tinterrupt events in countPeriod and p

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

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

# Comments
# 1. This 4WD uses two TB6612FNG DC motor drivers, each with two driver channels, with a total of 4 channels for four motors.
# 2. BLDC motor have built in motor drivers, therefor is not handled by TB6612 motor driver.

defaultDirection = 'Forward'
defaultSpeed     = 'VertHighSpeed'
defaultPwmFreq   = 1000
defaultDutyCycle = 90

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

motorConfigDictDict = \
    {
        '0': {'MotorDriverNum': 0, 'ChannelNum': 0},
        '1': {'MotorDriverNum': 0, 'ChannelNum': 1},
        '2': {'MotorDriverNum': 1, 'ChannelNum': 0},
        '3': {'MotorDriverNum': 1, 'ChannelNum': 1},        
    }

# Comment
# 1. There are four DC motors, each denoted/represented by a Motor Config Dictionary.
# 2. A motor config dict has two elementa:
#      (a) MotorDriverNum which the the number of one of the two TB6612FNG motor drivers.
#      (b) Channel Number, denoting each of the two channel of the motor driver.
# 3. motorConfigDictList01 = motorConfigDictList_00_01_10_11 = the list of all four motor confict dictionaries.
# 4. motorConfigDictListDict is the Dict of motorConfigDictLists (only one such dict list for now)

motorDriverGpPinNumDict = { \
    '0': {'StdByPinNum'  : stdByPinNum0,             
          '0' : {'In1PinNum'      : aIn1PinNum0,  
                 'In2PinNum'      : aIn2PinNum0,  
                 'PwmPinNum'      : aPwmPinNum0,
                 'PwmFreq'        : defaultPwmFreq,
                 'DutyCycle'      : defaultDutyCycle,
                 'IntPinNum'      : intPinNum0,
                 'IntPinCallBack' : intCallBack0,                 
                },
          '1' : {'In1PinNum'      : bIn1PinNum0,  
                 'In2PinNum'      : bIn2PinNum0,  
                 'PwmPinNum'      : bPwmPinNum0,
                 'PwmFreq'        : defaultPwmFreq,
                 'DutyCycle'      : defaultDutyCycle,
                 'IntPinNum'      : intPinNum1,
                 'IntPinCallBack' : intCallBack1,                  
                },  
          },                   
    '1': {'StdByPinNum'  : stdByPinNum1,             
          '0' : {'In1PinNum'      : aIn1PinNum1,  
                 'In2PinNum'      : aIn2PinNum1,  
                 'PwmPinNum'      : aPwmPinNum1,
                 'PwmFreq'        : defaultPwmFreq,
                 'DutyCycle'      : defaultDutyCycle,
                 'IntPinNum'      : intPinNum2,
                 'IntPinCallBack' : intCallBack2,                  
                },
          '1' : {'In1PinNum'      : bIn1PinNum1,  
                 'In2PinNum'      : bIn2PinNum1,  
                 'PwmPinNum'      : bPwmPinNum1,
                 'PwmFreq'        : defaultPwmFreq,
                 'DutyCycle'      : defaultDutyCycle,
                 'IntPinNum'      : intPinNum3,
                 'IntPinCallBack' : intCallBack3                  
                },  
          }, 
    }

# Comment
# 1. motorDriverGpPinNumDict specifies
#    (a) the GP pin numbers for the two TB6612FNG motor drivers ecah with two channels.
#    (b) the default values such as PWM frequency, duty cycles

def setupMotor(motorNum):
    motorConfigDict = motorConfigDictDict[str(motorNum)]
    motorDriverNum  = motorConfigDict['MotorDriverNum']
    channelNum      = motorConfigDict['ChannelNum']
    
    stdByPinNum     = motorDriverGpPinNumDict[str(motorDriverNum)]['StdByPinNum']
    in1PinNum       = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['In1PinNum']
    in2PinNum       = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['In2PinNum']
    
    pwmPinNum       = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmPinNum']
    pwmFreq         = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmFreq']    
    dutyCycle       = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['DutyCycle']     
    
    intPinNum       = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['IntPinNum']
    intPinCallBack  = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['IntPinCallBack']

    # *** Motor Driver Control Pin Setup ***    
    
    stdByPin    = Pin(stdByPinNum, Pin.OUT)
    in1Pin      = Pin(in1PinNum, Pin.OUT)    
    in2Pin      = Pin(in2PinNum, Pin.OUT)
    intPin      = Pin(intPinNum, Pin.IN, Pin.PULL_DOWN)
  
    stdByPin.high()
    in1Pin.low()
    in2Pin.low()

    # *** PWM Pin Setup ***      
    
    pwmPin      = PWM(Pin(pwmPinNum))
    pwmPin.freq(pwmFreq)
    u16DutyCycle = int((dutyCycle / 100) * 65536)  
    pwmPin.duty_u16(u16DutyCycle)
    
    # *** Interrupt Pin Setup ***
    
    intPin.irq(intPinCallBack, Pin.IRQ_FALLING)
    
    # *** Motor Control Dict ***
    
    motorControlDict = {'StdByPin': stdByPin,
                        'In1Pin'  : in1Pin,
                        'In2Pin'  : in2Pin,
                        'PwmPin'  : pwmPin,
                        'IntPin'  : intPin,
                       }
    
    motorStatusDict = {'Direction'   : defaultDirection,
                       'Speed'       : defaultSpeed,
                       'PwmFrequency': defaultPwmFreq,
                       'DutyCycle'   : defaultDutyCycle,
                      }                       

    motorDict = {'MotorConfictDict' : motorConfigDict,
                 'MotorControlDict' : motorControlDict,
                 'MotorStatusDict'  : motorStatusDict
                }    

    return motorDict

# Comments
# 1. setupMotor(motorNum) perfroms the following things:
#    1.1 setup and intiralize control/pwm/interrupt pin objects from controlPinNum controlPin objects
#    1.2 setup interrupt call back functions
#    1.3 returns motorControlDict which is a dictionary of the motor's pin objects (stdBy, Input, Pwm, Interrupt)

def setupMotorList(motorNumList):
    motorControlDictList = [0] * len(motorNumList)        
    for motorNum in motorNumList:
        motorControlDict = setupMotor(motorNum)
        motorControlDictList[motorNum] = motorControlDict
    return motorControlDictList

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

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

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

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

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

def stopMotorList(motorControlDictList):
    for motorControlDict in motorControlDictList:
        stopMotor(motorControlDict)
    return

# *** Test setup/stop/move motor functions ***

def testSetupMotor(motorNum):
    print('Begin testSetupMotor(), ', 'motorNum =', motorNum)
    motorControlDict = setupMotor(motorNum)['MotorControlDict']
    stopMotor(motorControlDict)
    print('End   testSetupMotor().')
    return

def testSetupMotorList(motorNumList):
    for motorNum in motorNumList:
        testSetupMotor(motorNum)
    return

def testSetupMoveMotor(motorNum, directionName, speedName, holdSecondsName):
    print('Begiun testSetupMoveMotor(), ', 'motorNum =', motorNum)
    motorDict = setupMotor(motorNum)
    motorControlDict = motorDict['MotorControlDict']
    stopMotor(motorControlDict)
    setupMotorDirection(motorControlDict, directionName)
    setupMotorSpeed(motorControlDict, speedName)    
    hold(holdSecondsName)
    stopMotor(motorControlDict)
    print('End   testSetupMoveMotor().')    
    return

def testSetupMoveMotorList(motorNumList, directionName, speedName, holdSecondsName):
    print('Begiun testSetupMoveMotorNumList(), ...')
    for motorNum in motorNumList:
        motorDict = setupMotor(motorNum)
        motorControlDict = motorDict['MotorControlDict']
        stopMotor(motorControlDict)
        setupMotorDirection(motorControlDict, directionName)
        setupMotorSpeed(motorControlDict, speedName)    
        hold(holdSecondsName)
        stopMotor(motorControlDict)
    print('End   testSetupMoveMotorNumList().')    
    return

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

'''
# *** BLDC Config/Fuctnions ***

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

def changeBldcMotorSpeed(motorControlDict, speedName):
    pwmPin = motorControlDict['PwmPin']
    dutyCycle = dutyCycleDict[speedName]
    pwmPin.duty_u16(int((dutyCycle / 100) * 65536) )
    return

def setupBldcMotor(motorConfigDict):
    motorDriverNum = motorConfigDict['MotorDriverNum']
    channelNum     = motorConfigDict['ChannelNum']
    
    stdByPinNum    = motorDriverGpPinNumDict[str(motorDriverNum)]['StdByPinNum']
    in1PinNum      = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['In1PinNum']
    in2PinNum      = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['In2PinNum']
    
    pwmPinNum      = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmPinNum']
    pwmFreq        = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmFreq']    
    dutyCycle      = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['DutyCycle']     
    
    intPinNum      = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['IntPinNum']
    intPinCallBack = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['IntPinCallBack']

    # *** Motor Driver Control Pin Setup ***    
    
    stdByPin    = Pin(stdByPinNum, Pin.OUT)
    in1Pin      = Pin(in1PinNum, Pin.OUT)    
    in2Pin      = Pin(in2PinNum, Pin.OUT)
    intPin      = Pin(intPinNum, Pin.IN, Pin.PULL_DOWN)
  
    stdByPin.high()
    in1Pin.low()
    in2Pin.high()

    # *** PWM Pin Setup ***      
    
    pwmPin      = PWM(Pin(pwmPinNum))
    pwmPin.freq(pwmFreq)
    u16DutyCycle = int((dutyCycle / 100) * 65536)  
    pwmPin.duty_u16(u16DutyCycle)
    
    # *** Interrupt Pin Setup ***
    
    intPin.irq(intPinCallBack, Pin.IRQ_FALLING)
    
    # *** Motor Control Dict ***
    
    motorControlDictBldc = {'StdByPin': stdByPin,
                            'In1Pin'  : in1Pin,
                            'In2Pin'  : in2Pin,
                            'PwmPin'  : pwmPin,
                            'IntPin'  : intPin,
                           }
# Test functions 

def testBldcMotor00():
    print('  Begin testBldcMotor00(), ...')
    motorConfigDict = {'MotorDriverNum': 0, 'ChannelNum': 0}
    setupBldcMotor(motorConfigDict)
    
    hold('TwoSeconds')
    changeBldcMotorSpeed(motorConfigDict, 'VeryFast')
    hold('TwoSeconds')
    utime.sleep(2)
    changeBldcMotorDirection(motorConfigDict, 'CCW')    
    utime.sleep(2)
    changeBldcMotorDirection(motorConfigDict, 'CW') 
    changeBldcMotorSpeed(motorConfigDict, 'VerySlow')
    utime.sleep(2)
    
    print('  End   testSetupMotor00(), ...')
    return

# *** Sample test function call

#testBldcMotor00()

'''
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========
# ========= ========= ========= ========= ========= ========= ========= ========= ========= =========

''' Old main test sample outputs

*** Sample Output  tlfong01  2021oct11hkt1955 ***
>>> %Run -c $EDITOR_CONTENT
Begin testSetupMoveMotorList(), ...
After 2 seconds, ...

  countIntPinNumListIntPeriod()
    intPinNumList           = [0, 1, 2, 3]
    intGpPinNumList         = [4, 5, 6, 7]
    countPeriod (seconds)   = 0.1
    pauseTime (seconds)     = 0.1
    repeat count times      = 10

    countList = [296, 219, 291, 205] , min  205 , max  296 , dif  91 , avg  252
    countList = [286, 215, 295, 208] , min  208 , max  295 , dif  87 , avg  251
    countList = [288, 217, 300, 213] , min  213 , max  300 , dif  87 , avg  254
    countList = [301, 223, 298, 207] , min  207 , max  301 , dif  94 , avg  257
    countList = [271, 223, 308, 207] , min  207 , max  308 , dif  101 , avg  252
    countList = [287, 223, 305, 203] , min  203 , max  305 , dif  102 , avg  254
    countList = [277, 233, 306, 226] , min  226 , max  306 , dif  80 , avg  260
    countList = [282, 240, 299, 222] , min  222 , max  299 , dif  77 , avg  260
    countList = [294, 225, 307, 209] , min  209 , max  307 , dif  98 , avg  258
    countList = [299, 223, 303, 229] , min  223 , max  303 , dif  80 , avg  263
End   testSetupMoveMotorList(), ...
>>> 
'''

# *** Main Test ***

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

# *** Main ***

#testSetupMotor(motorNum = 0)
#testSetupMotorList(motorNumList = [0, 1, 2, 3])

#testSetupMoveMotor(motorNum = 0, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')
#testSetupMoveMotor(motorNum = 1, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')
#testSetupMoveMotor(motorNum = 2, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')
#testSetupMoveMotor(motorNum = 3, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')

testSetupMoveMotorList([0, 1, 2, 3], 'Forward', 'VeryFast', 'TwoSeconds')

# *** End ***

'''
>>> %Run -c $EDITOR_CONTENT
Begiun testSetupMoveMotorNumList(), ...
End   testSetupMoveMotorNumList().
>>>
'''

''' Sample output  tlfong01  2021nov17hkt2033
>>> %Run -c $EDITOR_CONTENT
Begin setupMotor(), ...  tlfong01 2021nov1701
Begin testSetupMoveMotorList(), ...
After 2 seconds, ...

  countIntPinNumListIntPeriod()
    intPinNumList           = [0, 1, 2, 3]
    intGpPinNumList         = [12, 13, 14, 15]
    countPeriod (seconds)   = 0.1
    pauseTime (seconds)     = 0.1
    repeat count times      = 10

    countList = [0, 0, 0, 0] , min  0 , max  0 , dif  0 , avg  0
    countList = [0, 0, 0, 0] , min  0 , max  0 , dif  0 , avg  0
    countList = [0, 0, 0, 0] , min  0 , max  0 , dif  0 , avg  0
    countList = [0, 0, 0, 0] , min  0 , max  0 , dif  0 , avg  0
    countList = [0, 0, 0, 0] , min  0 , max  0 , dif  0 , avg  0
    countList = [0, 0, 0, 0] , min  0 , max  0 , dif  0 , avg  0
    countList = [0, 0, 0, 0] , min  0 , max  0 , dif  0 , avg  0
    countList = [0, 0, 0, 0] , min  0 , max  0 , dif  0 , avg  0
    countList = [0, 0, 0, 0] , min  0 , max  0 , dif  0 , avg  0
    countList = [0, 0, 0, 0] , min  0 , max  0 , dif  0 , avg  0
End   testSetupMoveMotorList(), ...
End   setupMotor(), ...
>>>
'''

/ to continue, …

Now Testing Driving 4 wheels and RF transmission at the same time.

testSetupMoveMotorListSequential([frontLeftWheel, frontRightWheel, rearLeftWheel, rearRightWheel], 'Forward', 'VeryFast', 'TwoSeconds')
testSetupMoveMotorListConcurrent([frontLeftWheel, frontRightWheel, rearLeftWheel, rearRightWheel], 'Backward', 'VerySlow', 'FourSeconds')


# *** pico_4wd_v95.py - tlfong01, 2021nov20hkt1516 ***

from machine import Pin, PWM, 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

# *** UARTTest Functions ***

#testUartLoopBack(uartPortNum = 0, writeBytes = 'uart0 Hello World')
#testUartLoopBack(uartPortNum = 1, writeBytes = 'uart1 Hello World')

# *** Sample output ***
'''
>>> %Run -c $EDITOR_CONTENT
    Begin testUartLoopBack(), ...
      uartPortNum        = 0
        writeBytes       = uart0 Hello World
    uartAny   = 17
        readBytes        = b'uart0 Hello World'
    End   testUartLoopBack().
    Begin testUartLoopBack(), ...
      uartPortNum        = 1
        writeBytes       = uart1 Hello World
    uartAny   = 17
        readBytes        = b'uart1 Hello World'
    End   testUartLoopBack().
>>>
'''

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

hc12UartPortNumDict = \
           {
             '0': 0,
             '1': 1,
           }            

# *** HC12 Functions ***

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

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

# *** HC12 Test Functions ***

def testHc12Config(hc12Num, writeBytes):
    print('Begin testHc12Config(), ...')
    uartPortNum = hc12UartPortNumDict[str(hc12Num)]
    setHc12ConfigMode(uartPortNum)
    utime.sleep(0.1)  
    testUartLoopBack(uartPortNum, writeBytes)
    print('End   testHc12Config(), ...')     
    return

# *** Sample Tests ***
#testHc12Config(hc12Num = 0, writeBytes = 'AT')
#testHc12Config(hc12Num = 1, writeBytes = 'AT')

''' *** Sample output ***
>>> %Run -c $EDITOR_CONTENT
Begin testHc12Config(), ...
    Begin testUartLoopBack(), ...
      uartPortNum        = 0
        writeBytes       = AT
    uartAny   = 4
        readBytes        = b'OK\r\n'
    End   testUartLoopBack().
End   testHc12Config(), ...
Begin testHc12Config(), ...
    Begin testUartLoopBack(), ...
      uartPortNum        = 1
        writeBytes       = AT
    uartAny   = 4
        readBytes        = b'OK\r\n'
    End   testUartLoopBack().
End   testHc12Config(), ...
>>> 
'''

def testHc12Communication(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

# *** Sample Tests ***

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

''' *** Sample Output ***
>>> %Run -c $EDITOR_CONTENT
Begin testHc12Communication(), ...
  Begin set both HC12s communication mode, ...
  End   set both HC12s communication mode.
  Begin transmit message, ...
    xmitBytes = Pico #1 at COM 11, uart0 transmitting, ...
  End transmit message.
  Begin receive message, ...
    uartAny   = 42
    recvBytes = b'Pico #1 at COM 11, uart0 transmitting, ...'
  End   receive msaages.
End   testHc12Communication(), ...
>>>
'''

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

# *** Pico GP pin assignments ***

uart0TxDNum  = 0 # HC12 #1 TxD
uart0RdDNum  = 1 # HC12 #2 RxD

hc12Setup1   = 2 # Reserved for SPI0 Sck
hc12Setup2   = 3 # Reserved for SPI0 Tx
i2c0Sda      = 4 # Reserved for SPI0 Rx
i2c0Scl      = 5 # Reserved for SPI0 Csn  

# *** PWM Pins ***

aPwmPinNum0  = 6 #0
bPwmPinNum0  = 7 #1

uart1TxdNum  = 8 # HC12 #2 TxD
uart1RxdNum  = 9 # HC12 #2 RxD

aPwmPinNum1  = 11 #2
bPwmPinNum1  = 10 #3

# *** Inrerrupt Pins ***

intPinNum0 = 12 #4 
intPinNum1 = 13 #5 
intPinNum2 = 14 #6 
intPinNum3 = 15 #7 

# *** Motor Driver Control Pins (TB6612FNG) ***

stdByPinNum0 = 16 #8
stdByPinNum1 = 17 #9

aIn1PinNum0  = 18 #10
aIn2PinNum0  = 19 #11
bIn1PinNum0  = 20 #12
bIn2PinNum0  = 21 #13

aIn1PinNum1  = 27 #14
aIn2PinNum1  = 28 #15
bIn1PinNum1  = 22 #16
bIn2PinNum1  = 26 #17

# *** Interrupt Pin Dicts ***

intGpPinNumDict = {'0': intPinNum0, 
                   '1': intPinNum1, 
                   '2': intPinNum2, 
                   '3': intPinNum3, 
                  }

intPinNumList = [intPinNum0, intPinNum1, intPinNum2, intPinNum3]

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

# *** Sleep time dicts ***

secondsDict = {'OneSecond'    :   1,
               'TwoSeconds'   :   2,
               'FourSeconds'  :   4,
               'TenSeconds'   :  10,               
               'SixtySeconds' :  60,
               'ThreeMinutes' : 180,
              }

def hold(secondsName):
    utime.sleep(secondsDict[secondsName])
    return

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

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

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

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

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

defaultDirection = 'Forward'
defaultSpeed     = 'VertHighSpeed'
defaultPwmFreq   = 1000
defaultDutyCycle = 90

frontLeftWheel  = 0
frontRightWheel = 1
rearLeftWheel   = 2
rearRightWheel  = 3

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

motorConfigDictDict = \
    {
        '0': {'MotorDriverNum': 0, 'ChannelNum': 0, 'position': 'Left'},
        '1': {'MotorDriverNum': 0, 'ChannelNum': 1, 'position': 'Right'},
        '2': {'MotorDriverNum': 1, 'ChannelNum': 0, 'position': 'Left'},
        '3': {'MotorDriverNum': 1, 'ChannelNum': 1, 'position': 'Right'},        
    }

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

def setupMotor(motorNum):
    motorConfigDict = motorConfigDictDict[str(motorNum)]
    motorDriverNum  = motorConfigDict['MotorDriverNum']
    channelNum      = motorConfigDict['ChannelNum']
    
    stdByPinNum     = motorDriverGpPinNumDict[str(motorDriverNum)]['StdByPinNum']
    in1PinNum       = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['In1PinNum']
    in2PinNum       = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['In2PinNum']
    
    pwmPinNum       = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmPinNum']
    pwmFreq         = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['PwmFreq']    
    dutyCycle       = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['DutyCycle']     
    
    intPinNum       = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['IntPinNum']
    intPinCallBack  = motorDriverGpPinNumDict[str(motorDriverNum)][str(channelNum)]['IntPinCallBack']

    # *** Motor Driver Control Pin Setup ***    
    
    stdByPin    = Pin(stdByPinNum, Pin.OUT)
    in1Pin      = Pin(in1PinNum, Pin.OUT)    
    in2Pin      = Pin(in2PinNum, Pin.OUT)
    intPin      = Pin(intPinNum, Pin.IN, Pin.PULL_DOWN)
  
    stdByPin.high()
    in1Pin.low()
    in2Pin.low()

    # *** PWM Pin Setup ***      
    
    pwmPin      = PWM(Pin(pwmPinNum))
    pwmPin.freq(pwmFreq)
    u16DutyCycle = int((dutyCycle / 100) * 65536)  
    pwmPin.duty_u16(u16DutyCycle)
    
    # *** Interrupt Pin Setup ***
    
    intPin.irq(intPinCallBack, Pin.IRQ_FALLING)
    
    # *** Motor Control Dict ***
    
    motorControlDict = {'StdByPin' : stdByPin,
                        'In1Pin'   : in1Pin,
                        'In2Pin'   : in2Pin,
                        'PwmPin'   : pwmPin,
                        'IntPin'   : intPin,
                        'MotorNum' : motorNum,
                       }
    
    motorStatusDict = {'Direction'   : defaultDirection,
                       'Speed'       : defaultSpeed,
                       'PwmFrequency': defaultPwmFreq,
                       'DutyCycle'   : defaultDutyCycle,
                      }                       

    motorDict = {'MotorConfictDict' : motorConfigDict,
                 'MotorControlDict' : motorControlDict,
                 'MotorStatusDict'  : motorStatusDict
                }    

    return motorDict

def setupMotorList(motorNumList):
    motorControlDictList = [0] * len(motorNumList)        
    for motorNum in motorNumList:
        motorControlDict = setupMotor(motorNum)
        motorControlDictList[motorNum] = motorControlDict
    return motorControlDictList

def setupMotorDirection(motorControlDict, directionName):
    if directionName =='Forward':
        if (motorControlDict['MotorNum'] % 2) == 0:
           motorControlDict['In1Pin'].low()
           motorControlDict['In2Pin'].high()
        else:
           motorControlDict['In1Pin'].high()
           motorControlDict['In2Pin'].low()      
        
    elif directionName =='Backward':
        if (motorControlDict['MotorNum'] % 2) == 0:
           motorControlDict['In1Pin'].high()
           motorControlDict['In2Pin'].low()
        else:
           motorControlDict['In1Pin'].low()
           motorControlDict['In2Pin'].high()                 
    return
    
def setupMotorSpeed(motorControlDict, speedName):
    pwmPin = motorControlDict['PwmPin']
    dutyCycle = dutyCycleDict[speedName]
    pwmPin.duty_u16(int((dutyCycle / 100) * 65536) )
    return

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

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

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

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

def stopMotorList(motorControlDictList):
    for motorControlDict in motorControlDictList:
        stopMotor(motorControlDict)
    return

# *** Test setup/stop/move motor functions ***

def testSetupMotor(motorNum):
    print('Begin testSetupMotor(), ', 'motorNum =', motorNum)
    motorControlDict = setupMotor(motorNum)['MotorControlDict']
    stopMotor(motorControlDict)
    print('End   testSetupMotor().')
    return

def testSetupMotorList(motorNumList):
    for motorNum in motorNumList:
        testSetupMotor(motorNum)
    return

def testSetupMoveMotor(motorNum, directionName, speedName, holdSecondsName):
    print('Begiun testSetupMoveMotor(), ', 'motorNum =', motorNum)
    motorDict = setupMotor(motorNum)
    motorControlDict = motorDict['MotorControlDict']
    stopMotor(motorControlDict)
    setupMotorDirection(motorControlDict, directionName)
    setupMotorSpeed(motorControlDict, speedName)    
    hold(holdSecondsName)
    stopMotor(motorControlDict)
    print('End   testSetupMoveMotor().')    
    return

def testSetupMoveMotorListSequential(motorNumList, directionName, speedName, holdSecondsName):
    print('Begiun testSetupMoveMotorNumListSequential(), ...')
    for motorNum in motorNumList:
        motorDict = setupMotor(motorNum)
        motorControlDict = motorDict['MotorControlDict']
        stopMotor(motorControlDict)
        setupMotorDirection(motorControlDict, directionName)
        setupMotorSpeed(motorControlDict, speedName)    
        hold(holdSecondsName)
        stopMotor(motorControlDict)
    print('End   testSetupMoveMotorNumListSequential().')    
    return

def testSetupMoveMotorListConcurrent(motorNumList, directionName, speedName, holdSecondsName):
    print('Begin testSetupMoveMotorNumListConcurrent(), ...')
    for motorNum in motorNumList:
        motorDict = setupMotor(motorNum)
        motorControlDict = motorDict['MotorControlDict']
        stopMotor(motorControlDict)
        setupMotorDirection(motorControlDict, directionName)
        setupMotorSpeed(motorControlDict, speedName)       
    hold(holdSecondsName)
    for motorNum in motorNumList:
        motorDict = setupMotor(motorNum)
        motorControlDict = motorDict['MotorControlDict']
        stopMotor(motorControlDict)      
    print('End   testSetupMoveMotorNumListConcurrent().')    
    return

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

# *** Main ***

#testSetupMotor(motorNum = 0)
#testSetupMotorList(motorNumList = [0, 1, 2, 3])

#testSetupMoveMotor(motorNum = 0, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')
#testSetupMoveMotor(motorNum = 1, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')
#testSetupMoveMotor(motorNum = 2, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')
#testSetupMoveMotor(motorNum = 3, directionName = 'Forward', speedName = 'VeryFast', holdSecondsName = 'TwoSeconds')

# *** Testing TB6612FNG Driving 4 Wheels ***
testSetupMoveMotorListSequential([frontLeftWheel, frontRightWheel, rearLeftWheel, rearRightWheel], 'Forward', 'VeryFast', 'TwoSeconds')
testSetupMoveMotorListConcurrent([frontLeftWheel, frontRightWheel, rearLeftWheel, rearRightWheel], 'Backward', 'VerySlow', 'FourSeconds')

# *** Testing HC12 Config and Transive/Receive ***
#testHc12Config(hc12Num = 0, writeBytes = 'AT')
#testHc12Config(hc12Num = 1, writeBytes = 'AT')
testHc12Communication(xmitUartPortNum = 0, recvUartPortNum = 1, testXmitMsg = 'xyz msg')

# *** End ***

''' Sample output  tlfong01  2021nov20hkt1531
>>> %Run -c $EDITOR_CONTENT
Begiun testSetupMoveMotorNumListSequential(), ...
End   testSetupMoveMotorNumListSequential().
Begin testSetupMoveMotorNumListConcurrent(), ...
End   testSetupMoveMotorNumListConcurrent().
Begin testHc12Communication(), ...
  Begin set both HC12s communication mode, ...
  End   set both HC12s communication mode.
  Begin transmit message, ...
    xmitBytes = xyz msg
  End transmit message.
  Begin receive message, ...
    uartAny   = 7
    recvBytes = b'xyz msg'
  End   receive msaages.
End   testHc12Communication(), ...
>>> 
'''

Now I am watching how the ESP32 hobbyists are making Robots

The 10 Best ESP32 Robotics Projects - Cherie Tan, Muo 2021nov21

Learn Python Programming on Raspberry Pi With These Commands and Data Structures - Cherie Tan, Muo 2021sep19


Integrating modules uart, hc12, interrupt, tb6612fng

Now I have integrated the above 4 python modules and tested all functions more or less OK.The penzu journal below has the full program listing and sample output.

pico_4wd_v115 program listing

/ to continue, …

Master and slave pico 4WD 433MHz Transceiving Mirror Moving Experiment v0.1

Now that I have tested all the Smart Pico 4WD OK, I am going to do the following experiment:

  1. Using two pico 4WD, one as master, another as slave.

  2. Master 4WD moves any pattern, and sends the motor/wheel move commands, as a text string, such as “FrontLeftWheelMoveForwardFullSpeed”, through a HC12 UART RF 433MHz channel to the slave 4WD.

  3. The slave 4WD, when receiving the move wheel command, move the wheeling according, and send back the Wheel/Motor speed (from motor rotary encoder signals) back to the master 4WD.

  4. So, as an example, if the master 4WD moves in a straight line, then a square, then a circle, the the slave 4WD moves the same pattern, at the same speed.

  5. The slave 4WD, if it wants, can record/remember the move commands as a command text file, and later moves the same pattern, as many times as possible, and at same or different speed as the master 4WD.


pico_4wd_v122.py

pico_4wd_v125.py


Open-source, 3D printed, low cost vehicle, controlled over the internet programmed in Python



Open-source, 3D printed, low cost transport and reconnaissance vehicle controlled over the internet, programmed in Python

https://www.open-ats.eu/

Element14 Rpi Pico Info

https://community.element14.com/products/raspberry-pi/w/documents/5191/raspberry-pi-pico


Kitronix Pico Buggy


Kitronik Autonomous Robotics Platform for Pico [New] - £34

Kitronik Autonomous Robotics Platform for Pico`

This morning I read that Kitronix is now an official Rpi reseller and they are selling an autonomous Pico robot car. I hope pi-top will catch up soon.

The Kitronik Autonomous Robotics Platform Pico, a fun and hands-on introduction to Robotics with the Raspberry Pi Pico.

*The Kitronik Autonomous Robotics Platform for Raspberry Pi Pico is a fun and hands-on introduction to buggy robotics. *

*The easy to follow booklet provided with the kit guides you through all of the steps required for you to take control of your robot. *

The Robotics Platform has been designed to grow with you and provided additional servo and ultrasonic sensor connectors for more advanced projects. This buggy requires a Raspberry Pi Pico with pin headers attached, yo…


pi-top [4] Complete Raspberry Pi 4 Computer Kit - $250

pi-top [4] Complete Raspberry Pi 4 Computer Kit - $250

Overview

You and your children can design, code and make anything you imagine with the pi-top [4] Complete Raspberry Pi 4 computer kit.

It includes everything you need to program a Raspberry Pi inside of its rugged case.

Whatever you wish to build an alarm or a sensor, or learning about problem solving and code writing, this computer kit is a must-have.


Pico 4WD v128 Program Listing

#setupMoveCarHold('FrontLeftWheel',  'Forward', 'Normal', '2 seconds')
#setupMoveCarHold('FrontRightWheel', 'Forward', 'Normal', '2 seconds')

#setupMoveCarHold('RearLeftWheel',   'Forward', 'Normal', '2 seconds')
#setupMoveCarHold('RearRightWheel',  'Forward', 'Normal', '2 seconds')

#setupMoveCarHold('FrontWheels',     'Forward', 'Normal', '2 seconds')
#setupMoveCarHold('RearWheels',      'Forward', 'Normal', '2 seconds')
#setupMoveCarHold('AllFourWheels',   'Forward', 'Normal', '2 seconds')

setupTurnCarHold('FrontWheels',      'Forward',    'Normal', '2 seconds')
setupTurnCarHold('RearWheels',       'Backward',   'Normal', '2 seconds')

Pico 4WD v128 Program Listing


Pico 4WD Moving in a straight line, in a sqaure, in a circle functions tested OK

Now the following functions are tested OK.

setupMoveCarHold('FrontLeftWheel',  'Forward', 'Normal', '2 seconds')
setupMoveCarHold('FrontRightWheel', 'Forward', 'Normal', '2 seconds')

setupMoveCarHold('RearLeftWheel',   'Forward', 'Normal', '2 seconds')
setupMoveCarHold('RearRightWheel',  'Forward', 'Normal', '2 seconds')

setupMoveCarHold('FrontWheels',     'Forward', 'Normal', '2 seconds')
setupMoveCarHold('RearWheels',      'Forward', 'Normal', '2 seconds')
setupMoveCarHold('AllFourWheels',   'Forward', 'Normal', '2 seconds')

setupTurnCarHold('FrontWheels',      'TurnLeft',   'Normal', '2 seconds')
setupTurnCarHold('FrontWheels',      'TurnRight',  'Normal', '2 seconds')
setupTurnCarHold('RearWheels',       'TurnLeft',   'Normal', '2 seconds')
setupTurnCarHold('RearWheels',       'TurnRight',  'Normal', '2 seconds')

So I have proven the concept that it is easy to move the 4WD in any pattern I wish: straight line, square, circle, hexagon etc.

And of course it should be also easy to communicate between a group of pico 4WDs each with HC12 433MHz tranceivers to talk to each other and perform orchestraed group movements with or without a Rpi4B master/conductor

pico_4wd_v130.py


Yet another self driving car

This remote-controlled car drives itself


4WD Moving in a square functions tested OK

4WD Moving in a square program listing

def carMoveSquareV01():
    print('Begin carMoveSquareV01(), ...')
    setupMoveCarHold('AllFourWheels', 'Forward',  'Normal', '2 seconds')
    setupTurnCarHold('FrontWheels',   'TurnLeft', 'VerySlow',   '1 second')    
    setupMoveCarHold('AllFourWheels', 'Forward',  'Normal', '2 seconds')
    setupTurnCarHold('FrontWheels',   'TurnLeft', 'VerySlow',   '1 second')
    setupMoveCarHold('AllFourWheels', 'Forward',  'Normal', '2 seconds')
    print('End   carMoveSquareV01().')
    return

Pico GP pins running out problem

I am running out of GP pins for the 4WD project. One workaround is to use IO expenderes such as MCP2307/MCP23s17, or PCF8574. I am thinking of trying out PCF8574 first.

PCF8574 Remote 8-Bit I/O Expander for I2C Bus - TI



PCF8574 IO pins for TB6612FNG signals

tb6612fng_pinout_2021nov2801


Now I am reading an old Pico micropython program using PCF8574 to control a DC motor controller MX15 I need to modify this program for TB6612FNG.


 *** iox_pcf8571_v34 tlfong01 2021mar01hkt1616
# Thonny 3.3.3 MicroPython (Raspberry Pi Pico)
# Chinese Windows 10
# References - https://github.com/raspberrypi/pico-micropython-examples

#import machine
from machine import Pin, Timer
import time

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

# Contents
#   Part A - I2C Bus Config/Setup/Test
#   Part B - PCF8571 8-Bit I/O Extender Config/Setup/Test
#   

# *** I2C ***

# *** I2C Bus Dictionary

i2cBusDict = {
    '0' : { 'BusNum'     : 0,
            'NickName'   : 'Amy',
            'SdaPinNum'  : 0,
            'SclPinNum'  : 1,
            'Frequency'  : '100 kHz',
          },
    '1' : { 'BusNum'     : 1,
            'NickName'   : 'Betty',
            'SdaPinNum'  : 2,
            'SclPinNum'  : 3,
            'Frequency'  : '400 kHz',
          },          
    }                  

frequencyDict = {
    '100 kHz' :  100000,
    '400 kHz' :  400000,
    '1 MHz'   : 1000000,
    }

# *** Print/Debug Functions ***

def printIntListInHex(intList):
    for integer in intList:
        print(hex(integer), ' ', end = '')
    #print('')        
    return

def padString(string, paddedStringLength):
    leftOver = paddedStringLength - len(string)
    string = string + (' ' * leftOver)
    return string    

# *** I2C Functions ***

def setupI2cBus(i2cBusNum):
    sdaPinNum = i2cBusDict[str(i2cBusNum)]['SdaPinNum'] 
    sclPinNum = i2cBusDict[str(i2cBusNum)]['SclPinNum']
    sdaPin    = machine.Pin(sdaPinNum)    
    sclPin    = machine.Pin(sclPinNum)
    frequency = frequencyDict[i2cBusDict[str(i2cBusNum)]['Frequency']]     
    i2cBus = machine.I2C(i2cBusNum, sda = sdaPin, scl = sclPin, freq = frequency)
    return i2cBus

def setupI2cBusList(i2cBusNumList):
    i2cBusList = []
    for i2cBusNum in i2cBusNumList:        
       i2cBus = setupI2cBus(i2cBusNum)
       i2cBusList.append(i2cBus)   
    return i2cBusList

# *** Test Functions ***

def testSetupI2cBusList():
    print('Begin testSetupI2cBusList(), ...')
    i2cBustList = setupI2cBusList([0, 1])
    print('End   testSetupI2cBusList().\n')
    return i2cBustList

def testSetupScanI2cBusList():
    print('Begin testSetupScanI2cBusList(), ...')    
    i2cBusList = setupI2cBusList([0, 1])    
    for i2cBus in i2cBusList:
        index = i2cBusList.index(i2cBus)
        print('  I2C Bus Num =', index, ' ', end = '')
        ljustNickName = padString(i2cBusDict[str(i2cBusList.index(i2cBus))]['NickName'], 8)
        print('NickName =', ljustNickName, end ='')       
        print('Frequency =', i2cBusDict[str(i2cBusList.index(i2cBus))]['Frequency'], ' ', end ='')
        print('sdaPin =', i2cBusDict[str(i2cBusList.index(i2cBus))]['SdaPinNum'], ' ', end ='')
        print('sclPin =', i2cBusDict[str(i2cBusList.index(i2cBus))]['SclPinNum'], ' ', end ='')         
        printI2cDeviceList(i2cBus)
    print('End   testSetupI2cBusList().\n')        
    return 

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

# *** PCF8574 8-bit IO Extender ***

# *** IoX Config ***

i2cDevDict = {
    '0' : { 'I2cDevNum'     : 0,
            'I2cBusNum'     : 0,
            'I2cDevAddr'    : 0x23,
            'DevName'       : 'PCF8574 #1',
            'DevNickName'   : 'Connie'
          },
    '1' : { 'I2cDevNum'     : 1,
            'I2cBusNum'     : 1,
            'I2cDevAddr'    : 0x24,
            'DevName'       : 'PCF8574 #2',
            'DevNickName'   : 'Daisy'
          },
    '2' : { 'I2cDevNum'     : 2,
            'I2cBusNum'     : 0,
            'I2cDevAddr'    : 0x27,
            'DevName'       : 'LCD2004 #1',
            'DevNickName'   : 'Emily'
          },
    '3' : { 'I2cDevNum'     : 3,
            'I2cBusNum'     : 1,
            'I2cDevAddr'    : 0x22,
            'DevName'       : 'LCD1602 #1',
            'DevNickName'   : 'Fanny'
          },     
    }

def printI2cDevDict():
    dictLength = len(i2cDevDict)
    i2cDevNumList = [i2cDevNum for i2cDevNum in range(dictLength)]
    
    for i2cDevNum in i2cDevNumList:
        print('      i2cDevNum =', i2cDevNum, ' ', end = '')
        
        ljustDeviceName = padString(i2cDevDict[str(i2cDevNum)]['DevName'], 8)
        print(' DeviceName =', ljustDeviceName, end ='')        
        
        ljustNickName = padString(i2cDevDict[str(i2cDevNum)]['DevNickName'], 8)
        print('  NickName =', ljustNickName, end ='')
        
        print('  I2cBusNum =', i2cDevDict[str(i2cDevNum)]['I2cBusNum'],end ='')
        print('  I2cDevAddr =', hex(i2cDevDict[str(i2cDevNum)]['I2cDevAddr']),end ='')         
        
        print('')
    print('')        
    return

def printI2cDevInfo(i2cDevNum):
    print('      i2cDevNum =', i2cDevNum, ' ', end = '')
        
    ljustDeviceName = padString(i2cDevDict[str(i2cDevNum)]['DevName'], 8)
    print(' DeviceName =', ljustDeviceName, end ='')        
        
    ljustNickName = padString(i2cDevDict[str(i2cDevNum)]['DevNickName'], 8)
    print('  NickName =', ljustNickName, end ='')
        
    print('  I2cBusNum =', i2cDevDict[str(i2cDevNum)]['I2cBusNum'],end ='')
    print('  I2cDevAddr =', hex(i2cDevDict[str(i2cDevNum)]['I2cDevAddr']),end ='')         
        
    print('')
    return

# *** IoX Functions ***

def scanAndPrintI2cBusList(i2cBusList):
    for i2cBus in i2cBusList:
        index = i2cBusList.index(i2cBus)        
        print('      I2C Bus Num =', index, ' ', end = '')
        i2cDeviceList = i2cBus.scan()
        print('I2cDeviceList = ', end = '')
        printIntListInHex(i2cDeviceList)
        print('')
    return

# *** Iox Test Functions ***

def testIoxDevices():
    printIoxDevices()
    return

def printI2cBusListConfig(i2cBusList):
    #print('\n        I2C Bus List Config, ... ')
    for i2cBus in i2cBusList:
        index = i2cBusList.index(i2cBus)        
        print('      I2C Bus Num =', index, ' ', end = '')
        ljustNickName = padString(i2cBusDict[str(i2cBusList.index(i2cBus))]['NickName'], 8)
        print('Bus nick name =', ljustNickName, end ='')       
        print('Frequency =', i2cBusDict[str(i2cBusList.index(i2cBus))]['Frequency'], ' ', end ='')
        print('sdaPin =', i2cBusDict[str(i2cBusList.index(i2cBus))]['SdaPinNum'], ' ', end ='')
        print('sclPin =', i2cBusDict[str(i2cBusList.index(i2cBus))]['SclPinNum'], ' ', end ='')
        print('')
    return

def printIoxDevicesOnI2cBusList(i2cBusList): 
    for i2cBus in i2cBusList:
        index = i2cBusList.index(i2cBus)        
        print('      I2C Bus Num =', index, ' ', end = '')        
        printI2cDeviceList(i2cBus)
    return

# *** Basic Tests ***

def pcf8574BasicTest01():
    print('>>>>>>>>>> Begin testPcf8574(), ... >>>>>>>>>>\n')  

    print('  *** Set up I2C bus list [i2cBus0, i2cBus1] ***\n')
    i2cBusList = setupI2cBusList([0, 1])
    
    print('  *** I2C Bus List Config ***')     
    printI2cBusListConfig(i2cBusList)
    print('')     
    
    print('  *** I2c Device Dict ***')    
    printI2cDevDict()
    
    print('  *** Scan and print I2C devices I2C bus list [i2cBus0, i2cBus1] ***')
    scanAndPrintI2cBusList(i2cBusList)

    print('\n>>>>>>>>>> End   testPcf8574(). >>>>>>>>>>\n')    
    return

# *** Write/Read I2C Device ***

# *** Write Functions ***

def writeI2cBusDevAddrOneByte(i2cBus, i2cDevAddr, writeByte):
    i2cBus.writeto(i2cDevAddr, bytes([writeByte]))
    return

def writeI2cDevNumOneByte(i2cBusList, i2cDevNum, writeByte):
    i2cBusNum  = i2cDevDict[str(i2cDevNum)]['I2cBusNum']
    i2cBus     = i2cBusList[i2cBusNum]
    i2cDevAddr = i2cDevDict[str(i2cDevNum)]['I2cDevAddr']
    writeI2cBusDevAddrOneByte(i2cBus, i2cDevAddr, writeByte)
    return

def blinkI2cDevNumByte1Byte2(i2cBusList, i2cDevNum, byte1, byte2, byteTime1, \
                             byteTime2, totalCount):
    i2cBusNum  = i2cDevDict[str(i2cDevNum)]['I2cBusNum']
    i2cBus     = i2cBusList[i2cBusNum]
    i2cDevAddr = i2cDevDict[str(i2cDevNum)]['I2cDevAddr']
    
    for count in range(totalCount):
        writeI2cBusDevAddrOneByte(i2cBus, i2cDevAddr, byte1)
        time.sleep(byteTime1)
        writeI2cBusDevAddrOneByte(i2cBus, i2cDevAddr, byte2)
        time.sleep(byteTime2)
    writeI2cBusDevAddrOneByte(i2cBus, i2cDevAddr, 0x00)
    #writeI2cBusDevAddrOneByte(i2cBus, i2cDevAddr, 0xff)      
    return

def scanI2cDevNumOneByte(i2cBusList, i2cDevNum, scanByte, scanTime, totalCount):
    i2cBusNum  = i2cDevDict[str(i2cDevNum)]['I2cBusNum']
    i2cBus     = i2cBusList[i2cBusNum]
    i2cDevAddr = i2cDevDict[str(i2cDevNum)]['I2cDevAddr']
    
    maskByte = 0x01
    for byteCount in range(totalCount):
        for bitCount in range(8):
            newMaskByte = maskByte << bitCount
            newByte = scanByte & newMaskByte
            writeI2cBusDevAddrOneByte(i2cBus, i2cDevAddr, newByte)
            time.sleep(scanTime)
    writeI2cBusDevAddrOneByte(i2cBus, i2cDevAddr, 0x00)    
    return

# *** Read Functions ***

''' tested not OK 

def readI2cBusDevAddrOneByte(i2cBus, i2cDevAddr):
    readByte = i2cBus.readfrom(i2cDevAddr, 4) 
    return readByte

def readPrintI2cBusDevAddrOneByte(i2cBus, i2cDevAddr):
    readByte = readI2cBusDevAddrOneByte(i2cBus, i2cDevAddr)
    print('Read byte =', readByte)
    return

def readI2cDevNumOneByte(i2cBusList, i2cDevNum):
    i2cBusNum  = i2cDevDict[str(i2cDevNum)]['I2cBusNum']
    i2cBus     = i2cBusList[i2cBusNum]
    i2cDevAddr = i2cDevDict[str(i2cDevNum)]['I2cDevAddr']
    readPrintI2cBusDevAddrOneByte(i2cBus, i2cDevAddr)
    return
'''

# *** Write/Read Tests ***

def pcf8574WriteBlinkTest01():
    print('>>>>>>>>>> Begin   pcf8574WriteTest01(), ... >>>>>>>>>>\n')     
    
    print('  *** Set up I2C bus list [i2cBus0, i2cBus1] ***\n')
    i2cBusList = setupI2cBusList([0, 1])    
    
    print('  *** Scan and print I2C devices I2C bus list [i2cBus0, i2cBus1] ***')
    scanAndPrintI2cBusList(i2cBusList)
        
    #print('\n *** Read pcf8574 input pins - to test later ***')
    #i2cDevNum = 0    
    #readI2cDevNumOneByte(i2cBusList, i2cDevNum)
        #i2cBus = i2cBusList[0]
    #i2cDevAddr = 0x23
    #readByteArray = []
    #readByteArray = i2cBus.readfrom(i2cDevAddr, 1)
    #i2cBus.writeto_mem(76, 6, b'456')
    #i2cBus.readfrom_mem(76, 6, 4)

    print('\n  *** Toggle/Blink pcf8574 output pins/LEDs ***') 
   
    #print('dp 01')  
    i2cBusList[0].writeto(0x27, bytes([0x55]))
    i2cBusList[0].writeto(0x23, bytes([0x55]))
    i2cBusList[1].writeto(0x22, bytes([0x55]))      
    i2cBusList[1].writeto(0x24, bytes([0x55]))
    
    #print('dp 02')
    writeI2cBusDevAddrOneByte(i2cBusList[0], 0x23, 0xff)    
    writeI2cBusDevAddrOneByte(i2cBusList[1], 0x24, 0xff)
    time.sleep(1)
    writeI2cBusDevAddrOneByte(i2cBusList[0], 0x23, 0x00)    
    writeI2cBusDevAddrOneByte(i2cBusList[1], 0x24, 0x00)
    
    #print('dp03') 
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum = 0, writeByte = 0x55)
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum = 1, writeByte = 0xaa)
    
    #print('dp04 blink')
    byte1 = 0x55
    byte2 = 0xaa
    byte1Time = 0.5
    byte2Time = 0.5
    totalCount = 2
    
    i2cDevNum = 0    
    blinkI2cDevNumByte1Byte2(i2cBusList, i2cDevNum, byte1, byte2, byte1Time, \
                             byte2Time, totalCount)
    i2cDevNum = 1 
    blinkI2cDevNumByte1Byte2(i2cBusList, i2cDevNum, byte1, byte2, byte1Time, \
                             byte2Time, totalCount)

    print('\n>>>>>>>>>> End   pcf8574WriteTest01().>>>>>>>>>>') 
    return

def pcf8574WriteBitTest01():
    print('\n>>>>>>>>>> Begin pcf8574WriteBitTest01(). >>>>>>>>>>')
    
    print('  *** Set up I2C bus list [i2cBus0, i2cBus1] ***\n')
    i2cBusList = setupI2cBusList([0, 1])    
    
    print('  *** I2c Device Dict ***')    
    printI2cDevDict()
    
    print('  *** Scan and print I2C devices I2C bus list [i2cBus0, i2cBus1] ***')
    scanAndPrintI2cBusList(i2cBusList)
    
    print('\n  *** Wrtie to i2cDevNum0, i2cDevNum1 ***')
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum = 0, writeByte = 0x55)
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum = 1, writeByte = 0xaa)
    time.sleep(0.5)
    
    print('\n  *** scan bit i2cDevNum0 ***')
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum = 0, writeByte = 0x00)
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum = 1, writeByte = 0x00)
    time.sleep(0.5)

    i2cDevNum = 0   
    #oldByte = 0x00
    newByte = 0x01
    maskByte = 0x00
    
    for i in range(8):
        #maskByte = newByte
        #newByte = newByte << 1
        writeI2cDevNumOneByteOrMaskByte(i2cBusList, i2cDevNum, newByte, maskByte)
        
        #newByte = newByte | oldByte
        #writeByte = newByte
        #writeI2cDevNumOneByte(i2cBusList, i2cDevNum, writeByte)
        time.sleep(0.5)
        maskByte = newByte | maskByte
        newByte = newByte << 1        
        
    print('\n>>>>>>>>>> End   pcf8574WriteBitTest01(). >>>>>>>>>>') 
    return

def writeI2cDevNumOneByteOrMaskByte(i2cBusList, i2cDevNum, writeByte, maskByte):
    writeByte = writeByte | maskByte
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum, writeByte)
    return

def writeI2cDevNumOneByte(i2cBusList, i2cDevNum, writeByte):
    i2cBusNum  = i2cDevDict[str(i2cDevNum)]['I2cBusNum']
    i2cBus     = i2cBusList[i2cBusNum]
    i2cDevAddr = i2cDevDict[str(i2cDevNum)]['I2cDevAddr']
    writeI2cBusDevAddrOneByte(i2cBus, i2cDevAddr, writeByte)
    return

def writeI2cDevNumOneByteOrMaskByte(i2cBusList, i2cDevNum, writeByte, maskByte):
    writeByte = writeByte | maskByte
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum, writeByte)
    return

#def setBitHigh(i2cBusList, i2cDevNum, writeByte, bitPosition):

# *** Motor Driver MX1908 Functions ***

i2cMotorDict = {
    '0' : {'I2cDevNum'    : 0,
           'MotorName'    : 'Gigi',
           'Action'       : {'MoveForward'  : 0b01,
                             'MoveBackward' : 0b10,
                             'Stop'         : 0b00,
                            }
          },
    '1' : {'I2cDevNum'    : 1,
           'MotorName'    : 'Helen',
           'Action'       : {'MoveForward'  : 0b01,
                             'MoveBackward' : 0b10,
                             'Stop'         : 0b00,
                            }           
          },
    }

i2cDevNameDict = {
    'Gigi'  : {'I2cDevNum'  : 0,
               'DeviceName' : 'Motor'},
    'Helen' : {'I2cDevNum'  : 1,
               'DeviceName' : 'Motor'},   
    }

def writeI2cMotorOneByte(i2cBusList, motorName, actionName):
    i2cDevNum = i2cDevNameDict[motorName]['I2cDevNum']
    writeByte = i2cMotorDict[str(i2cDevNum)]['Action'][actionName]
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum, writeByte)
    print('dp1', 'i2cDevNum =', i2cDevNum, 'actionName =', actionName, 'writeByte =', hex(writeByte))
    return

def pcf8574MotorTest01():
    print('\n>>>>>>>>>> Begin pcf8574MotorTest01(). >>>>>>>>>>')
    
    print('  *** Set up I2C bus list [i2cBus0, i2cBus1] ***\n')
    i2cBusList = setupI2cBusList([0, 1])    
    
    print('  *** I2c Device Dict ***')    
    printI2cDevDict()
    
    print('  *** Scan and print I2C devices I2C bus list [i2cBus0, i2cBus1] ***')
    scanAndPrintI2cBusList(i2cBusList)
    
    print('\n  *** Write Motor Test ***')
    #writeI2cMotorOneByte(i2cBusList, 'Gigi', 'MoveForward')
    
    i2cDevNum = 0
    motorByte = 0b10
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum, motorByte)
    time.sleep(2)
    
    motorByte = 0b01
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum, motorByte)    
    time.sleep(2)
    
    motorByte = 0b00
    writeI2cDevNumOneByte(i2cBusList, i2cDevNum, motorByte)    
    time.sleep(2) 
    
    print('\n>>>>>>>>>> End   pcf8574MotorTest01(). >>>>>>>>>>')    
    return

# *** Main ***

# *** test PCF8457 IOX Devices ***

#pcf8574BasicTest01()
#pcf8574WriteBlinkTest01()
#pcf8574WriteBitTest01()
pcf8574MotorTest01()

# *** End ***

'''
import utime
from machine import Pin

motor1a = Pin(10, Pin.OUT)
motor1b = Pin(11, Pin.OUT)

def forward():
   motor1a.high()
   motor1b.low()

def backward():
   motor1a.low()
   motor1b.high()

def stop():
   motor1a.low()
   motor1b.low()

def test():
    print('  Begin test()')
    forward()
    utime.sleep(1)
    backward()
    utime.sleep(1)
    stop()
    print('  End   test()')

for i in range(1):
    print('Test ', i)
    test()

'''

How do we develop AI education in schools? A panel discussion - Maria Richter, Rpi Foundation monthly AI education seminar series 2021nov30



Pico I2C Evaluation Board v0.1



Drive a Raspberry Pi Car Using Hand Gestures With OpenCV - Ash Hill 2021dec04

This new Raspberry Pi-powered cluster computer is cheaper than a basic desktop - Mayank Sharma 2021dec05

Learn about electronics, coding, IoT and more as you build fun projects for just $20 - ZDNet

You don’t need to know anything except how to use a computer to acquire all kinds of new tech skills as you build the most interesting projects, like GPS tracking, smart home remote dashboards and much more.


Pico UART, SPI, I2C Evaluation Board Pinout v0.1 2021dec05hkt1314




Dual PCF8574 Module Board Testing Notes

PCF8574 Module - 8-bit I/O Expander for I2C Bus - Nettigo

PCF8574A Remote 8-bit I/O expander for I2C-bus with interrupt - NXP



PCF8574 IOX Test Function v01

PCF8574 IOX Test Function v01


PCF8574 Wiring V0.2


Everyday Robot has eyes and arms. I am so jealous, …

Alphabet’s Everyday Robots - IEEE Spectrum 2021nov23

Introducing Everyday Robots - Everyday Robots 2021nov01


PCF8574 Iox Driving TB6612FNG Python Program

pcf8574_test_v53_2021dec0801.py


The Elektor Lab Team is interesting

The Elektor Lab Team


picorobot67.py


Pico MicroPython program Driving 4WD Through PCF8514 Iox and TB6612FNG Motor Driver

picorobot79.py


Pico Wireless Pack - Piromorni £12

Me jealously read the following this morning:

Pico Wireless Pack - Piromorni £12


Then this morning I read the following:

Develop boards remotely, in real time with new hardware-as-a-service - Nitin Dahad 2021dec13


The forum editor is getting very slow. So I am writing a new reply to see the response time will improve.

/ To continue, …

Scaling up 4WD (PCF8574 x 2) to 8WD (PCF8574 x 4)

Now I am writing a new reply, to verify my guess that if a reply gets too long, the editing time gets slower and slow. So far my guess seems proved. Anyway, I am moving on to the 4WD experiements.

I have found that my Pico controlling two remote 8 bit GPIO entender chips PCF8574 seems very smooth, so greed me is thinking of scaling up two to four PCF8574 chips, so I can have 4 x 8 to 32 GPIO pins to control 2WD to up to 6WD or 8WDs.

I am also thinking of checking out if Pico I2C bus can handling as many as 8 PCF8574, or MCP23017 16 bit GPIO extenders, so I can have 16 x 8 = 128 GPIO pins. Also I don’t need to use any Pico GP pins. Also I am using microPython, and my code can be easily ported to ESP32 projects.


Quad PCF8574 Evaluation Board



picoRobotV80.py


i2cBusList = setupI2cBusList([0, 1]) 
scanI2cBusList(i2cBusList) 

# *** Sample Output ***
MicroPython v1.14 on 2021-02-02; Raspberry Pi Pico with RP2040
>>> %Run -c $EDITOR_CONTENT
      I2C Bus Num = 0   I2cDevAddr List = 0x24 0x26 
      I2C Bus Num = 1   I2cDevAddr List = 0x20 0x23 

>>>

ZDnet says 2022 might has an robotics revolution

2022: A major revolution in robotics - A world class roboticist on why everything is about to change - ZDnet


Pico Smart Vehicle 6WD/8WD setup and testing notes

picorobot85.py

So I have completed the basic tests of 8 bit Iox PCF8574 x 4 (blinking byte and blinking bit). Next step is to setup and test 4 TB6612FNG DC motor drivers and continue testing.

I have already done TB6612 testing in Part 1 of the project, together with 4 TM310 DC motors, but this time I will be using N20 motors.


I2C MCP23017 and SPI MCP23S17 16 bit/channel GPIO Extenders

I am also thinking of playing with mcp23017 and mcp23s17.

(1) Using an MCP23017 with a Pi Pico [SOLVED] - rpi.org.forum 2021jun01

(2) Raspberry Pi Pico MCP23017 Library - GitHub 2021feb01

(3) tlfong01’s mcp23017 forum posts - rpi/org/fourm search “mcp23017 tlfong01” = 178 matches


Quad TB6612FNG DC Motor Driver Board


Replacing I2C 8-bit PCF8574 Iox by 16-bit I2C MCP23017 or MCP23S17

Replacing Pico GP by PCF8574 Iox has been smooth. Below is a debugged preliminary test program:

picoRobot87.py

However, I found PCF8574 8-bit Iox newbie friendly, but not that flexible and powerful as 16-bit I2C MCP23017 or SPI MCP23S17 Iox.

So I have decided to replace PCF8574 by MCP23S17.


MCP23S17 References

(1) MCP23017/MCP23S17 16-Bit I/O Expander with SPI/I2C Interface - MicroChip

(2) CJMCU-2317 mcp23s17 bidirectional 16-bit i/o io i2c expansion board serial interface module for arduonio - AliExpress US$3.52

(3) SPI- bus length? - Asked 2015, Viewed 4k times

(4) SPI Bus Termination Issue - Asked 2015, Viewed 2k times

(5) SPI noise after extending wires. Why? - EESE 2021nov

(6) Can the length of a wire impact SPI transmission? - EESE 2020feb24



Pico Projects by Tom’s Hardware

Pico Projects by Tom’s Harware


Pico SPI Pinout


RFID and Multiple ultrasonic sensor projects

I am feeling jealous again, this time on the guys making Pico RFID and multiple ultrasonic distance sensors

(1) Raspberry Pi Pico Powered RFID Lighting - Les Pounder 2021dec19

(2) HCSR04 Ultrasonic Distance Sensor


Wiring up i2c mcp23017 x 2 and spi mcp23s17 x 2 for testing


MCP23x17 Programming Notes


Pico MicroPython SPI MCP23S17 Programming Design Pattern Notes


SPI Tutorials

Raspberry Pi Pico (RP2040) SPI Example (ADXL343) with MicroPython and C/C++ | Digi-Key Electronics

Beginners Guide to SPI on the Raspberry Pi Pico (BMP280 Example) - Learn Embedded Systems

MicroPython Doc 1.17 Class SPI – a Serial Peripheral Interface bus protocol (controller side)

Raspberry Pi Pico (RP2040) SPI Example with MicroPython and C/C++ - Digikey

Introduction to SPI Interface - Piyu Dhaker, Analog Dialogue


Raspberry Pi Pico - SPI 8x8 LED Matrix - Micropython example - 2021mar08


SPI Loopback tested OK

from machine import SPI, Pin
import utime

spiPort0  = machine.SPI(0, 
baudrate  = 100000,
polarity  = 0,
phase     = 0,
bits      = 8,
firstbit  = machine.SPI.MSB,
sck       = machine.Pin(2),
mosi      = machine.Pin(3),
miso      = machine.Pin(4))

cs0 = Pin(5, mode=Pin.OUT, value = 1) 

# *** main ***

for count in range(2):  
 
  #spiBuffer = bytearray(4)
  #spiPort0.write_readinto('test', spiBuffer)

  spiBuffer = bytearray(1)
  #spiPort0.write_readinto('x', spiBuffer)
  spiPort0.write_readinto(b'\x35', spiBuffer)   
    
  print('spiBuffer =', spiBuffer)  
  
  utime.sleep(1)
  
print('End of test')

# *** End ***

# *** Sample output ***
'''
>>> %Run -c $EDITOR_CONTENT
spiBuffer = bytearray(b'5')
spiBuffer = bytearray(b'5')
End of test
'''

# *** End of Sample Output ***

Trilobot, what is it?

A versatile, mid-level robot (with N20 motors and RGB LED underlighting) learning platform for Raspberry Pi - Piromori



Quad MCP23x17 SPI/I2C 160bit Iox Learning Board


Write Read MCP23S17 Registers

Now I have written a little Pico micropython function to do SPI loopback of three bytes. Next step is to write/read MCP23S17 registers.

# mcp23s17v03.py tlfong01  2021dec23hkt1540

from machine import SPI, Pin
import utime

# *** SPI Config ***

# *** spiPort0 ***

spiPort0  = machine.SPI(0, 
baudrate  = 100000,
polarity  = 0,
phase     = 0,
bits      = 8,
firstbit  = machine.SPI.MSB,
sck       = machine.Pin(2),
mosi      = machine.Pin(3),
miso      = machine.Pin(4))

cs00 = Pin(5, mode=Pin.OUT, value = 1)

# *** spiPort1 ***

spiPort1  = machine.SPI(1, 
baudrate  = 100000,
polarity  = 0,
phase     = 0,
bits      = 8,
firstbit  = machine.SPI.MSB,
sck       = machine.Pin(10),
mosi      = machine.Pin(11),
miso      = machine.Pin(12))

cs10 = Pin(13, mode=Pin.OUT, value = 1)

spiPortDict = {
                 '0': spiPort0,
                 '1': spiPort1,
              }                 

# *** Test Functions ***

def testSpi123ByteLoopback(): # setup notes: short MOSI and MISO pins to loop/echo input to output
    print('Begin testSpi123ByteLoopback(),...')

    spiBuffer1 = bytearray(1)                         # 1 byte buffer
    
    writeBytes = b'\x35'
    spiPort0.write_readinto(writeBytes, spiBuffer1)   # 1 byte loopback      
    print('  readBytes =', spiBuffer1)
    print('  readBytes =', hex(spiBuffer1[0]))

    writeBytes = b'\x36'
    spiPort0.write_readinto(writeBytes, spiBuffer1)   # 1 byte loopback      
    print('  readBytes =', spiBuffer1)
    print('  readBytes =', hex(spiBuffer1[0]))    
    
    spiBuffer3 = bytearray(3)                         # 3 byte buffer
    writeBytes = b'\x35\x36\x37'                      # 3 byte loopback
    print('  writeBytes =', writeBytes)
    spiPort0.write_readinto(writeBytes, spiBuffer3)    
    print('  readBytes =', spiBuffer3)
    print('  readBytes =', hex(spiBuffer3[0]), hex(spiBuffer3[1]), hex(spiBuffer3[2]))
    
    print('End   testSpi123ByteLoopback().')
    return

# *** Sample Test ***
# testSpi123ByteLoopback()

def spiWriteRead3Bytes(spiPortNum, write3Bytes):   
    spiPort = spiPortDict[str(spiPortNum)]
    buffer3Bytes = bytearray(3)    
    spiPort.write_readinto(write3Bytes, buffer3Bytes)    
    return buffer3Bytes

def testSpiWriteRead3Bytes():
    print('Begin testSpiWriteRead3Bytes(), ...')
    spiPortNum = 0
    write3Bytes = b'\x35\x36\x37'    
    buffer3Bytes = spiWriteRead3Bytes(spiPortNum, write3Bytes)
    print('  write3Bytes =', write3Bytes)
    print('  read3Bytes  =', buffer3Bytes)
    print('  read3Bytes  =', hex(buffer3Bytes[0]), hex(buffer3Bytes[1]), hex(buffer3Bytes[2]))    
    print('End   testSpiWriteRead3Bytes().') 

# *** Sample Tests ***

# testSpiWriteRead3Bytes()

# *** main ***

testSpi123ByteLoopback()
testSpiWriteRead3Bytes()

# *** End ***

'''
*** Begin Sample output ***
>>> %Run -c $EDITOR_CONTENT
Begin testSpi123ByteLoopback(),...
  readBytes = bytearray(b'5')
  readBytes = 0x35
  readBytes = bytearray(b'6')
  readBytes = 0x36
  writeBytes = b'567'
  readBytes = bytearray(b'567')
  readBytes = 0x35 0x36 0x37
End   testSpi123ByteLoopback().
Begin testSpiWriteRead3Bytes(), ...
  write3Bytes = b'567'
  read3Bytes  = bytearray(b'567')
  read3Bytes  = 0x35 0x36 0x37
End   testSpiWriteRead3Bytes().
>>> 
*** End Sample Output ***
'''

Build an Octapi


TriLoBot


Stepper Motor Control Reading Summary

This morning I read ElektroMagazine’s articles focusing on motor control. I found the stepper motor driver TMC2160 very interesting. I am thinking of experimenting with TMC21xx and TMC22xx and use TMC2209 Stepper Motor Controller to expand my 4WD.

ElektroMagazine 2022 Focus on Motor Control


TMC2160 Motor Driver Board - ElektorMagazine


Stepper Motor YouTube Tutorial

Stepper Motors with Arduino - Controlling Bipolar & Unipolar stepper motors - DroneBot Workshop, 403K subscribers 1,612,862 views, 2018feb10


/ to continue, …

Testing Stepper Motor for 4WD

Now I am thinking of using stepping motors to make a 4WD, so that I can precisely control the speed, position, and distance travelled.


STEM Global Action’s No More Lost Einsteins Campaign - Jahmeer Cade, 2022jan18


Raspberry Pi Pico Hot Wheels drag race track - HackSpace 2022jan20


Raspberry Pi RP2040 Discovered in 3D Printer Control Board - Tom’s Hardware


Raspberry Pi Pico 200Khz Digital Oscilloscope #piday #raspberrypi @Raspberry_Pi


Santagostino’s Predictive Maintenance for HVAC Using Arduino Nano RP2040 Connect 942 viewsJan 21, 2022


Pico StackyPi Hat

Pico Quad TB6612FNG DC Motor Hat


Stepper Motor 4WD

So far I have been experimenting DIY 4WD using DC motor and BLDC motor, with DC motor drivers including TB6612FNG.

No I am thinking of using stepper motor instead. Below is the spec of the stepper motor I think I would be using.

Nema 17 Stepper Motor for CNC, 1pc, 4 Leads, 48mm Length, 78oz-in, 1.8A, 42bygh (17HS8401) - AliExpress US$7.5

NEMA17 42 stepper motor 17HS8401/S 48mm - TaoBAo¥26


Stepping Motor 4WD Bottom Plate Assembly Notes

So I have assembled the acrylic pate with 4 stepping motors. I thought it should be a 30 minutes job, but it took me about three hours.


TMC2160 Stepper Motor Driver x 4 for 4WD


TMC2160 Step Motor Driver 4WD Wiring

The complete wiring took me about 5 hours.


Testing TMC2160 Stepping Motor Controller Module


Using PCF8574 8-bit GPIO Expander to control TMC2160 Stepper Motor Controller


Pico Pin Assignment for PCF8574 IO Pins Expander

i2cPort0 = machine.I2C(0, scl = machine.Pin(17), sda = machine.Pin(16))
i2cPort1 = machine.I2C(0, scl = machine.Pin(19), sda = machine.Pin(18))

# ========= ========= ========= ========= ========= ========= ========= =========
# I2C Config/Test Functions

i2cPort0 = machine.I2C(0, scl = machine.Pin(17), sda = machine.Pin(16))
i2cPort1 = machine.I2C(1, scl = machine.Pin(19), sda = machine.Pin(18))

# Print out any addresses found

def detectI2cDevices(i2cPort):
    i2cDeviceList = i2cPort.scan()
    for device in i2cDeviceList:
        print('  ', hex(device))
    return        

# *** Sample Tests ***
#detectI2cDevices(i2cPort0)
#detectI2cDevices(i2cPort1)

def testI2cV01():
    printProgramNameTimeNow()    
    print('Begin testI2cV01(), ...')
    detectI2cDevices(i2cPort0)
    detectI2cDevices(i2cPort1)    
    print('End   testI2cV01().')    
    return

# *** Sample Tests ***
testI2cV01()

'''
Sample Output
>>> %Run -c $EDITOR_CONTENT
Program Name = tmc2130test36.py   Programmer = tlfong01   Time Now = 2022Jan30hkt15:54

Begin testI2cV01(), ...
   0x24
   0x26
End   testI2cV01().
>>>
'''

***Now I am reading the PCF8574 Datasheet and Turorials ***

(1) PCF8574 Remote 8-Bit I/O Expander for I2C Bus Datasheet - TI 2015mar

(2) Using I2C devices with Raspberry PI Pico and MicroPython - Peppe80 2021may30

(3) Using I2C LCD display (with PCF8574 backpack) With Raspberry PI Pico and MicroPython - Peppe80 2021jun


Detecting the two PCF8574’s on two I2C buses

And I have debugged a program to detect the two PCF8574 chips on the Pico, with a sample output shown below.

'''
Sample Output
>>> %Run -c $EDITOR_CONTENT
Program Name = tmc2130test39.py   Programmer = tlfong01   Time Now = 2022Jan30hkt19:18

Begin testDetectI2cDevicesV01(), ...
  i2cPortNum         = 0
    i2cPortName      = I2cPort0
    Devices detected = 0x24 (PCF8574)
  i2cPortNum         = 1
    i2cPortName      = I2cPort1
    Devices detected = 0x26 (PCF8574)
End   testDetectI2cDevices().
>>>
'''

This is the complete listing with sample output:

tmc2130test39.py


Using two PCF8574 GPIO 8-bit expanders to drive 4 Stepping Motors

Now that I have successfully detected the two PCF8574s on two separate I2C buses, next step is to use the GPIO output pins to drive t stepping motors. I will first write simple testing codes to make sure I can set the output pins high and low (toggling or blinking the LEDs), before letting them drive the motor. The testing hardware consisting two things, Pico and PCF8574 board, as displayed below.


PCF8574 MicroPython I2C Programming Basics

I skimmend the MicroPython docs on I2C and found a list of I2C read/write commands, as summarized below.

MicroPython I2C Documentation

(1) i2c.writeto(42, b’123’) # write 3 bytes to peripheral with 7-bit address 42

(2) i2c.readfrom(42, 4) # read 4 bytes from peripheral with 7-bit address 42

(3) i2c.writeto_mem(42, 2, b’\x10’) # write 1 byte to memory (register) of peripheral 42

(4) i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of peripheral 42

(5) I2C.write(buf)

(6) I2C.readinto(buf, nack=True, /)

PCF8574 is very simple with no registers. So I will try to use the veery first command to set high/low of each of the PCF8574’s 8 output/bits ports. (Later I might need to use read commands to read the stepping motors interrupt/encoder signals.)


Maker Pi Pico Board Review

Maker Pi RP2040 Review: The Best RP2040 Robotics Board Under $10! 2022jan29

This morning I read the US$10 Maker Pi Pico Board (with two motor drivers of DC/Stepper Motors) review, and find it interesting. I need to read it again to see if I can learn something or borrow ideas from them.


PCF8475 and TMC2160 Interface Proposal V0.1 - tlfong01 2022jan30hkt2233

I am trying my luck with this interface proposal v0.1.


Pico 4WD scaling up to 8WD

So the two 8-bit IOx PFC8574s on the I2C bus can control 4WD. Me greedy is adding another 2 PCF8574s to scale up the smart vehicle to 8WD. I just plug and play another dual pcf8574 board, update the data dictionaries, and program with the same control structure can now detect 4 pcf8574s, and summarized below.

'''
Sample Output
>>> %Run -c $EDITOR_CONTENT
Program Name = tmc2130test40.py   Programmer = tlfong01   Time Now = 2022Jan31hkt14:51

Begin testDetectI2cDevicesV01(), ...
  i2cPortNum         = 0
    i2cPortName      = I2cPort0
    ic2PortSclPinNum = 17
    ic2PortSdaPinNum = 16
    ic2PortFrea      = 400000
    Devices detected = 0x20 (PCF8574), 0x24 (PCF8574), 
  i2cPortNum         = 1
    i2cPortName      = I2cPort1
    ic2PortSclPinNum = 19
    ic2PortSdaPinNum = 18
    ic2PortFrea      = 100000
    Devices detected = 0x23 (PCF8574), 0x26 (PCF8574), 
End   testDetectI2cDevices().
>>> 
'''

The complete listing of the 4WD scaling up to 8WD is linked below.

tmc2130test40.py



Pico MicroPython PCF8574 Programming Notes

testing writeByte() - https://penzu.com/p/e1b00c73


This morning I read IEEE Spectrum saying that Multiple Purpose Robotics Vehicle is getting popular. So I need to consider that later.

Multi-Functional Robots - Pablo Molinall, IEEE Spectrum 2022jan24


Blinking Function for troubleshooting pcf8574

Now I have written two blinking led functions to troubleshoot/make sure that the pfc8547 8 GPIO ports x 4 = 32 GPIO pins are working OK.

And this is a complete program listing of the pcfc8574 test program

Next step is to use the two pcf8574s to move 8WD, ie, 8 stepping motors!


Tidying up toggling function for tmc2160 app.


C2I 2021 Young Innovator Winner: Fall-proof innovation - Melissa Bradshaw, The Engineer, 2022feb10


This robotic “otter” tracks fish - Ashley Whittaker, rpi.com, 2022feb11


GPS WayPoint Nagigator - Repeatability & Obstacle Avoidance Demo


how-raspberry-pi-is-a-creating-a-new-generation-of-python-developers

/ to continue, …

Pi-Top SuperSets







Mars 2020 Mission Perseverance Rover


Rpi4B Supply Issues


The 15 Best Educational Linux Apps for Students - Ali Arslan 2022mar09


I am jealous that some guys’s 4WD can track objects:

UWB Tracker - Cybercom Group, 2017jun20, 13,296 views


New data: What makes developers happy at work: Turns out developers and plants need mostly the same things. David Gibson, Senior Data Analyst


A closer look at Acorn, our open source precision farming rover - 5,786 views, May 1, 2021

https://www.i-programmer.info/programming/hardware/15293-the-pico-in-micropython-dc-motors.html

/ to continue, …

Raspberry Pi Pico Detects Accidents and Sends for Help
By Ash Hill published 1 day ago


5 Amazing Warehouse Robots You Must See - 1,101,734 views Feb 23, 2021


Modern Warehouse Technology For A Next level Automation


Pimoroni Announces Servo 2040 Servo Motor Controller - Ian Evenden 2022apr01

Why is there a STEM skills shortage in the UK and what is being done to correct it? - Madeline Bennett 2022apr01


Raspberry Pi and Raspberry Pi Pico Team Up for Robot Lawnmower Project - Ian Evenden 2022apr08


OpenMower - The affordable Open Source DIY Smart GPS Robotic Mower - 2022apr04


Robotic Mower STIHL RMI 422 P - Test / Review: The Garden Gurus - 2021jan18


Best Robotic Lawn Mowers 2022 | Robot Lawn Mower Reviews - 2021sep29


Review: ECOVACS DEEBOT X1 OMNI: all new robot vacuum, mop that cleans + maintains - 2022mar22 11,592 views Erin Lawrence 59.1K subscribers





Raspberry Pi Pico PIO - 8 Little Processors You Can Program - 2022may03


Introducing the Create 3 Educational Robot
The next generation of iRobot’s affordable, trusted, all-in-one mobile robot development platform. For advanced makers learning ROS 2.

iRobot’s Create 3 robotics kit does the Roomba


Now I am thinking of making my Pico smart by teaching it how to do ADC. I will follow what TK Hareendran is doing his Pico ADC experiments.

Raspberry Pi Pico ADC & Quick Experiments - TK Hareendran, Codrey Electronics, 2022may10



[45% off pi-top [3] AKA - the Green Laptop!]((https://6rn12.r.a.d.sendibm1.com/mk/mr/zfffsD-ZeUpCtJlwDft1NHDoNsWxxa7yTKybC1lpApnmeWqC3fb3aOqx8wf57-vLv9nklTtyZwifjzVylV0iOGS5eULtOnvnqZK5-fUI_iBa_D5D2rASqjnUgBwUkNFdg7E3GJSEB0Cq-NNWfHGsCVH6) https://6rn12.r.a.d.sendibm1.com/mk/mr/zfffsD-ZeUpCtJlwDft1NHDoNsWxxa7yTKybC1lpApnmeWqC3fb3aOqx8wf57-vLv9nklTtyZwifjzVylV0iOGS5eULtOnvnqZK5-fUI_iBa_D5D2rASqjnUgBwUkNFdg7E3GJSEB0Cq-NNWfHGsCVH6) ­
­ ­ ­ ­
[From Thursday, May 19 through Sunday, May 22 you can purchase your very own “green laptop” at 45% off MSRP]


(1) Should Raspberry Pi Products be Incorporated Into The Teaching of Computer Science Lessons In Schools? - 2022may24 TeamTechzimo
https://www.techzimo.com/should-raspberry-pi-products-be-incorporated-into-the-teaching-of-computer-science-lessons-in-schools/

(2) Why we translate our free online projects for young people to learn coding

(3) Build your own tiny robot dog with a kit - $299

(4) Raspberry Pi Pico 200Khz Digital Oscilloscope


Discover Pinterest’s 10 best ideas and inspiration for Raspberry pi, Get inspired and try out new things. (tlfong01’s comment: not too impressive!)


Powering your Pico


How to Build Your Own 3D Printed Raspberry Pi Robot - Kevin McAleer 2022jun04


Explora was designed using AutoDesk Fusion 360.

Each piece is a discrete component to enable easier 3D printing. Fusion 360 makes it really easy to export the models into STL files, ready for slicing and then 3D printing.

To slice the robot parts (creating the instructions for a 3D printer to print the part) from Fusion 360 I use Cura, and then upload it to OctoPrint to manage the print jobs.

The 3D printed parts are designed to be quick and easy to print, and the whole thing is easy to assemble using a couple of screws and wire up.


3D printing - Wikipedia

3D Printing Slicer Software Guide - Cura, 2021feb18 320 views

Pimoroni Explorer pHAT


(1) Creality Ender-3 S1 Review - The 3D Print General 86,700 views 2021dec30

(2) Creality Ender 3 S1 Review, Best Ender Ever? - 3D Printing Nerd 97,915 views 2022ma26

(3) Worth The Price? Creality Ender 3 S1 3d Printer Review - Modbot, 2022mar26 39,411 views



Introduction to Raspberry Pi Pico guide - Raspberry Pi Pico
https://projects.raspberrypi.org/en/projects/introduction-to-the-pico/5


Elektor Engineering Insights #6 - Embedded SW and IoT







.END

GitHub - 26 public repositories matching raspberrypi pico

Star









Raspberry Pi Pico W Robot - Burgerbot gets an upgrade

Meet Amazon’s first fully autonomous mobile robot


Rpi Pico W Setup/Test Notes 1 - Connecting to WiFi Network

# pico_w_wifi_connect_2022jul0505.py  tlfong01  2022jul05hkt2131

# *********************************************************************************
# Rpi Pico W WiFi Connection Demo Program v0.1, tlfong01, 2022jul05hkt2126
# Thonny 3.3.13, Windows 10 (64-bit), Python 3.7.9 (32 bit), Tk 8.6.9
# MicroPython v1.19.1-88-g99c258977 on 2022-06-30; Raspberry Pi Pico W with RP2040

# *********************************************************************************

import network
import time

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect('tlfong01', '1234567')
print(wlan.isconnected())

'''
# *** Sample Output tlfong01  2022jul05hkt2132 ***
MicroPython v1.19.1-88-g99c258977 on 2022-06-30; Raspberry Pi Pico W with RP2040

Type "help()" for more information.
>>> %Run -c $EDITOR_CONTENT
True
>>>
# *** End of sample output ***
'''

#.END

How to bring STEM to K-12 Classrooms with Robotics & Coding platforms?

Hongkong University CITE Seminar: 2022jul07 3:00pm - 4:00pm Venue: via Zoom, Andy Lee, IFI (HK), Kelsey Zhang, VEX Robotics, APAC

https://www.cite.hku.hk/news.php?id=620&category=seminar


Rpi Pico W Setup/Test Notes 2.1 - Running a Web Server

(1) Pico W Web Server with MicroPython Control the onboard LED (Learn how to run a MicroPython web server on the Pico W that lets you control the onboard LED over Wi-Fi) - 2022jun30, 511 views

(2) Pico W (micropython wifi web server test) 2022jul02

(3) Pico W Web Server Control Outputs (Demo) - 2022apr09, 348 views

(4) How to run a webserver on Raspberry Pi Pico W - Alasdair Allan 2022jul05

(5) Pico W Connecting to the Internet with Pico W - Rpi.com
https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf

(6) Raspberry Pi Pico W vs Pico: Whats The Difference? 3,843 views Jun 30, 2022
Let’s compare the Raspberry Pi Pico, and Pico W. Aside from the obvious difference (the Pico W has wireless connectivity), there are a few smaller and more subtle differences that are worth considering.

(7) Pico W - The full guide: https://core-electronics.com.au/guide
https://www.youtube.com/watch?v=BkfIxLreqFw

(8) Raspberry Pi Pico W | Overview, Features and Specs - By Michael Updated 30 June 2022

(9) Pico W Datasheet - Rpi.com
https://datasheets.raspberrypi.com/picow/pico-w-datasheet.pdf

(10) Raspberry Pi Pico Web Server Control GPIO Outputs

(11) Controlling a LED via the web

Rpi Pico W Setup/Test Notes 2.2 - Running a Web Server

(1) Raspberry Pi Pico W | Overview, Features and Specs By Michael Updated 30 June 2022

Connecting to the Internet with Raspberry Pi Pico W - Rpi.com
https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf

3.4. The on-board LED

Unlike the original Raspberry Pi Pico, the on-board LED on Pico W is not connected to a pin on RP2040, but instead to a GPIO pin on the wireless chip. MicroPython has been modified accordingly. This means that you can now do:

>>> import machine
>>> led = machine.Pin("LED", machine.Pin.OUT)
>>> led.off()
>>> led.on()

or even:
>>> led.toggle()

to change the current state. However, if you now look at the led object:

>>> led

Pin(WL_GPIO0, mode=OUT)

>>>

You can also do the following:

>>> led = machine.Pin("LED", machine.Pin.OUT, value=1)

which will configure the led object, associate it with the on-board LED and turn the LED on.

Connect WiFi and switch on/off LED


What’s the best hardware to learn IoT programming? - Kevin Tofel, 2022jul12



https://wbactive.com/11-great-raspberry-pi-pico-projects-review-geek/


TI CC3100 WiFi Network Processor Block Diagram






Setup Web Server on Pico W
https://projects.raspberrypi.org/en/projects/get-started-pico-w/1

.END

https://www.kickstarter.com/projects/336477435/mini-pupper-open-sourceros-robot-dog-kit




https://www.jumia.com.ng/generic-hc-05-rs232ttl-wireless-bluetooth-transceiver-module-for-arduino-raspberry-pi-135632377.html







https://www.pi-top.com/bundles/robotics-electronics

https://www.tutorialspoint.com/raspberry-pi-pico-an-introduction-with-micropython/index.asp



https://www.electronicdesign.com/markets/robotics/video/21247033/electronic-design-so-you-want-to-get-started-with-robotics




.END







https://www.digitaljournal.com/pr/k-12-robotic-toolkits-market-will-hold-the-largest-industry-share-owing-to-the-rising-market-popularity-in-global-countries-including-86-pages-report

https://www.tutorialspoint.com/raspberry-pi-boot-camp/index.asp

https://nuttx.apache.org/docs/latest/platforms/arm/rp2040/boards/raspberrypi-pico-w/index.html

https://forums.raspberrypi.com/viewtopic.php?t=340360


.END

https://all3dp.com/1/50-cool-things-to-3d-print-for-october-2022/



Self-Balancing Robot Using PID Packs Other Punches - Elektromagzine



Raspberry Pi Pico W: WiFi Controlled Robot - Explaining Computers









# Why am I the only girl in my A-Level computer science class?

https://www.computerweekly.com/blog/WITsend/Why-am-I-the-only-girl-in-my-A-Level-computer-science-class


https://www.prnewsblog.com/news/tech/14561/how-to-use-a-raspberry-pi-to-build-a-wi-fi-access-point/





https://learn.adafruit.com/guides/projects?guide_page=33&total_count=1920&total_verbiage=total+series

wow what a coding you explain. love your work related lawn mower. what to ask you is compeletily safe to use lawn mower

Yes, it is almost as save as a vacuum cleaner.


https://www.pi-top.com/bundles/robotics-electronics?utm_source=sendinblue&utm_campaign=End%20User%20Newsletter%20December%202022&utm_medium=email

There is something for everyone at zing manga because it offers a diverse selection of genres and interests. Zinmangaa is a veritable gold mine where you can find, read, and relish an array of captivating stories, regardless of your preference for suspenseful novels, engrossing books, or immersive manga.