Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions XRPLib/board.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ class Board:

_DEFAULT_BOARD_INSTANCE = None

# Board identity. The one place a machine name is matched; everything else compares
# against these constants (see get_type).
XRP = 0
BETA = 1
NANO = 2
_type = None

@classmethod
def get_type(cls) -> int:
"""
Identify which XRP board this code is running on.

:return: One of Board.XRP, Board.BETA, or Board.NANO
:rtype: int
"""
if cls._type is None:
machine = sys.implementation._machine
cls._type = cls.NANO if "NanoXRP" in machine else cls.BETA if "Beta" in machine else cls.XRP
return cls._type

@classmethod
def get_default_board(cls):
"""
Expand Down Expand Up @@ -47,9 +67,9 @@ def are_motors_powered(self) -> bool:
:return: Returns true if the batteries are connected and powering the motors, false otherwise
:rytpe: bool
"""
if "NanoXRP" in sys.implementation._machine:
if Board.get_type() == Board.NANO:
return True

threshold_voltage = 4.272
return self.get_battery_voltage() > threshold_voltage

Expand Down Expand Up @@ -141,7 +161,7 @@ def get_battery_voltage(self, vin_pin="BOARD_VIN_MEASURE") -> float:
:rtype: float
"""

if "NanoXRP" in sys.implementation._machine:
if Board.get_type() == Board.NANO:
# VIN pin on NanoXRP is also used for RM2.
self.on_switch = ADC(Pin(vin_pin))

Expand Down
5 changes: 3 additions & 2 deletions XRPLib/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .rangefinder import Rangefinder
from .imu import IMU
from .reflectance import Reflectance
from .board import Board
from .puppet import Puppet, VAR_TYPE_INT, VAR_TYPE_FLOAT, PERM_READ_ONLY

from machine import Timer, ADC, Pin
Expand Down Expand Up @@ -82,7 +83,7 @@ def __init__(self):
self.imu = IMU.get_default_imu()
self.rangefinder = Rangefinder.get_default_rangefinder()
self.reflectance = Reflectance.get_default_reflectance()
self.VoltageADC = ADC(Pin('BOARD_VIN_MEASURE'))
self.board = Board.get_default_board()
#self.CurrLADC = ADC(Pin('ML_CUR'))
#self.CurrRADC = ADC(Pin('MR_CUR'))
#self.Curr3ADC = ADC(Pin('M3_CUR'))
Expand Down Expand Up @@ -188,7 +189,7 @@ def _dashboard_update(self):
self._puppet.set_variable('$reflectance.right', self.reflectance.get_right())

# Voltage
voltage = self.VoltageADC.read_u16() / (1024*64/14)
voltage = self.board.get_battery_voltage()
self._puppet.set_variable('$voltage', voltage)

def start(self, rate_hz=3):
Expand Down
24 changes: 7 additions & 17 deletions XRPLib/differential_drive.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from .timeout import Timeout
import time
import math
from sys import implementation

class DifferentialDrive:

Expand Down Expand Up @@ -38,9 +37,9 @@ def __init__(self, left_motor: EncodedMotor, right_motor: EncodedMotor, imu: IMU
:type rightMotor: EncodedMotor
:param imu: The IMU of the robot. If None, the robot will not use the IMU for turning or maintaining heading.
:type imu: IMU
:param wheelDiam: The diameter of the wheels in inches. Defaults to 6 cm.
:param wheelDiam: The diameter of the wheels in cm.
:type wheelDiam: float
:param wheelTrack: The distance between the wheels in inches. Defaults to 15.5 cm.
:param wheelTrack: The distance between the wheels in cm.
:type wheelTrack: float
"""

