Okay and jumping right into it here...
For one, I am excited to make this set up of ideas finally work.
Although the people at beagleboard.org and their personnel made this work years ago, I am just catching on...
So, for one, we have some hardware and we will get into the software later...
https://www.adafruit.com/product/2348 is the product we attach to our BeagleY-AI to make a "simple" DC motor actuate and turn one direction, reverse direction, and then stop. I am using, again, the BeagleY-AI, this Adafruit Motor Hat, and a 9v battery along with a geared DC Motor.
The BeagleY-AI and data on this build can be found here too: https://docs.beagleboard.org/boards/beagley/ai/demos/pca9685-motor-drivers.html
The schematic for the Motor Hat can be found here: https://cdn-learn.adafruit.com/assets/assets/000/022/655/original/raspberry_pi_schem1.png?1422045515
Okay, so only connect the Hat to your BeagleY-AI while the power is off. Once all connections are soldered on or if you are using headers on the Hat, do so and tighten them so that they do not come loose during operation.
Oh. Also, I am using the 6.1.x kernel on the BeagleY-AI. They have a imager for making images on their github.com page online which can be found here: https://github.com/beagleboard/bb-imager-rs/releases/tag/v0.0.14.
So, once your connections are made...
1. Boot the board by supplying USB-C to USB-C into the host and then the target or via fist the target and then the host. In this case the host is our development desktop while the target is our BeagleY-AI.
2. I am using a USB-C to USB-A 3.0 for powering my board and booting the BeagleY-AI.
3. Run some source to test:
sudo apt update && sudo apt upgrade
sudo apt install i2c-tools python3-smbus
Here are the two main files:
1. The code to run once we have our library
#!/usr/bin/python3
# from docs.beagleboard.org
from PCA9685 import PCA9685
import time
Dir = [
'forward',
'backward',
]
pwm = PCA9685(0x40, debug=False)
pwm.setPWMFreq(50)
class MotorDriver():
def __init__(self):
# Match these to your particular HAT!
self.PWMA = 8
self.AIN1 = 10
self.AIN2 = 9
self.PWMB = 5
self.BIN1 = 3
self.BIN2 = 4
def MotorRun(self, motor, index, speed):
if speed > 100:
return
if(motor == 0):
pwm.setDutycycle(self.PWMA, speed)
if(index == Dir[0]):
print ("1")
pwm.setLevel(self.AIN1, 0)
pwm.setLevel(self.AIN2, 1)
else:
print ("2")
pwm.setLevel(self.AIN1, 1)
pwm.setLevel(self.AIN2, 0)
else:
pwm.setDutycycle(self.PWMB, speed)
if(index == Dir[0]):
print ("3")
pwm.setLevel(self.BIN1, 0)
pwm.setLevel(self.BIN2, 1)
else:
print ("4")
pwm.setLevel(self.BIN1, 1)
pwm.setLevel(self.BIN2, 0)
def MotorStop(self, motor):
if (motor == 0):
pwm.setDutycycle(self.PWMA, 0)
else:
pwm.setDutycycle(self.PWMB, 0)
print("this is a motor driver test code")
Motor = MotorDriver()
print("forward 2 s")
Motor.MotorRun(0, 'forward', 100)
Motor.MotorRun(1, 'forward', 100)
time.sleep(2)
print("backward 2 s")
Motor.MotorRun(0, 'backward', 100)
Motor.MotorRun(1, 'backward', 100)
time.sleep(2)
print("stop")
Motor.MotorStop(0)
Motor.MotorStop(1)
2. The library
#!/usr/bin/python3
# from grippy
import time
import math
import smbus
# ============================================================================
# PCA9685 16-Channel PWM Servo Driver
# ============================================================================
class PCA9685:
# Registers/etc.
__SUBADR1 = 0x02
__SUBADR2 = 0x03
__SUBADR3 = 0x04
__MODE1 = 0x00
__PRESCALE = 0xFE
__LED0_ON_L = 0x06
__LED0_ON_H = 0x07
__LED0_OFF_L = 0x08
__LED0_OFF_H = 0x09
__ALLLED_ON_L = 0xFA
__ALLLED_ON_H = 0xFB
__ALLLED_OFF_L = 0xFC
__ALLLED_OFF_H = 0xFD
def __init__(self, address, debug=False):
self.bus = smbus.SMBus(1)
self.address = address
self.debug = debug
if (self.debug):
print("Reseting PCA9685")
self.write(self.__MODE1, 0x00)
def write(self, reg, value):
"Writes an 8-bit value to the specified register/address"
self.bus.write_byte_data(self.address, reg, value)
if (self.debug):
print("I2C: Write 0x%02X to register 0x%02X" % (value, reg))
def read(self, reg):
"Read an unsigned byte from the I2C device"
result = self.bus.read_byte_data(self.address, reg)
if (self.debug):
print("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % (self.address, result & 0xFF, reg))
return result
def setPWMFreq(self, freq):
"Sets the PWM frequency"
prescaleval = 25000000.0 # 25MHz
prescaleval = prescaleval / 4096.0 # 12-bit
prescaleval = prescaleval / float(freq)
prescaleval = prescaleval - 1.0
if (self.debug):
print("Setting PWM frequency to %d Hz" % freq)
print("Estimated pre-scale: %d" % prescaleval)
prescale = math.floor(prescaleval + 0.5)
if (self.debug):
print("Final pre-scale: %d" % prescale)
oldmode = self.read(self.__MODE1);
newmode = (oldmode & 0x7F) | 0x10 # sleep
self.write(self.__MODE1, newmode) # go to sleep
self.write(self.__PRESCALE, int(math.floor(prescale)))
self.write(self.__MODE1, oldmode)
time.sleep(0.005)
self.write(self.__MODE1, oldmode | 0x80)
def setPWM(self, channel, on, off):
"Sets a single PWM channel"
self.write(self.__LED0_ON_L + 4*channel, on & 0xFF)
self.write(self.__LED0_ON_H + 4*channel, 0xff & (on >> 8))
self.write(self.__LED0_OFF_L + 4*channel, off & 0xFF)
self.write(self.__LED0_OFF_H + 4*channel, 0xff & (off >> 8))
if (self.debug):
print("channel: %d LED_ON: %d LED_OFF: %d" % (channel,on,off))
def setDutycycle(self, channel, pulse):
self.setPWM(channel, 0, int(pulse * int(4096 / 100)))
def setLevel(self, channel, value):
if (value == 1):
self.setPWM(channel, 0, 4095)
else:
self.setPWM(channel, 0, 0)
# pwm = PCA9685(0x5f, debug=False)
# pwm.setPWMFreq(50)
# pwm.setDutycycle(0,100)
# pwm.setLevel(1,0)
# pwm.setLevel(2,1)
That should get you started...
If on your BeagleY-AI you seem to notice some error due to specific commands within the source code files, adjust at will!
Also, this command will help you with i2c-tools with i2cdetect.
i2cdetect -y -r 1
That should you the correct addresses of your Hat chips.
Seth
I made a short in case the disbelief kicks in!
Comments