Skip to content

Commit

Permalink
Added dual motor examples, and fixed some things
Browse files Browse the repository at this point in the history
  • Loading branch information
ZodiusInfuser committed Oct 13, 2023
1 parent 04b5863 commit 80d694a
Show file tree
Hide file tree
Showing 9 changed files with 297 additions and 94 deletions.
88 changes: 88 additions & 0 deletions examples/modules/dual_motor/all_motors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import math
from pimoroni_yukon import Yukon
from pimoroni_yukon.modules import DualMotorModule
from pimoroni_yukon.timing import ticks_ms, ticks_add
from pimoroni_yukon.logging import LOG_WARN
from motor import MotorCluster

"""
How to drive up to 12 motors from a set of Dual Motor Modules connected to Slots, using a MotorCluster.
A wave pattern will be played on the attached motors.
The MotorCluster controls the whole set of motors using PIO.
It also staggers the updates of each motor to reduce peak current draw.
"""

# Constants
SPEED = 0.005 # How much to advance the motor phase offset by each update
UPDATES = 50 # How many times to update the motors per second
SPEED_EXTENT = 1.0 # How far from zero to drive the motors
CURRENT_LIMIT = 0.5 # The maximum current (in amps) the motors will be driven with
CLUSTER_PIO = 0 # The PIO system to use (0 or 1) to drive the motor cluster
CLUSTER_SM = 0 # The State Machines (SM) to use to drive the motor cluster

# Variables
yukon = Yukon(logging_level=LOG_WARN) # Create a new Yukon object, with its logging level lowered
modules = [] # A list to store QuadServo module objects created later
phase_offset = 0 # The offset used to animate the motors


# Function to get a motor speed from its index
def speed_from_index(index, offset=0.0):
phase = ((index / DualMotorModule.NUM_MOTORS) + offset) * math.pi * 2
speed = math.sin(phase) * SPEED_EXTENT
return speed


# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt)
try:
# Find out which slots of Yukon have DualMotorModule attached
for slot in yukon.find_slots_with(DualMotorModule):
module = DualMotorModule(init_motors=False) # Create a DualMotorModule object
yukon.register_with_slot(module, slot) # Register the DualMotorModule object with the slot
modules.append(module) # Add the object to the module list

# Record the number of motors that will be driven
NUM_MOTORS = len(modules) * DualMotorModule.NUM_MOTORS
print(f"Up to {NUM_MOTORS} motors available")

yukon.verify_and_initialise() # Verify that DualMotorModules are attached to Yukon, and initialise them

# Create a MotorCluster object, with a list of motor pin pairs to control.
# The pin list is created using nested list comprehension
motors = MotorCluster(CLUSTER_PIO, CLUSTER_SM,
pins=[pin for module in modules for pin in module.motor_pins])

yukon.enable_main_output() # Turn on power to the module slots

for module in modules:
module.current_limit(CURRENT_LIMIT) # Change the current limit (in amps) of the motor driver
module.enable() # Enable the motor driver on the DualMotorModule

current_time = ticks_ms() # Record the start time of the program loop

# Loop until the BOOT/USER button is pressed
while not yukon.is_boot_pressed():

# Give all the motors new speeds
for current_motor in range(motors.count()):
speed = speed_from_index(current_motor, phase_offset)
motors.speed(current_motor, speed)

# Advance the phase offset, wrapping if it exceeds 1.0
phase_offset += SPEED
if phase_offset >= 1.0:
phase_offset -= 1.0

print(f"Phase = {phase_offset}")

# Advance the current time by a number of seconds
current_time = ticks_add(current_time, int(1000 / UPDATES))

# Monitor sensors until the current time is reached, recording the min, max, and average for each
# This approach accounts for the updating of the rainbows taking a non-zero amount of time to complete
yukon.monitor_until_ms(current_time)

finally:
# Put the board back into a safe state, regardless of how the program may have ended
yukon.reset()
81 changes: 81 additions & 0 deletions examples/modules/dual_motor/multiple_motors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import math
from pimoroni_yukon import Yukon
from pimoroni_yukon.modules import DualMotorModule
from pimoroni_yukon.timing import ticks_ms, ticks_add
from pimoroni_yukon.logging import LOG_WARN

"""
How to drive up to 8 motors from a set of Dual Motor Module connected to Slots.
A wave pattern will be played on the attached motors.
To use more motors, look at the all_motors.py example.
"""

# Constants
SPEED = 0.005 # How much to advance the motor phase offset by each update
UPDATES = 50 # How many times to update the motors per second
SPEED_EXTENT = 1.0 # How far from zero to drive the motors
CURRENT_LIMIT = 0.5 # The maximum current (in amps) the motors will be driven with

# Variables
yukon = Yukon(logging_level=LOG_WARN) # Create a new Yukon object, with its logging level lowered
modules = [] # A list to store DualMotorModule objects created later
phase_offset = 0 # The offset used to animate the motors


# Function to get a motor speed from its index
def speed_from_index(index, offset=0.0):
phase = ((index / DualMotorModule.NUM_MOTORS) + offset) * math.pi * 2
speed = math.sin(phase) * SPEED_EXTENT
return speed


# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt)
try:
# Find out which slots of Yukon have DualMotorModule attached
for slot in yukon.find_slots_with(DualMotorModule):
module = DualMotorModule() # Create a DualMotorModule object
yukon.register_with_slot(module, slot) # Register the DualMotorModule object with the slot
modules.append(module) # Add the object to the module list

# Record the number of motors that will be driven
NUM_MOTORS = len(modules) * DualMotorModule.NUM_MOTORS
print(f"Up to {NUM_MOTORS} motors available")

