Uncategorized

spv5 notes

Making a Rpi Pico Based Smart Vehicle

ProjectsJun 3018 / 18Sep 105h ago1 MONTH LATER

tlfong0112 4d

I am drafting a test function to proving the concept of:

  1. Using a list of two interrupt event counts of this 2WD (later 4 counts for 4WD).
  2. Using only one callback function for 2WD’s two interrupt pins.

# *** Interrupt Functions ***

# *** Interrupt Event Variables and Service Routines *** 

# *** Setup Motor and Vehicle ***

def setupMotorV2(motorDriverDictNum, motorNum):
    motorDriverDict         = motorDriverDictDict[str(motorDriverDictNum)] # Get driver dict
    driverStandBy           = Pin(motorDriverDict['STANDBY'], Pin.OUT) # create driverStandBy pin object    
    motorIn1                = Pin(motorDriverDict[str(motorNum)]['IN1'], Pin.OUT) # Create Motor # motorNum In1 pin object
    motorIn2                = Pin(motorDriverDict[str(motorNum)]['IN2'], Pin.OUT) # Create Motor # motorNum In2 pin object    
    motorPwm                = PWM(Pin(motorDriverDict[str(motorNum)]['PWM'])) # Create Motor # motorNum Pwm pin object    
    motorEncode             = Pin(motorDriverDict[str(motorNum)]['ENCODE'], Pin.IN, Pin.PULL_DOWN) # Create Motor # motorNum Encode pin object
    motorPwmFreq            = motorDriverDict[str(motorNum)]['DEFAULT_PWM_FREQ']
    motorDutyCycle          = motorDriverDict[str(motorNum)]['DEFAULT_DUTY_CYCLE']
    motorEncodeIntCount     = 0   
    motorConfigDict = {'StdBy': driverStandBy, 'In1': motorIn1, 'In2': motorIn2, 'Pwm': motorPwm, 'Encode': motorEncode}
    motorConfigDict['StdBy'].high() # enable motor driver normal operation, (low = disable)
    motorConfigDict['Pwm'].freq(motorPwmFreq)                          # setup frequency
    motorConfigDict['Pwm'].duty_u16(int(65536 / 100) * motorDutyCycle) #   and duty cycle    
    motorStateDict = {'PwmFreq': motorPwmFreq, 'DutyCycle': motorDutyCycle, 'MotorEncodeIntCount': motorEncodeIntCount}     
    motorDict = {'MOTOR_CONFIG_DICT': motorConfigDict, 'MOTOR_STATE_DICT': motorStateDict}    
    stopMotor(motorConfigDict)
    return motorDict

def setupVehicleV2(vehicleNum):
    print('  setupVehicle(), ...')
    motorDriverDictNum  = vehicleDictDict[str(vehicleNum)]['MOTOR_DRIVER_DICT_NUM']
    frontLeftMotorDict  = setupMotorV2(motorDriverDictNum, 1)
    frontRightMotorDict = setupMotorV2(motorDriverDictNum, 2)
    frontLeftMotorInterruptPin  = frontLeftMotorDict['MOTOR_CONFIG_DICT']['Encode']
    frontRightMotorInterruptPin = frontRightMotorDict['MOTOR_CONFIG_DICT']['Encode']
    motorInterruptPinList = [frontLeftMotorInterruptPin, frontRightMotorInterruptPin]    
    vehicleDict = {'FRONT_LEFT_MOTOR': frontLeftMotorDict, 'FRONT_RIGHT_MOTOR': frontRightMotorDict, 'INTERRUPT_PIN_LIST': motorInterruptPinList}  
    return vehicleDict