Expand All @@ -53,27 +52,18 @@ def __init__(self, left_motor: EncodedMotor, right_motor: EncodedMotor, imu: IMU
# Resolve hardware defaults when the caller leaves the arg at its 0.0 sentinel;
# honor any explicit non-zero value that is passed in.
if wheel_diam == 0.0:
if "NanoXRP" in implementation._machine:
self.wheel_diam = 3.46
else:
self.wheel_diam = 6.0
self.wheel_diam = 3.46 if Board.get_type() == Board.NANO else 6.0
else:
self.wheel_diam = wheel_diam

if wheel_track == 0.0:
if "NanoXRP" in implementation._machine:
self.wheel_track = 7.8
else:
self.wheel_track = 15.5
self.wheel_track = 7.8 if Board.get_type() == Board.NANO else 15.5
else:
self.wheel_track = wheel_track

# Effort is raw PWM duty, so torque scales with pack voltage. Gains are tuned against
# nominal_voltage and voltage_scale corrects the duty for the pack actually installed.
if "NanoXRP" in implementation._machine:
self.nominal_voltage = 4.2
else:
self.nominal_voltage = 6.0
self.nominal_voltage = 4.2 if Board.get_type() == Board.NANO else 6.0

self.voltage_scale = 1.0
self.update_voltage_compensation()
Expand Down Expand Up @@ -220,9 +210,9 @@ def _move(self, distance_target: float, heading_target: float, max_effort: float
Shared translation/rotation controller for straight() and turn().
"""

if "NanoXRP" in implementation._machine:
if Board.get_type() == Board.NANO:
if min_effort is None:
min_effort = 0.10
min_effort = 0.10

if distance_controller is None:
distance_controller = PID(
Expand Down
9 changes: 3 additions & 6 deletions XRPLib/encoded_motor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from machine import Timer, Pin
from .controller import Controller
from .pid import PID
from sys import implementation
from .board import Board

class EncodedMotor:

Expand All @@ -25,10 +25,7 @@ def get_default_encoded_motor(cls, index:int = 1):
:type index: int
"""

if "Beta" in implementation._machine:
MotorImplementation = SinglePWMMotor
else:
MotorImplementation = DualPWMMotor
MotorImplementation = SinglePWMMotor if Board.get_type() == Board.BETA else DualPWMMotor

if index == 1:
if cls._DEFAULT_LEFT_MOTOR_INSTANCE is None:
Expand Down Expand Up @@ -70,7 +67,7 @@ def __init__(self, motor, encoder: Encoder):
self.brake_at_zero = False

self.target_speed = None
if "NanoXRP" in implementation._machine:
if Board.get_type() == Board.NANO:
self.DEFAULT_SPEED_CONTROLLER = PID(
kp=0.015,
ki=0.06,
Expand Down
4 changes: 2 additions & 2 deletions XRPLib/encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import machine
import rp2
import time
from sys import implementation
from .board import Board
import re

class Encoder:
if "NanoXRP" in implementation._machine:
if Board.get_type() == Board.NANO:
_gear_ratio = (68/1)
_counts_per_motor_shaft_revolution = 12
else:
Expand Down
5 changes: 3 additions & 2 deletions XRPLib/imu.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# Import wrapped in a try/except so that autodoc generation can process properly
pass
from machine import I2C, Pin, Timer, disable_irq, enable_irq
from sys import implementation
from .board import Board
import time, math

class IMU():
Expand All @@ -30,7 +30,8 @@ def get_default_imu(cls):
return cls._DEFAULT_IMU_INSTANCE

def __init__(self, scl_pin: int|str = "I2C_SCL_1", sda_pin: int|str = "I2C_SDA_1", addr=LSM_ADDR_PRIMARY):
self._is_nanoxrp = "NanoXRP" in implementation._machine
# Cached once at construction so the hard-IRQ update handler never calls get_type().
self._is_nanoxrp = Board.get_type() == Board.NANO

# I2C values
self.i2c = I2C(id=1, scl=Pin(scl_pin), sda=Pin(sda_pin), freq=400000)
Expand Down
7 changes: 2 additions & 5 deletions XRPLib/motor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from machine import Pin, PWM
from sys import implementation
from .board import Board

class SinglePWMMotor:

Expand Down Expand Up @@ -57,10 +57,7 @@ class DualPWMMotor:

def __init__(self, in1_pwm_forward: int|str, in2_pwm_backward: int|str, flip_dir:bool=False):

if "NanoXRP" in implementation._machine:
self.flip_dir = not flip_dir
else:
self.flip_dir = flip_dir
self.flip_dir = (not flip_dir) if Board.get_type() == Board.NANO else flip_dir

self._MAX_PWM = 65535 # Motor holds when actually at full power

Expand Down