Close

I Have an Update Finally!

A project log for Mower and BBG/MotorBridgeCape

I am trying to make a robotic mower for the BBG and MotorBridgeCape with some old parts, electronics, and/or stuff...enjoy.

silver2rowsilver2row 02/17/2022 at 11:380 Comments

So, 

Here we are again trying to make something that works well, work better!

Please view the video:

So, that is the bot but smaller. It is not a mower but has four, bidirectional DC Motors that work together to move the bot in an almost frictionless movement. 

The software is here:

# /*
 # * MotorBridge.py
 # * This is a library for BBG/BBB motor bridge cape
 # *
 # * Copyright (c) 2015 seeed technology inc.
 # * Author      : Jiankai Li
 # * Create Time : Nov 2015
 # * Change Log  : From #beagle on Freenode and my changes (Seth 2019)!
 # *
 # * The MIT License (MIT)
 # *
 # * Permission is hereby granted, free of charge, to any person obtaining a copy
 # * of this software and associated documentation files (the "Software"), to deal
 # * in the Software without restriction, including without limitation the rights
 # * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 # * copies of the Software, and to permit persons to whom the Software is
 # * furnished to do so, subject to the following conditions:
 # *
 # * The above copyright notice and this permission notice shall be included in
 # * all copies or substantial portions of the Software.
 # *
 # * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 # * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 # * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 # * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 # * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # * THE SOFTWARE.
 # */
# FileName : MotorBridge.py
# by Jiankai.li

# w/ help from additions from #beagle on what used to be Freenode and me (Seth)!

from smbus2 import SMBus
import time
import pathlib

# reset pin is P9.23, i.e. gpio1.17
reset_pin = pathlib.Path('/sys/class/gpio/gpio49/direction')
reset_pin.write_text('low')

MotorBridge = SMBus('/dev/i2c-2')

ReadMode  = 0
WriteMode = 1
DeAddr    = 0X4B
ConfigValid = 0x3a6fb67c
DelayTime = 0.005

# TB_WORKMODE

TB_SHORT_BREAK  = 0
TB_CW           = 1
TB_CCW          = 2
TB_STOP         = 3
TB_WORKMODE_NUM = 4


# TB_PORTMODE

TB_DCM          = 0
TB_SPM          = 1
TB_PORTMODE_NUM = 2


# SVM_PORT

SVM1            = 0
SVM2            = 1
SVM3            = 2
SVM4            = 3
SVM5            = 4
SVM6            = 5
SVM_PORT_NUM    = 6

# SVM_STATE

SVM_DISABLE     = 0
SVM_ENABLE      = 1
SVM_STATE_NUM   = 2

# IO_MODE

IO_IN           = 0
IO_OUT          = 1
IO_MODE_NUM     = 2

# IO_PUPD

IO_PU           = 0
IO_PD           = 1
IO_NP           = 2
IO_PUPD_NUM     = 3

# IO_PPOD

IO_PP           = 0
IO_OD           = 1
IO_PPOD_NUM     = 2

# IO_STATE

IO_LOW          = 0
IO_HIGH         = 1
IO_STATE_NUM    = 2

# IO_PORT

IO1             = 0
IO2             = 1
IO3             = 2
IO4             = 3
IO5             = 4
IO6             = 5
IO_NUM          = 6


# PARAM_REG

CONFIG_VALID        = 0
CONFIG_TB_PWM_FREQ  = CONFIG_VALID + 4

I2C_ADDRESS         = CONFIG_TB_PWM_FREQ + 4

TB_1A_MODE          = I2C_ADDRESS + 1
TB_1A_DIR           = TB_1A_MODE + 1
TB_1A_DUTY          = TB_1A_DIR + 1
TB_1A_SPM_SPEED     = TB_1A_DUTY + 2
TB_1A_SPM_STEP      = TB_1A_SPM_SPEED + 4

TB_1B_MODE          = TB_1A_SPM_STEP + 4
TB_1B_DIR           = TB_1B_MODE + 1
TB_1B_DUTY          = TB_1B_DIR + 1
TB_1B_SPM_SPEED     = TB_1B_DUTY + 2
TB_1B_SPM_STEP      = TB_1B_SPM_SPEED + 4