def testSyncTwoVehicleWheels():
    print('testSyncTwoVehicleWheels(), ...')   
  
    # *** This function reads one of the interrupt count list *** 
    def readMotorEncodeIntCount(countNum):    
        return motorEncodeIntCount[countNum]

    # *** motorEncodeCallBack ***
    # Notes:
    #   This callback function is a bit too clever to understand.  All motor interrupt pins will trigger this callback.
    #   The callback will find which interrupt pin interrupts, then increment the corresponding element of the int count list.    
    def motorEncodeIntCallBack(pin):
        index = interruptPinList.index(pin)
        motorEncodeIntCountList[index] += 1    
        return        
    
    vehicleDict = setupVehicleV2(vehicleNum = 1)
    
    vehicleDict['INTERRUPT_PIN_LIST'][0].irq(motorEncodeIntCallBack, Pin.IRQ_FALLING)    
    vehicleDict['INTERRUPT_PIN_LIST'][1].irq(motorEncodeIntCallBack, Pin.IRQ_FALLING)     
    
    #print('  motorEncodeIntServiceRoutine[2] =', motorEncodeIntCountList[2])    
    
    return

# *** Main Tests ***

#testMoveVehicleForwardBackwardTurnLeftTurnRight()

testSyncTwoVehicleWheels()
    
# End


I was jealous that PiTop4 can use mpu6050 gesture to control a robot. This morning I read how to do it. So I might try later to use my smart phone to control my smart robot, to say, first walk in a straight line.

Raspberry Pi Pico Controls Robot with Smartphone Accelerometer – Ash Hill, 2021sep07
Tom’s Hardware – 6 Sep 21

Raspberry Pi Pico Controls Robot with Smartphone Accelerometer

It’s like Kirby Tilt and Tumble but without Kirby and your Game Boy is a phone.

Raspberry Pi: Python Libraries for I2C, SPI, UART – Sebastian Günther, 2021sep06
DEV Community

Raspberry Pi: Python Libraries for I2C, SPI, UART

The Raspberry Pi is one of the most popular single board computers for hobbyists. Its 40 Pins support…


I feel jealous that some smart guy has a smart 4WD, while mine is only a stupid looking 2WD, which should damage my reputation. So I am stalling my 2WD project and go build a smart 4WD. Stay tuned. See you later.four_wheel_drive_2021sep07021192×751 229 KB


Scaling up 2WD to 4WD

So there you are, 2WD becomes 4WD!

pico 4wd 2021sep0701


# Program Name
#   spv5013_2021sep0603.py - tlfong01 2021sep06hkt1802

# Reference
#   Pi-Top Forum - making-a-rpi-pico-based-smart-vehicle/924
#   https://forum.pi-top.com/t/making-a-rpi-pico-based-smart-vehicle/924
#
# Configuration
#   Acer Aspire XC-780 Intel CORE i5-6400 2.7GHz, 8GB, Chinese Windows 10 Home (64-bit, 2020nov15),
#   Thonny 3.3.3, Python 3.7.9 (32-bit), Tk 8.6.9, USB COM Port #4
#
# Thonny MicroPython Intepreter
#   Micropython (Rapsberry Pi Pico)
#
# DC Motor
#   TT130 1:48 gear motor 
#     9.0V = 350mA = 240uS = 70rpm
#     7.2V = 270mA = 300us = 55rpm
#     6.0V = 250mA = 340us = 49rpm
#     4.5V = 200mA = 400us = 42rpm
#     3.0V = 150mA = 660us = 25rpm
#   N20 1:100 6V DC Gear Motor with quadrature encoder signals A, B
#   N20 Gear Motor Spec (6V gear 1:100 no load speed = 300 rpm (https://www.pololu.com/search/compare/173)
#   
# DC Motor Driver
#   TB6612FNG Dual DC Motor Driver

# Brief Description of Program Function
#   1. Move DC motor forward, backware, stop.
#   2. Use PWM to control motor speed
#   3. Use motor encoder to measure speed
#   4. Use encoder signals to help driving a 2WD to move in a straight line

# Digital Oscilloscope ATTEN ADS1102CAL+
# https://toolboom.com/en/digital-oscilloscope-atten-ads1102calplus/

# ATTEN ADS100 User Manual
# https://micromir.ucoz.ru/Oscil/Atten/ADS1000_User_Manual.pdf

import utime
from machine import Pin, PWM

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

# *** Motor Level Config and Functions ***

# *** Motor Dicts ***

