-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2e43acd
commit 5c37784
Showing
4 changed files
with
520 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import time | ||
import math | ||
from pimoroni_yukon import Yukon | ||
from pimoroni_yukon.modules import SerialServoModule | ||
from pimoroni_yukon.protocols.lx_servos import * | ||
|
||
SPEED = 5 # The speed that the servos will cycle at | ||
UPDATES = 5 # How many times to update LEDs and Servos per second | ||
SERVO_EXTENT = 80.0 # How far from zero to move the servos | ||
|
||
# Create a Yukon object to begin using the board | ||
yukon = Yukon(logging_level=1) | ||
|
||
# List to store the modules | ||
servo_modules = [] | ||
|
||
try: | ||
# Create a Quad Servo Direct class for each populated module slot | ||
for slot in yukon.find_slots_with_module(SerialServoModule): | ||
serial_servo = SerialServoModule() | ||
yukon.register_with_slot(serial_servo, slot) | ||
servo_modules.append(serial_servo) | ||
|
||
# Initialise Yukon's registered modules | ||
yukon.initialise_modules(allow_unregistered=True) | ||
|
||
# Turn on the module power | ||
yukon.enable_main_output() | ||
|
||
time.sleep(1) | ||
|
||
old_id = 1 | ||
new_id = 11 | ||
|
||
servo_ids = [1, 2, 3] | ||
|
||
#for module in servo_modules: | ||
# module.send_on_data() | ||
# SerialServoSetID(module.uart, old_id, new_id) | ||
|
||
# for module in servo_modules: | ||
# module.send_on_data() | ||
# SerialServoSetMode(module.uart, 2, 1, 1000) | ||
|
||
offset = 0 | ||
toggle = False | ||
while not yukon.is_boot_pressed(): | ||
offset += SPEED / 1000.0 | ||
|
||
# Update all the Servos | ||
for module in servo_modules: | ||
for sid in servo_ids: | ||
angle = SerialServoReadPosition(module.uart, module.send_on_data, module.receive_on_data, sid) | ||
angle = ((angle - 500) / 360) * 90 | ||
voltage = SerialServoReadVin(module.uart, module.send_on_data, module.receive_on_data, sid) | ||
voltage = (voltage / 1000) | ||
temp = SerialServoReadTemperature(module.uart, module.send_on_data, module.receive_on_data, sid) | ||
print(f"ID: {sid}, Angle: {angle}, Vin: {voltage}, Temp: {temp}", end=", ") | ||
print() | ||
|
||
if yukon.is_pressed('A'): | ||
SerialServoMove(module.uart, 1, 500, 1000) | ||
|
||
if yukon.is_pressed('B'): | ||
SerialServoMove(module.uart, 1, 800, 1000) | ||
|
||
toggle = not toggle | ||
if toggle: | ||
SerialServoActivateLED(module.uart, 1) | ||
else: | ||
SerialServoDeactivateLED(module.uart, 1) | ||
|
||
yukon.monitored_sleep(1.0 / UPDATES) | ||
|
||
finally: | ||
# Put the board back into a safe state, regardless of how the program may have ended | ||
yukon.reset() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# SPDX-FileCopyrightText: 2023 Christopher Parrott for Pimoroni Ltd | ||
# | ||
# SPDX-License-Identifier: MIT | ||
|
||
from .common import YukonModule, ADC_FLOAT, LOW, HIGH | ||
from busio import UART | ||
from digitalio import DigitalInOut | ||
from collections import OrderedDict | ||
from pimoroni_yukon.errors import OverTemperatureError | ||
|
||
|
||
class SerialServoModule(YukonModule): | ||
NAME = "Serial Bus Servo" | ||
DEFAULT_BAUDRATE = 115200 | ||
TEMPERATURE_THRESHOLD = 50.0 | ||
|
||
# | ADC1 | SLOW1 | SLOW2 | SLOW3 | Module | Condition (if any) | | ||
# |-------|-------|-------|-------|----------------------|-----------------------------| | ||
# | FLOAT | 1 | 0 | 0 | Serial Servo | | | ||
@staticmethod | ||
def is_module(adc_level, slow1, slow2, slow3): | ||
return adc_level is ADC_FLOAT and slow1 is HIGH and slow2 is LOW and slow3 is LOW | ||
|
||
def __init__(self, baudrate=DEFAULT_BAUDRATE): | ||
super().__init__() | ||
|
||
self.__baudrate = baudrate | ||
|
||
def initialise(self, slot, adc1_func, adc2_func): | ||
try: | ||
# Create the serial object | ||
self.uart = UART(slot.FAST1, slot.FAST2, baudrate=self.__baudrate) | ||
except ValueError as e: | ||
raise type(e)("UART perhiperal already in use. Check that a module in another slot does not share the same UART perhiperal") from None | ||
|
||
# Create the direction pin objects | ||
self.__tx_to_data_en = DigitalInOut(slot.FAST3) | ||
self.__data_to_rx_en = DigitalInOut(slot.FAST4) | ||
|
||
# Pass the slot and adc functions up to the parent now that module specific initialisation has finished | ||
super().initialise(slot, adc1_func, adc2_func) | ||
|
||
def reset(self): | ||
self.uart.reset_input_buffer() | ||
|
||
self.__tx_to_data_en.switch_to_output(True) # Active low | ||
self.__data_to_rx_en.switch_to_output(True) # Active low | ||
|
||
def send_on_data(self): | ||
self.__data_to_rx_en.value = True | ||
self.__tx_to_data_en.value = False | ||
|
||
def receive_on_data(self): | ||
self.__tx_to_data_en.value = True | ||
self.__data_to_rx_en.value = False | ||
|
||
def read_temperature(self): | ||
return self.__read_adc2_as_temp() | ||
|
||
def monitor(self): | ||
temperature = self.read_temperature() | ||
if temperature > self.TEMPERATURE_THRESHOLD: | ||
raise OverTemperatureError(self.__message_header() + f"Temperature of {temperature}°C exceeded the limit of {self.TEMPERATURE_THRESHOLD}°C! Turning off output") | ||
|
||
# Run some user action based on the latest readings | ||
if self.__monitor_action_callback is not None: | ||
self.__monitor_action_callback(temperature) | ||
|
||
self.__max_temperature = max(temperature, self.__max_temperature) | ||
self.__min_temperature = min(temperature, self.__min_temperature) | ||
self.__avg_temperature += temperature | ||
|
||
self.__count_avg += 1 | ||
|
||
def get_readings(self): | ||
return OrderedDict({ | ||
"T_max": self.__max_temperature, | ||
"T_min": self.__min_temperature, | ||
"T_avg": self.__avg_temperature | ||
}) | ||
|
||
def process_readings(self): | ||
if self.__count_avg > 0: | ||
self.__avg_temperature /= self.__count_avg | ||
|
||
def clear_readings(self): | ||
self.__max_temperature = float('-inf') | ||
self.__min_temperature = float('inf') | ||
self.__avg_temperature = 0 | ||
|
||
self.__count_avg = 0 |
Oops, something went wrong.