TB_2A_MODE          = TB_1B_SPM_STEP + 4
TB_2A_DIR           = TB_2A_MODE + 1
TB_2A_DUTY          = TB_2A_DIR + 1
TB_2A_SPM_SPEED     = TB_2A_DUTY + 2
TB_2A_SPM_STEP      = TB_2A_SPM_SPEED + 4

TB_2B_MODE          = TB_2A_SPM_STEP + 4
TB_2B_DIR           = TB_2B_MODE + 1
TB_2B_DUTY          = TB_2B_DIR + 1
TB_2B_SPM_SPEED     = TB_2B_DUTY + 2
TB_2B_SPM_STEP      = TB_2B_SPM_SPEED + 4

SVM1_STATE          = TB_2B_SPM_STEP + 4
SVM1_FREQ           = SVM1_STATE + 1
SVM1_ANGLE          = SVM1_FREQ + 2

SVM2_STATE          = SVM1_ANGLE + 2
SVM2_FREQ           = SVM2_STATE + 1
SVM2_ANGLE          = SVM2_FREQ + 2

SVM3_STATE          = SVM2_ANGLE + 2
SVM3_FREQ           = SVM3_STATE + 1
SVM3_ANGLE          = SVM3_FREQ + 2

SVM4_STATE          = SVM3_ANGLE + 2
SVM4_FREQ           = SVM4_STATE + 1
SVM4_ANGLE          = SVM4_FREQ + 2

SVM5_STATE          = SVM4_ANGLE + 2
SVM5_FREQ           = SVM5_STATE + 1
SVM5_ANGLE          = SVM5_FREQ + 2

SVM6_STATE          = SVM5_ANGLE + 2
SVM6_FREQ           = SVM6_STATE + 1
SVM6_ANGLE          = SVM6_FREQ + 2

IO1_STATE           = SVM6_ANGLE + 2
IO1_MODE            = IO1_STATE + 1
IO1_PUPD            = IO1_MODE + 1
IO1_PPOD            = IO1_PUPD + 1

IO2_STATE           = IO1_PPOD + 1
IO2_MODE            = IO2_STATE + 1
IO2_PUPD            = IO2_MODE + 1
IO2_PPOD            = IO2_PUPD + 1

IO3_STATE           = IO2_PPOD + 1
IO3_MODE            = IO3_STATE + 1
IO3_PUPD            = IO3_MODE + 1
IO3_PPOD            = IO3_PUPD + 1

IO4_STATE           = IO3_PPOD + 1
IO4_MODE            = IO4_STATE + 1
IO4_PUPD            = IO4_MODE + 1
IO4_PPOD            = IO4_PUPD + 1

IO5_STATE           = IO4_PPOD + 1
IO5_MODE            = IO5_STATE + 1
IO5_PUPD            = IO5_MODE + 1
IO5_PPOD            = IO5_PUPD + 1

IO6_STATE           = IO5_PPOD + 1
IO6_MODE            = IO6_STATE + 1
IO6_PUPD            = IO6_MODE + 1
IO6_PPOD            = IO6_PUPD + 1

PARAM_REG_NUM = IO6_PPOD + 1

def WriteByte(Reg,Value):
    data = [0 for i in range(2)]
    data[0] = Reg
    data[1] = Value
    MotorBridge.write_i2c_block_data(0x4b, 1, data)

def WriteHalfWord(Reg,Value):
    data = [0 for i in range(3)]
    data[0] = Reg
    data[1] = Value & 0xff
    data[2] = (Value>>8) & 0xff
    MotorBridge.write_i2c_block_data(0x4b, 1, data)

def WriteOneWord(Reg,Value):
    data = [0 for i in range(5)]
    data[0] = Reg
    data[1] = Value & 0xff
    data[2] = (Value>>8) & 0xff
    data[3] = (Value>>16) & 0xff
    data[4] = (Value>>24) & 0xff
    MotorBridge.write_i2c_block_data(0x4b, 1, data)

def SetDefault():
    WriteOneWord(CONFIG_VALID,0x00000000)