motorDriverDict02 = {
              'TITLE' : 'TB6612FNG Dual DC Motor Driver Dictionary v0.2  tlfong01 2021aug23hkt1009',
              'STANDBY' : 5, 
              '1': {'IN1': 10, 'IN2': 11, 'PWM' : 3, 'ENCODE': 14, \
                    'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},
              '2': {'IN1': 12, 'IN2': 13, 'PWM' : 4, 'ENCODE': 15, \
                    'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},
              '3': {'IN1':  0, 'IN2':  0, 'PWM' : 0, 'ENCODE':  0, \
                    'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},
              '4': {'IN1':  0, 'IN2':  0, 'PWM' : 0, 'ENCODE':  0, \
                    'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},                 
              }

motorDriverDictDict = {
                '1': motorDriverDict02,
                '2': motorDriverDict02,                
                }

# *** Motor Functions ***

def setupMotor(motorDriverDictNum, motorNum):
    motorDriverDict   = motorDriverDictDict[str(motorDriverDictNum)] # Get driver dict
    driverStandBy     = Pin(motorDriverDict['STANDBY'], Pin.OUT) # create driverStandBy pin object    
    motorIn1          = Pin(motorDriverDict[str(motorNum)]['IN1'], Pin.OUT) # Create Motor # motorNum In1 pin object
    motorIn2          = Pin(motorDriverDict[str(motorNum)]['IN2'], Pin.OUT) # Create Motor # motorNum In2 pin object    
    motorPwm          = PWM(Pin(motorDriverDict[str(motorNum)]['PWM'])) # Create Motor # motorNum Pwm pin object    
    motorEncode       = Pin(motorDriverDict[str(motorNum)]['ENCODE'], Pin.IN, Pin.PULL_DOWN) # Create Motor # motorNum Encode pin object
  
    motorPwmFreq      = motorDriverDict[str(motorNum)]['DEFAULT_PWM_FREQ']
    motorDutyCycle    = motorDriverDict[str(motorNum)]['DEFAULT_DUTY_CYCLE']
    motorEncIntCntRev = motorDriverDict[str(motorNum)]['DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION']
    
    motorConfigDict = {'StdBy': driverStandBy, 'In1': motorIn1, 'In2': motorIn2, 'Pwm': motorPwm, 'Encode': motorEncode}    
    
    motorStateDict = {'PwmFreq': motorPwmFreq, 'DutyCycle': motorDutyCycle, 'EncodeIntCntRev': motorEncIntCntRev} 
    
    motorDict = {'MOTOR_CONFIG_DICT': motorConfigDict, 'MOTOR_STATE_DICT': motorStateDict}
    
    motorConfigDict['StdBy'].high() # enable motor driver normal operation, (low = disable)
    motorConfigDict['Pwm'].freq(motorStateDict['PwmFreq'])                          # setup frequency
    motorConfigDict['Pwm'].duty_u16(int(65536 / 100) * motorStateDict['DutyCycle']) #   and duty cycle
    stopMotor(motorConfigDict)
    return motorDict

def changeMotorPwmFreqAndDutyCycle(motorDict, pwmFreq, dutyCycle):
    motorStateDict = motorDict['MOTOR_STATE_DICT']
    motorStateDict['PwmFreq'] = pwmFreq
    motorStateDict['DutyCycle'] = dutyCycle
    
    motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
    motorConfigDict['Pwm'].freq(motorStateDict['PwmFreq'])                          
    motorConfigDict['Pwm'].duty_u16(int(65536 / 100) * motorStateDict['DutyCycle'])
    return

def stopMotor(motorConfigDict):
    motorConfigDict['In1'].low() 
    motorConfigDict['In2'].low() 
    return

def moveMotorForwardNonStop(motorConfigDict):
    motorConfigDict['In1'].low()  # move motor
    motorConfigDict['In2'].high() #   backward
    return

def moveMotorForwardSeconds(motorConfigDict, moveSeconds):
    moveMotorForwardNonStop(motorConfigDict)
    utime.sleep(moveSeconds)    
    stopMotor(motorConfigDict)
    return

def moveMotorForwardHoldTime(motorConfigDict, holdTime):
    moveMotorForwardNonStop(motorConfigDict)
    utime.sleep(holdTime)    
    stopMotor(motorConfigDict)
    return

def moveMotorBackwardNonStop(motorConfigDict):
    motorConfigDict['In1'].high()  # move motor
    motorConfigDict['In2'].low() #   backward
    return

def moveMotorBackwardSeconds(motorConfigDict, moveSeconds):
    moveMotorBackwardNonStop(motorConfigDict)    
    utime.sleep(moveSeconds)    
    stopMotor(motorConfigDict)
    return

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

# *** Interrupt Related Functions ***

def encodeIntCallBack(pin):
    global encodeIntCount
    encodeIntCount = encodeIntCount + 1    
    return

def readEncodeIntCount(motorDriverDictNum, motorNum, pwmFreq, dutyCycle, moveSeconds):
    motorDict = setupMotor(motorDriverDictNum, motorNum)   
    motorStateDict  = motorDict['MOTOR_STATE_DICT']
    motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
    changeMotorPwmFreqAndDutyCycle(motorDict, pwmFreq, dutyCycle)    

    motorConfigDict['Encode'].irq(encodeIntCallBack, Pin.IRQ_FALLING)
    
    global encodeIntCount
    encodeIntCount = 0    
    
    moveMotorForwardNonStop(motorConfigDict)  
    utime.sleep(moveSeconds)        
    stopMotor(motorConfigDict)              
    
    totalEncodeIntCount = encodeIntCount
    return totalEncodeIntCount

# *** Move revoloutions and distance ***

def moveMotorEncodeIntCount(motorDriverDictNum, motorNum, encodeIntCount):
    motorDict = setupMotor(motorDriverDictNum, motorNum)
    motorConfigDict = motorDict['MOTOR_CONFIG_DICT']    
        
    #intCountPerSecond = 983
    intCountPerSecond = 750     
  
    print('  encodeIntCount    =', encodeIntCount)
    print('  intCountPerSecond =', intCountPerSecond)
 
    moveSeconds = encodeIntCount / intCountPerSecond  
    print('  moveSeconds       =', moveSeconds)      
       
    moveMotorForwardNonStop(motorConfigDict)
    utime.sleep(moveSeconds)
    stopMotor(motorConfigDict)
    return

def moveMotorRevolutions(motorDriverDictNum, motorNum, revolutions):
    motorDict = setupMotor(motorDriverDictNum, motorNum)
    motorConfigDict = motorDict['MOTOR_CONFIG_DICT']    
        
    intCountPerRevolution = 983
    intCountPerSecond = 750
    moveSeconds = (revolutions * intCountPerRevolution) / intCountPerSecond     
  
    print('  intCountPerRevolution    =', intCountPerRevolution)
    print('  intCountPerSecond        =', intCountPerSecond)
    print('  moveSeconds              =', moveSeconds)      
       
    moveMotorForwardNonStop(motorConfigDict)
    utime.sleep(moveSeconds)
    stopMotor(motorConfigDict)
    return

# *** Test Functions *** 

def testMoveMotorForwardSeconds(motorDriverDictNum, motorNum, moveSeconds):
    print('\ntestmoveMotorForwardSeconds()')
    motorDict = setupMotor(motorDriverDictNum, motorNum)
    motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
    moveMotorForwardSeconds(motorConfigDict, moveSeconds)
    stopMotor(motorConfigDict)     
    return

def testMoveMotorBackwardSeconds(motorDriverDictNum, motorNum, moveSeconds):
    print('\ntestMoveMotorBackwardSeconds()')
    motorDict = setupMotor(motorDriverDictNum, motorNum)
    motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
    moveMotorBackwardSeconds(motorConfigDict, moveSeconds)
    stopMotor(motorConfigDict)     
    return

def testChangeMotorPwmFreqAndDutyCycleAndmoveMotorForwardSeconds(motorDriverDictNum, motorNum, pwmFreq, dutyCycle, moveSeconds):
    print('\ntestChangeMotorPwmFreqAndDutyCycleAndmoveMotorForwardSeconds()')
    motorDict = setupMotor(motorDriverDictNum, motorNum)
    changeMotorPwmFreqAndDutyCycle(motorDict, pwmFreq, dutyCycle)
    
    motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
    print('moveSeconds =', moveSeconds)
    moveMotorForwardSeconds(motorConfigDict, moveSeconds)
    stopMotor(motorConfigDict)     
    return 

def testMeasureMotorSpeed(motorDriverDictNum, motorNum, pwmFreq, dutyCycle):    
    totalEncodeIntCount = readEncodeIntCount(motorDriverDictNum, motorNum, pwmFreq, dutyCycle, moveSeconds = 1)        
    print('motorNum =', motorNum, end = '')
    print('  pwmFreq   =', pwmFreq, end = '')
    print('  dutyCycle =', dutyCycle, end = '')
    print('  totalEncodeIntCount Per Second =', totalEncodeIntCount, end = '')
    print('  motor speed rpm =', int(int(totalEncodeIntCount * 60)/100))              
    return

def testMoveMotorEncodeIntCount(motorDriverDictNum, motorNum, encodeIntCount):
    print('testMoveMotorEncodeIntCount(), ...')
    moveMotorEncodeIntCount(motorDriverDictNum, motorNum, encodeIntCount)
    return

def testMoveMotorRevolutions(motorDriverDictNum, motorNum, revolutions):
    print('testMoveMotorRevolutions(), ...')
    moveMotorRevolutions(motorDriverDictNum, motorNum, revolutions)
    return

def testMeasureEncodeIntCountMoveSeconds(motorDriverDictNum, motorNum, pwmFreq, dutyCycle, moveSeconds):
    encodeIntCount = readEncodeIntCount(motorDriverDictNum, motorNum, pwmFreq, dutyCycle, moveSeconds)
    print('MotorDriverDictNum =', motorDriverDictNum, ' ', end = '')
    print('MotorNum =', motorNum, ' ', end = '')
    print('PWM Freq =', pwmFreq, ' ', end = '')
    print('DutyCycle =', dutyCycle, ' ', end = '')
    print('MoveSeconds =,', moveSeconds, ' ', end = '')            
    print('encodeIntCount =', encodeIntCount)
    return encodeIntCount

def testStopMotor(motorDriverDictNum, motorNum):
    motorDict = setupMotor(motorDriverDictNum, motorNum)
    motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
    stopMotor(motorConfigDict)     
    return

# *** Old Main Tests ***

'''
testMoveMotorForwardSeconds(motorDriverDictNum = 2, motorNum = 1, moveSeconds = 2)
testMoveMotorBackwardSeconds(motorDriverDictNum = 2, motorNum = 2, moveSeconds = 4)
testChangeMotorPwmFreqAndDutyCycleAndmoveMotorForwardSeconds(motorDriverDictNum = 2, motorNum = 1 , \                                              pwmFreq = 1000, dutyCycle = 10, moveSeconds = 2)                               
testChangeMotorPwmFreqAndDutyCycleAndmoveMotorForwardSeconds(motorDriverDictNum = 2, motorNum = 1 , \ 
                                                     pwmFreq = 1000, dutyCycle = 90, moveSeconds = 1)
testMeasureMotorSpeed(motorDriverDictNum = 2, motorNum = 1, pwmFreq = 1000, dutyCycle = 80)
testMeasureMotorSpeed(motorDriverDictNum = 2, motorNum = 1, pwmFreq = 1000, dutyCycle = 10)
testMoveMotorEncodeIntCount(motorDriverDictNum = 2, motorNum = 1, encodeIntCount = 1020)
testMoveMotorEncodeIntCount(motorDriverDictNum = 2, motorNum = 2, encodeIntCount = 1920)
testMoveMotorRevolutions(motorDriverDictNum = 2, motorNum = 1, revolutions = 1)
testMeasureEncodeIntCountMoveSeconds(motorDriverDictNum = 2, motorNum = 1, pwmFreq = 1000, dutyCycle = 100, moveSeconds = 4)
testStopMotor(motorDriverDictNum = 2, motorNum = 1)
'''

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

#
# *** Vehicle Level Config and Functions ***

vehicleDict01 = {
                  'MOTOR_DRIVER_DICT_NUM': 2,
                }

vehicleDictDict = {
                     '1': vehicleDict01,
                     '2': vehicleDict01,
                  }

# *** Vehicle and Wheel Functions ***


'''
def encodeIntCallBack(pin):
    global encodeIntCount
    encodeIntCount = encodeIntCount + 1    
    return

def readEncodeIntCount(motorDriverDictNum, motorNum, pwmFreq, dutyCycle, moveSeconds):
    motorDict = setupMotor(motorDriverDictNum, motorNum)   
    motorStateDict  = motorDict['MOTOR_STATE_DICT']
    motorConfigDict = motorDict['MOTOR_CONFIG_DICT']
    changeMotorPwmFreqAndDutyCycle(motorDict, pwmFreq, dutyCycle)    

    motorConfigDict['Encode'].irq(encodeIntCallBack, Pin.IRQ_FALLING)
    
    global encodeIntCount
    encodeIntCount = 0    
    
    moveMotorForwardNonStop(motorConfigDict)  
    utime.sleep(moveSeconds)        
    stopMotor(motorConfigDict)              
    
    totalEncodeIntCount = encodeIntCount
    return totalEncodeIntCount
    
motorDriverDict02 = {
              'TITLE' : 'TB6612FNG Dual DC Motor Driver Dictionary v0.2  tlfong01 2021aug23hkt1009',
              'STANDBY' : 5, 
              '1': {'IN1': 10, 'IN2': 11, 'PWM' : 3, 'ENCODE': 14, \
                    'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},
              '2': {'IN1': 12, 'IN2': 13, 'PWM' : 4, 'ENCODE': 15, \
                    'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},
              '3': {'IN1':  0, 'IN2':  0, 'PWM' : 0, 'ENCODE':  0, \
                    'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},
              '4': {'IN1':  0, 'IN2':  0, 'PWM' : 0, 'ENCODE':  0, \
                    'DEFAULT_PWM_FREQ': 1000, 'DEFAULT_DUTY_CYCLE': 50, 'DEFAULT_ENCODE_INT_PULSE_PER_REVOLUTION': 980},                 
              }    
'''

def setupVehicle(vehicleNum):
    motorDriverDictNum  = vehicleDictDict[str(vehicleNum)]['MOTOR_DRIVER_DICT_NUM']
    frontLeftMotorDict  = setupMotor(motorDriverDictNum, 1)
    frontRightMotorDict = setupMotor(motorDriverDictNum, 2)
    motorDictDict = {'FRONT_LEFT_MOTOR': frontLeftMotorDict, 'FRONT_RIGHT_MOTOR': frontRightMotorDict}
    return motorDictDict

def moveVehicleMotorListForwardHoldTime(vehicleNum, holdTime):
    motorDictDict = setupVehicle(vehicleNum)    
    frontLeftMotorConfigDict  = motorDictDict['FRONT_LEFT_MOTOR']['MOTOR_CONFIG_DICT']
    frontRightMotorConfigDict = motorDictDict['FRONT_RIGHT_MOTOR']['MOTOR_CONFIG_DICT']       
    motorConfigDictList = [frontLeftMotorConfigDict,  frontRightMotorConfigDict] 
    for motorConfigDict in motorConfigDictList:
        moveMotorForwardNonStop(motorConfigDict)
    utime.sleep(holdTime)
    for motorConfigDict in motorConfigDictList:
       stopMotor(motorConfigDict) 
    return

def moveVehicleMotorListBackwardHoldTime(vehicleNum, holdTime):
    motorDictDict = setupVehicle(vehicleNum)    
    frontLeftMotorConfigDict  = motorDictDict['FRONT_LEFT_MOTOR']['MOTOR_CONFIG_DICT']
    frontRightMotorConfigDict = motorDictDict['FRONT_RIGHT_MOTOR']['MOTOR_CONFIG_DICT']       
    motorConfigDictList = [frontLeftMotorConfigDict,  frontRightMotorConfigDict] 
    for motorConfigDict in motorConfigDictList:
        moveMotorBackwardNonStop(motorConfigDict)
    utime.sleep(holdTime)
    for motorConfigDict in motorConfigDictList:
       stopMotor(motorConfigDict) 
    return

def turnTwoMotorsLeftHoldTime(frontLeftMotorConfigDict, frontReghtConfigDict, holdTime):
    moveMotorForwardNonStop(frontLeftMotorConfigDict)
    moveMotorBackward(frontRightMotorConfigDict)    
    utime.sleep(holdTime)    
    stopMotor(frontLeftMotorConfigDict)
    stopMotor(frontRightMotorConfigDict)    
    return

def turnVehicleLeftHoldTime(vehicleNum, holdTime):
    motorDictDict = setupVehicle(vehicleNum)    
    frontLeftMotorConfigDict  = motorDictDict['FRONT_LEFT_MOTOR']['MOTOR_CONFIG_DICT']
    frontRightMotorConfigDict = motorDictDict['FRONT_RIGHT_MOTOR']['MOTOR_CONFIG_DICT']       
    moveMotorForwardNonStop(frontLeftMotorConfigDict)
    moveMotorBackwardNonStop(frontRightMotorConfigDict)    
    utime.sleep(holdTime)
    stopMotor(frontLeftMotorConfigDict)
    stopMotor(frontRightMotorConfigDict)    
    return

def turnVehicleRightHoldTime(vehicleNum, holdTime):
    motorDictDict = setupVehicle(vehicleNum)    
    frontLeftMotorConfigDict  = motorDictDict['FRONT_LEFT_MOTOR']['MOTOR_CONFIG_DICT']
    frontRightMotorConfigDict = motorDictDict['FRONT_RIGHT_MOTOR']['MOTOR_CONFIG_DICT']       
    moveMotorBackwardNonStop(frontLeftMotorConfigDict)
    moveMotorForwardNonStop(frontRightMotorConfigDict)    
    utime.sleep(holdTime)
    stopMotor(frontLeftMotorConfigDict)
    stopMotor(frontRightMotorConfigDict)    
    return

snipped … to avoid 32k word limit

def setupVehicleV2(vehicleNum):
    print('  setupVehicle(), ...')
    motorDriverDictNum  = vehicleDictDict[str(vehicleNum)]['MOTOR_DRIVER_DICT_NUM']
    frontLeftMotorDict  = setupMotorV2(motorDriverDictNum, 1)
    frontRightMotorDict = setupMotorV2(motorDriverDictNum, 2)
    frontLeftMotorInterruptPin  = frontLeftMotorDict['MOTOR_CONFIG_DICT']['Encode']
    frontRightMotorInterruptPin = frontRightMotorDict['MOTOR_CONFIG_DICT']['Encode']
    motorInterruptPinList = [frontLeftMotorInterruptPin, frontRightMotorInterruptPin]    
    vehicleDict = {'FRONT_LEFT_MOTOR': frontLeftMotorDict, 'FRONT_RIGHT_MOTOR': frontRightMotorDict, 'INTERRUPT_PIN_LIST': motorInterruptPinList}  
    return vehicleDict

def testSyncTwoVehicleWheels():
    print('testSyncTwoVehicleWheels(), ...')   
  
    # *** This function reads one of the interrupt count list *** 
    def readMotorEncodeIntCount(countNum):    
        return motorEncodeIntCount[countNum]

    # *** motorEncodeCallBack ***
    # Notes:
    #   This callback function is a bit too clever to understand.  All motor interrupt pins will trigger this callback.
    #   The callback will find which interrupt pin interrupts, then increment the corresponding element of the int count list.    
    def motorEncodeIntCallBack(pin):
        index = interruptPinList.index(pin)
        motorEncodeIntCountList[index] += 1    
        return        
    
    vehicleDict = setupVehicleV2(vehicleNum = 1)
    
    vehicleDict['INTERRUPT_PIN_LIST'][0].irq(motorEncodeIntCallBack, Pin.IRQ_FALLING)    
    vehicleDict['INTERRUPT_PIN_LIST'][1].irq(motorEncodeIntCallBack, Pin.IRQ_FALLING)     
    
    #print('  motorEncodeIntServiceRoutine[2] =', motorEncodeIntCountList[2])    
    
    return

# *** Main Tests ***

#testMoveVehicleForwardBackwardTurnLeftTurnRight()
#testSyncTwoVehicleWheels()
#testTurnVehicleLeftHoldTime()

testMoveMotorForwardSeconds(motorDriverDictNum = 2, motorNum = 1, moveSeconds = 10)


TM310 DC Motor Calibration

TT DC Gear Reduced Motor with Encoder for Smart Car DIY – AliExpress US$5
aliexpress.com

4.8US $ |TT DC Gear Reduced Motor with Encoder for Smart Car DIY or Mecanum…

Smarter Shopping, Better Living! Aliexpress.com

Spec:
Rated voltage: DC 9V
No-load current: 100mA
Stall current: 1.2A
No-load speed: 8000 rpm
Suitable voltage: 6-12V
Reduction ratio: 1:48/1:90 


tm310_test_2021sep0801800×480 145 KB


tm310_test_2021sep08011024×748 274 KB


TM310 Motor #1 and #2 Speed Discrepancy

So I calibrated the second motor. I found the speeds of the second motor is very close to the first one; both encoder signals measure almost “exactly” 300uS.

This is very good news, because it means that it is practical and easy to sync two motors (bought by same order, therefore very likely from the same production lot from the manufacturer), by adjusting PWM duty cycle.

The second motor’s encoder AB signals at 12V power are displayed below.


tm310_2_test_2021sep0801800×480 135 KB


Adding WS2812b NeoPixels LEDs to my 4WD

Now I am thinking of adding NeoPixels to my smart 4WD.Python Awesome – 8 Sep 21 1

A library for using WS2812b leds (aka neopixels) with Raspberry Pi Pico 1

A library for using WS2812b leds (aka neopixels) with Raspberry Pi Pico


This pico relay module looks good. I hope to get on and mount it on my smart pico.The Pi Hut

Industrial 8-Channel Relay Module for Raspberry Pi Pico

Utilise the Raspberry Pi Pico in industrial or home automation environments with this robust Industrial 8-Channel Relay Module! This module provides 8 relay channels which can each switch up to 10A 250VAC or 10A 30V DC max. The module offers safety…

Price: GBP 17.00


MT310 Encoder Motor #3 Calibration Notes

So I checked out MT310 #3. It seems too good to be true that this third motor’s encoder A signal is also almost exactly 300uS. Now I need to display all 4 motor’s encoder A signals together, at the same time, and and see if there is any tiny difference of the A signal periods. I still think now it is too good to be true, or there are some critical mistake I have made in the calibrations.tm310_3_test_2021sep0802800×480 142 KB


MT310 Motor #4 12V power Speed Measurement

So I checked out Motor 4. I was glad to see the that that encoder Signal is now 290us, not 300us as other three. If all 4 motors were axactly 300us, than is was too good to be true. Now (300 – 290) / 300 ~= 0.3% speed difference. I guess it should be easy to adjust the duty cycle of either motor to get same speed. (Apology: it should not be called “in sync” which is about time, but should be called speed matching, which is about speed.


tm310_04_test_2021sep1001800×480 137 KB


Note – I am hitting the forum’s 32k word limit again. So I need to make a new reply.

/ to continue, …Reply

tlfong015h

Speed measurement of 4 MT310 motors

The encoder A signal of Motor 4 has little glitches. I need to display all 4 A signals together, at the same time, to see if this switching noise/glitches is common to all 4 motors, or just Motor 4.

Now I am doing the following speed measurements.

  1. All 4 MT310 motors powered by the same 12V DC.
  2. All 4 MT310 motor encoder powered by the same 5VDC.
  3. Use 30MHz 4 channel scope to display the 4 encoder A signals.
  4. Check if the A signals have almost identical, say, 300uS period.

MT310 Encoder Motor x 4 powered by 12VDC moving at the same time

mt310 motor test 2021sep1001


4WD TM310 1:90 Encoder 12ppr powered by 12VDC

I am happy to see my 4 channel scope displaying the 4 motors’ encoder A signals all showing roughly 300us period pulses. I am not going to take pulse period measurements by hand and then calculate the corresponding speeds, because my next step is to use Thonny micropython to detect the encoder A signals as interrupt events and count them to calculate very precise speed values.tm310_4wd_test_2021sep1001800×480 173 KB


/ to continue, …

Categories: Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.