Files
mixly3-server/mixly/boards/default/micropython/build/lib/pe_g1.py

127 lines
4.1 KiB
Python

"""
Micropython library for
PE_G1 (Motor*5*2 & Servo*4)
MDB (Motor*4*2 & Servo*6)
===============================
@dahanzimin From the Mixly Team
"""
from time import sleep_ms
from micropython import const
_PE_GX_ADDRESS = const(0x25)
_PE_GX_ID = const(0x00)
_PE_GX_VBAT = const(0x01)
_PE_GX_MOTOR = const(0x03)
class PE_G1:
def __init__(self, i2c_bus, addr=_PE_GX_ADDRESS):
self._i2c = i2c_bus
self._addr = addr
sleep_ms(500)
if self._rreg(_PE_GX_ID) == 0x25:
self._PE_GX_SERVO = 0x0D
self._type = 1 #PE_G1
elif self._rreg(_PE_GX_ID) == 0x26:
self._PE_GX_SERVO = 0x0B
self._type = 2 #MDB
else:
raise AttributeError("Cannot find a PE_G1 or MDB")
self.reset()
def _wreg(self, reg, val):
'''Write memory address'''
try:
self._i2c.writeto_mem(self._addr, reg, val.to_bytes(1, 'little'))
except:
return 0
def _rreg(self, reg, nbytes=1):
'''Read memory address'''
try:
self._i2c.writeto(self._addr, reg.to_bytes(1, 'little'))
return self._i2c.readfrom(self._addr, nbytes)[0] if nbytes <= 1 else self._i2c.readfrom(self._addr, nbytes)
except:
return 0
def reset(self):
"""Reset all registers to default state"""
if self._type == 1:
self._i2c.writeto_mem(self._addr, _PE_GX_MOTOR, bytes(18))
if self._type == 2:
self._i2c.writeto_mem(self._addr, _PE_GX_MOTOR, bytes(20))
def read_bat(self, ratio=1):
'''Read battery power'''
vbat = self._rreg(_PE_GX_VBAT) << 2 | self._rreg(_PE_GX_VBAT+1) >> 6
if self._type == 1:
return round(vbat * ratio * 0.00968, 2)
if self._type == 2:
return round(vbat * ratio * 0.01398, 2)
def m_pwm(self, index, duty=None):
"""Motor PWM duty cycle data register"""
if self._type == 1: # Motor*5*2
if not 0 <= index <= 9:
raise ValueError("Motor port must be a number in the range: 0~4")
if self._type == 2: # Motor*4*2
if not 0 <= index <= 7:
raise ValueError("Motor port must be a number in the range: 0~3")
if duty is None:
return self._rreg(_PE_GX_MOTOR + index)
else:
if not 0 <= duty <= 255:
raise ValueError("Duty must be a number in the range: 0~255")
self._wreg(_PE_GX_MOTOR + index, duty)
def s_pwm(self, index, duty=None):
"""Servo PWM duty cycle data register"""
if self._type == 1: # Servo*4
if not 0 <= index <= 3:
raise ValueError("Servo port must be a number in the range: 0~3")
if self._type == 2: # Servo*6
if not 0 <= index <= 5:
raise ValueError("Servo port must be a number in the range: 0~5")
if duty is None:
return self._rreg(self._PE_GX_SERVO + index * 2) << 8 | self._rreg(self._PE_GX_SERVO + index * 2 + 1)
else:
if not 0 <= duty <= 4095:
raise ValueError("Duty must be a number in the range: 0~4095")
self._wreg(self._PE_GX_SERVO + index * 2,duty >> 8)
self._wreg(self._PE_GX_SERVO + index * 2 + 1,duty & 0xff)
def motor(self, index, action="NC", speed=0):
if not 0 <= speed <= 100:
raise ValueError("Speed parameters must be a number in the range: 0~100")
if action == "N":
self.m_pwm(index * 2, 0)
self.m_pwm(index * 2 + 1, 0)
elif action == "P":
self.m_pwm(index * 2, 255)
self.m_pwm(index * 2 + 1, 255)
elif action == "CW":
self.m_pwm(index * 2, 0)
self.m_pwm(index * 2 + 1, speed * 255 // 100)
elif action == "CCW":
self.m_pwm(index * 2, speed * 255 // 100)
self.m_pwm(index * 2 + 1, 0)
elif action == "NC":
return round(self.m_pwm(index * 2) * 100 / 255), round(self.m_pwm(index * 2 + 1) * 100 / 255)
else:
raise ValueError('Invalid input, valid are "N","P","CW","CCW"')
def servo180(self, index, angle=None):
if angle is None:
return round((self.s_pwm(index) - 102.375) * 180 / 409.5)
else:
if not 0 <= angle <= 180:
raise ValueError("Servo(180) angle must be a number in the range: 0~180")
self.s_pwm(index,round(102.375 + 409.5 / 180 * angle))
def servo360(self, index, speed=None):
if speed is None:
return round((self.s_pwm(index) - 102.375) * 200 / 409.5 - 100)
else:
if not -100 <= speed <= 100:
raise ValueError("Servo(360) speed must be a number in the range: -100~100")
self.s_pwm(index,round(102.375 + 409.5 / 200 * (speed + 100)))