class MotorBridgeCape:
    def __init__(self):
        reset_pin.write_text('high')
        time.sleep(1)

    # init stepper motor A
    def StepperMotorAInit(self):
        WriteByte(TB_1A_MODE,TB_SPM) #Stepper
        time.sleep(DelayTime)
        WriteHalfWord(TB_1A_DUTY,1000)    # voltage
        time.sleep(DelayTime)

    # MoveSteps > 0 CW
    # MoveSteps < 0 CCW
    # StepDelayTime : delay time for every step. uint us
    def StepperMotorAMove(self,MoveSteps,StepDelayTime):
        if MoveSteps > 0:
            WriteByte(TB_1A_DIR,TB_CW)   #CW
        else:
            WriteByte(TB_1A_DIR,TB_CCW)   #CW
            MoveSteps = -MoveSteps
        time.sleep(DelayTime)
        WriteOneWord(TB_1A_SPM_SPEED,StepDelayTime)  # unit us
        time.sleep(DelayTime)
        WriteOneWord(TB_1A_SPM_STEP,MoveSteps)
        time.sleep(DelayTime)


    # init stepper motor B
    def StepperMotorBInit(self):
        WriteByte(TB_2A_MODE,TB_SPM) #Stepper
        time.sleep(DelayTime)
        WriteHalfWord(TB_2A_DUTY,1000)    # voltage
        time.sleep(DelayTime)

    # MoveSteps > 0 CW
    # MoveSteps < 0 CCW
    # StepDelayTime : delay time for every step. uint us
    def StepperMotorBMove(self,MoveSteps,StepDelayTime):
        if MoveSteps > 0:
            WriteByte(TB_2A_DIR,TB_CW)   #CW
        else:
            WriteByte(TB_2A_DIR,TB_CCW)   #CW
            MoveSteps = -MoveSteps
        time.sleep(DelayTime)
        WriteOneWord(TB_2A_SPM_SPEED,StepDelayTime)  # unit us
        time.sleep(DelayTime)
        WriteOneWord(TB_2A_SPM_STEP,MoveSteps)
        time.sleep(DelayTime)

    # Init DC Motor
    def DCMotorInit(self,MotorName,Frequency):
    # Init the DC Frequency
        WriteOneWord(CONFIG_TB_PWM_FREQ,Frequency)
        time.sleep(DelayTime)

    # Set the port as DC Motor
        if MotorName == 1 or MotorName == 2:
            WriteByte(TB_1A_MODE,TB_DCM)
            time.sleep(DelayTime)
            WriteByte(TB_1A_DIR,TB_STOP)
            time.sleep(DelayTime)
            WriteByte(TB_1B_MODE,TB_DCM)
            time.sleep(DelayTime)
            WriteByte(TB_1B_DIR,TB_STOP)
            time.sleep(DelayTime)
        if MotorName == 3 or MotorName == 4:
            WriteByte(TB_2A_MODE,TB_DCM)
            time.sleep(DelayTime)
            WriteByte(TB_2A_DIR,TB_STOP)
            time.sleep(DelayTime)
            WriteByte(TB_2B_MODE,TB_DCM)
            time.sleep(DelayTime)
            WriteByte(TB_2B_DIR,TB_STOP)
            time.sleep(DelayTime)

    # Drive the DC Motor
    # Direction 1 CW | 2 CCW
    # PWNDuty  0 ~ 100
    def DCMotorMove(self, MotorName,Direction,PWMDuty):
        if MotorName == 1:
            WriteByte(TB_1B_DIR,Direction)
            time.sleep(DelayTime)
            WriteOneWord(TB_1B_DUTY,PWMDuty*10)
            time.sleep(DelayTime)

        if MotorName == 2:
            WriteByte(TB_1A_DIR,Direction)
            time.sleep(DelayTime)
            WriteOneWord(TB_1A_DUTY,PWMDuty*10)
            time.sleep(DelayTime)

        if MotorName == 3:
            WriteByte(TB_2B_DIR,Direction)
            time.sleep(DelayTime)
            WriteOneWord(TB_2B_DUTY,PWMDuty*10)
            time.sleep(DelayTime)

        if MotorName == 4:
            WriteByte(TB_2A_DIR,Direction)
            time.sleep(DelayTime)
            WriteOneWord(TB_2A_DUTY,PWMDuty*10)
            time.sleep(DelayTime)

    # Stop the DC motor
    def DCMotorStop(self, MotorName):
        if MotorName == 1:
            WriteByte(TB_1B_DIR,TB_STOP)
        if MotorName == 2:
            WriteByte(TB_1A_DIR,TB_STOP)
        if MotorName == 3:
            WriteByte(TB_2B_DIR,TB_STOP)
        if MotorName == 4:
            WriteByte(TB_2A_DIR,TB_STOP)
        time.sleep(DelayTime)

    # init the Servo
    def ServoInit(self,ServoName,Frequency):
        if ServoName == 1:
            WriteHalfWord(SVM1_FREQ,Frequency)
            time.sleep(DelayTime)
            WriteByte(SVM1_STATE,SVM_ENABLE)
            time.sleep(DelayTime)

        if ServoName == 2:
            WriteHalfWord(SVM2_FREQ,Frequency)
            time.sleep(DelayTime)
            WriteByte(SVM2_STATE,SVM_ENABLE)
            time.sleep(DelayTime)
        if ServoName == 3:
            WriteHalfWord(SVM3_FREQ,Frequency)
            time.sleep(DelayTime)
            WriteByte(SVM3_STATE,SVM_ENABLE)
            time.sleep(DelayTime)

        if ServoName == 4:
            WriteHalfWord(SVM4_FREQ,Frequency)
            time.sleep(DelayTime)
            WriteByte(SVM4_STATE,SVM_ENABLE)
            time.sleep(DelayTime)
        if ServoName == 5:
            WriteHalfWord(SVM5_FREQ,Frequency)
            time.sleep(DelayTime)
            WriteByte(SVM5_STATE,SVM_ENABLE)
            time.sleep(DelayTime)

        if ServoName == 6:
            WriteHalfWord(SVM6_FREQ,Frequency)
            time.sleep(DelayTime)
            WriteByte(SVM6_STATE,SVM_ENABLE)
            time.sleep(DelayTime)

    def ServoMoveAngle(self,ServoName,Angle):
        if ServoName == 1:
            WriteHalfWord(SVM1_ANGLE,Angle)
            time.sleep(DelayTime)

        if ServoName == 2:
            WriteHalfWord(SVM2_ANGLE,Angle)
            time.sleep(DelayTime)

        if ServoName == 3:
            WriteHalfWord(SVM3_ANGLE,Angle)
            time.sleep(DelayTime)

        if ServoName == 4:
            WriteHalfWord(SVM4_ANGLE,Angle)
            time.sleep(DelayTime)

        if ServoName == 5:
            WriteHalfWord(SVM5_ANGLE,Angle)
            time.sleep(DelayTime)

        if ServoName == 6:
            WriteHalfWord(SVM6_ANGLE,Angle)
            time.sleep(DelayTime)