yukon.verify_and_initialise() # Verify that DualMotorModules are attached to Yukon, and initialise them
yukon.enable_main_output() # Turn on power to the module slots

for module in modules:
module.current_limit(CURRENT_LIMIT) # Change the current limit (in amps) of the motor driver
module.enable() # Enable the motor driver on the DualMotorModule

current_time = ticks_ms() # Record the start time of the program loop

# Loop until the BOOT/USER button is pressed
while not yukon.is_boot_pressed():

# Give all the motors new speeds
current_motor = 0
for module in modules:
for motor in module.motors:
speed = speed_from_index(current_motor, phase_offset)
motor.speed(speed)
current_motor += 1

# Advance the phase offset, wrapping if it exceeds 1.0
phase_offset += SPEED
if phase_offset >= 1.0:
phase_offset -= 1.0

print(f"Phase = {phase_offset}")

# Advance the current time by a number of seconds
current_time = ticks_add(current_time, int(1000 / UPDATES))

# Monitor sensors until the current time is reached, recording the min, max, and average for each
# This approach accounts for the updating of the rainbows taking a non-zero amount of time to complete
yukon.monitor_until_ms(current_time)

finally:
# Put the board back into a safe state, regardless of how the program may have ended
yukon.reset()
69 changes: 69 additions & 0 deletions examples/modules/dual_motor/two_motors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import math
from pimoroni_yukon import Yukon
from pimoroni_yukon import SLOT1 as SLOT
from pimoroni_yukon.modules import DualMotorModule
from pimoroni_yukon.timing import ticks_ms, ticks_add
from pimoroni_yukon.logging import LOG_WARN

"""
How to drive up to 2 motors from a Dual Motor Module connected to Slot1.
A wave pattern will be played on the attached motors.
"""

# Constants
SPEED = 0.005 # How much to advance the motor phase offset by each update
UPDATES = 50 # How many times to update the motors per second
SPEED_EXTENT = 1.0 # How far from zero to drive the motors
CURRENT_LIMIT = 0.5 # The maximum current (in amps) the motors will be driven with

# Variables
yukon = Yukon(logging_level=LOG_WARN) # Create a new Yukon object, with its logging level lowered
module = DualMotorModule() # Create a DualMotorModule object
phase_offset = 0 # The offset used to animate the motors


# Function to get a motor speed from its index
def speed_from_index(index, offset=0.0):
phase = ((index / DualMotorModule.NUM_MOTORS) + offset) * math.pi * 2
speed = math.sin(phase) * SPEED_EXTENT
return speed


# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt)
try:
yukon.register_with_slot(module, SLOT) # Register the DualMotorModule object with the slot
yukon.verify_and_initialise() # Verify that a DualMotorModule is attached to Yukon, and initialise it
yukon.enable_main_output() # Turn on power to the module slots

module.current_limit(CURRENT_LIMIT) # Change the current limit (in amps) of the motor driver
module.enable() # Enable the motor driver on the DualMotorModule

current_time = ticks_ms() # Record the start time of the program loop

# Loop until the BOOT/USER button is pressed
while not yukon.is_boot_pressed():

# Give all the motors new speeds
current_motor = 0
for motor in module.motors:
speed = speed_from_index(current_motor, phase_offset)
motor.speed(speed)
current_motor += 1

# Advance the phase offset, wrapping if it exceeds 1.0
phase_offset += SPEED
if phase_offset >= 1.0:
phase_offset -= 1.0

print(f"Phase = {phase_offset}")

# Advance the current time by a number of seconds
current_time = ticks_add(current_time, int(1000 / UPDATES))

# Monitor sensors until the current time is reached, recording the min, max, and average for each
# This approach accounts for the updating of the rainbows taking a non-zero amount of time to complete
yukon.monitor_until_ms(current_time)

finally:
# Put the board back into a safe state, regardless of how the program may have ended
yukon.reset()
12 changes: 6 additions & 6 deletions examples/modules/quad_servo/all_servos.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ def angle_from_index(index, offset=0.0):
try:
# Find out which slots of Yukon have QuadServoDirectModules attached
for slot in yukon.find_slots_with(QuadServoDirectModule):
module = QuadServoDirectModule(init_servos=False) # Create a QuadServoDirectModule object, but do not have it create Servo objects
yukon.register_with_slot(module, slot) # Register the QuadServoDirectModule object with the slot
modules.append(module) # Add the object to the module list
module = QuadServoDirectModule(init_servos=False) # Create a QuadServoDirectModule object, but do not have it create Servo objects
yukon.register_with_slot(module, slot) # Register the QuadServoDirectModule object with the slot
modules.append(module) # Add the object to the module list

# Find out which slots of Yukon have QuadServoRegModule attached
for slot in yukon.find_slots_with(QuadServoRegModule):
module = QuadServoRegModule(init_servos=False) # Create a QuadServoRegModule object, but do not have it create Servo objects
yukon.register_with_slot(module, slot) # Register the QuadServoDirectModule object with the slot
modules.append(module) # Add the object to the module list
module = QuadServoRegModule(init_servos=False) # Create a QuadServoRegModule object, but do not have it create Servo objects
yukon.register_with_slot(module, slot) # Register the QuadServoDirectModule object with the slot
modules.append(module) # Add the object to the module list

# Record the number of servos that will be driven
NUM_SERVOS = len(modules) * QuadServoDirectModule.NUM_SERVOS
Expand Down
56 changes: 0 additions & 56 deletions examples/yukon_adaptive_motor.py

This file was deleted.

Loading

0 comments on commit 80d694a

Please sign in to comment.