if __name__=="__main__":
    print( 'Hello From MotorBridge' )
    #motor = MotorBridgeCape()
    #motor.StepperMotorBInit()
    #while True:
        #motor.StepperMotorBMove(1000,1000) # 20 steppers  1000us every step
        #time.sleep(1)
        #motor.StepperMotorBMove(-1000,1000) # 20 steppers  1000us every step
        #time.sleep(1)

This is the library to use called MotorBridge.py that calls for SMBus2 that can be installed via pip3 or by python3 -m pip install smbus2 .

There is a small write up on Github.com about this particular Cape for beagleboard.org am335x family of boards located here: silver2row/bbg: Motor Bridge Cape and BBG (BeagleBone Green)/Python Scripts (github.com) .

The MBC or Motor Bridge Cape is hard to find these days. It carries a STM32F0 on it. and can handle four DC Motors or two steppers and then can handle six servo motors.

Line 302 on smbus2.py needs to be changed to look like this:

filepath = "/dev/i2c-2".format(bus)

Anyway, that video was from a year back. Let us see if it works w/ the current set up:

uname -r: 4.19.94-ti-r71

cat /etc/dogtag: BeagleBoard.org Debian Buster IoT Image 2020-04-06

This image can be attained from the beagleboard.org/latest-images wesbite or you can use their forum for searching for the new images they produce.

So, if you have any questions, good. If not, see ya!

oh! The next video:

Discussions