Warning:

To protect the digital assets of creators and enhance system security and stability, the CyberBrick Multi-Function Core Board does not support firmware flashing with any third-party tools! If you need to restore the Multi-Function Core Board to its factory state, please wait for the official recovery tool to be released by CyberBrick. If you proceed to flash the firmware using third-party tools, the firmware of the Multi-Function Core Board will be permanently damaged and cannot be recovered. CyberBrick will not be responsible for any consequences resulting from such operations.

This documentation is adapted from the official MicroPython project. The CyberBrick team has extended the source code with custom interfaces and features to our hardware and application needs.

In addition to these enhancements, certain built-in MicroPython interfaces have been intentionally disabled to protect the system's integrity, and ensure the overall security and reliability of the device. This also facilitates content protection for creators' intellectual property, where applicable.

Portions of the content are derived from the official MicroPython documentation and have been included here under its open-source license to provide users with a consistent and enriched development experience tailored to the CyberBrick platform.

Source code for bbl.motors

# -*-coding:utf-8-*-
#
# The CyberBrick Codebase License, see the file LICENSE for details.
#
# Copyright (c) 2025 MakerWorld
#

from machine import Pin

MOTOR1_CHANNEL1 = 4
MOTOR1_CHANNEL2 = 5
MOTOR2_CHANNEL1 = 6
MOTOR2_CHANNEL2 = 7

PERIOD = 20


[docs] class MotorsController: """ A singleton class to control two DC motors using PWM signals. This class provides a simple interface to control the speed and direction of two DC motors. It initializes the PWM pins for each motor channel and provides methods to set the motor speed, stop the motors, and configure the forward/reverse speed and offset parameters for each motor. Example: >>> motors = MotorsController() >>> # Set motor 1 to forward at half speed >>> motors.set_speed(1, 1024) >>> # Set motor 2 to reverse at quarter speed >>> motors.set_speed(2, -512) >>> # Stop motor 1 >>> motors.stop(1) """ _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(MotorsController, cls).__new__(cls) return cls._instance
[docs] def __init__(self): """ Initializes the MotorsController instance. """ # Ensure __init__ only initializes once if hasattr(self, '_initialized') and self._initialized: return self._initialized = True self.motor1_1 = Pin(MOTOR1_CHANNEL1, Pin.OUT) self.motor1_2 = Pin(MOTOR1_CHANNEL2, Pin.OUT) self.motor2_1 = Pin(MOTOR2_CHANNEL1, Pin.OUT) self.motor2_2 = Pin(MOTOR2_CHANNEL2, Pin.OUT) self.motor1_1_duty = 0 self.motor1_2_duty = 0 self.motor2_1_duty = 0 self.motor2_2_duty = 0 self.motor_params = { 1: {'forward_speed': 100, 'reverse_speed': 100, 'offset': 0}, 2: {'forward_speed': 100, 'reverse_speed': 100, 'offset': 0} } self.period_cnt = 0 self.motor1_1.on() self.motor1_2.on() self.motor2_1.on() self.motor2_2.on()
[docs] def motors_period_cb(self): """ Updates the duty cycles of the motors based on the current motor duty. This method simulates PWM by turning the motors on and off in intervals, adjusting the duty cycles based on the PWM timing signal. This method should be called periodically to update motor speed. Example: >>> motors.motors_period_cb() # Periodically update motor speed """ self.period_cnt = (self.period_cnt + 1) % PERIOD if self.motor1_1_duty == 0 and self.motor1_2_duty == 0: self.motor1_1.on() self.motor1_2.on() else: if self.period_cnt >= self.motor1_1_duty: self.motor1_1.off() else: self.motor1_1.on() if self.period_cnt >= self.motor1_2_duty: self.motor1_2.off() else: self.motor1_2.on() if self.motor2_1_duty == 0 and self.motor2_2_duty == 0: self.motor2_1.on() self.motor2_2.on() else: if self.period_cnt >= self.motor2_1_duty: self.motor2_1.off() else: self.motor2_1.on() if self.period_cnt >= self.motor2_2_duty: self.motor2_2.off() else: self.motor2_2.on()
[docs] def set_speed(self, motor_idx, speed): """ Sets the speed of a motor. This method sets the speed of a specified motor by adjusting the duty \ cycles of its channels. The speed is controlled using a simulated PWM (Pulse Width Modulation)\ signal, where the duty cycle determines the effective speed of the motor. The speed value can range from -2048 to 2048, where \ positive values indicate forward movement, \ negative values indicate reverse movement, and zero \ indicates no movement. Args: motor_idx (int): Index of the motor (1 or 2). speed (int): Speed value to set for the motor,\ ranging from -2048 to 2048. Returns: None Example: >>> # Set motor 1 to move forward at half speed >>> set_speed(1, 1024) >>> # Set motor 2 to move reverse at a quarter speed >>> set_speed(2, -512) """ if motor_idx == 1: self.motor1_1_duty, self.motor1_2_duty = self._speed_handler(speed) elif motor_idx == 2: self.motor2_1_duty, self.motor2_2_duty = self._speed_handler(speed) else: print("[motors]Invalid motor index. Must be between 1 and 2.")
[docs] def stop(self, motor_idx): """ Stops a motor by setting its duty cycles to 0. Args: motor_idx (int): Index of the motor (1 or 2). Raises: ValueError: If the motor index is not 1 or 2. Example: >>> motors.stop(1) # Stop motor 1 >>> motors.stop(2) # Stop motor 2 """ if motor_idx == 1: self.motor1_1_duty = 0 self.motor1_2_duty = 0 self.motor1_1.on() self.motor1_2.on() elif motor_idx == 2: self.motor2_1_duty = 0 self.motor2_2_duty = 0 self.motor2_1.on() self.motor2_2.on() else: raise ValueError( "[motors]Invalid motor index. Must be between 1 and 2.")
[docs] def set_forward_rate(self, motor_idx, val): """ Sets the maximum forward speed for the specified motor. The speed value must be between 0 and 100, \ where 100 indicates maximum speed. Args: motor_idx (int): Index of the motor (1 or 2). val (int): The forward speed, in the range [0, 100]. Raises: ValueError: If the value is outside the acceptable range. Example: >>> # Set motor 1 to 80% forward speed >>> motors.set_forward_rate(1, 80) """ if motor_idx in self.motor_params: if 0 <= val <= 100: self.motor_params[motor_idx]['forward_speed'] = val else: print("[motors]Parameter value out of range (0-100).") else: print("[motors]Invalid motor index or parameter.")
[docs] def set_reverse_rate(self, motor_idx, val): """ Sets the maximum reverse speed for the specified motor. Args: motor_idx (int): Index of the motor (1 or 2). val (int): The reverse speed, in the range [0, 100]. Raises: ValueError: If the value is outside the acceptable range. Example: >>> # Set motor 2 to 50% reverse speed >>> motors.set_reverse_rate(2, 50) """ if motor_idx in self.motor_params: if 0 <= val <= 100: self.motor_params[motor_idx]['reverse_speed'] = val else: print("[motors]Parameter value out of range (0-100).") else: print("[motors]Invalid motor index or parameter.")
[docs] def set_offset(self, motor_idx, val): """ Sets the offset for the specified motor. Args: motor_idx (int): Index of the motor (1 or 2). val (int): The offset value, in the range [-100, 100]. Raises: ValueError: If the value is outside the acceptable range. Example: >>> motors.set_offset(1, 20) # Set motor 1 offset to 20 """ if motor_idx in self.motor_params: if -100 <= val <= 100: self.motor_params[motor_idx]['offset'] = val else: print("[motors]Parameter value out of range (-100-100).") else: print("[motors]Invalid motor index or parameter.")
# Getter methods for motor parameters
[docs] def get_forward_rate(self, motor_idx): """ Gets the maximum forward speed for the specified motor. Args: motor_idx (int): Index of the motor (1 or 2). Returns: int: The forward speed of the motor, in the range [0, 100]. If the motor index is invalid, returns None. Example: >>> # Returns 100 (default forward speed for motor 1) >>> motors.get_forward_rate(1) >>> # Returns 80 (if motor 2's forward speed is set to 80) >>> motors.get_forward_rate(2) """ if motor_idx in self.motor_params: return self.motor_params[motor_idx]['forward_speed'] else: print("[motors] Invalid motor index.") return None
[docs] def get_reverse_rate(self, motor_idx): """ Gets the maximum reverse speed for the specified motor. Args: motor_idx (int): Index of the motor (1 or 2). If the motor index is invalid, returns None. Returns: int: The reverse speed of the motor, in the range [0, 100]. Example: >>> # Returns 100 (default reverse speed for motor 1) >>> motors.get_reverse_rate(1) >>> # Returns 80 (if motor 2's reverse speed is set to 80) >>> motors.get_reverse_rate(2) """ if motor_idx in self.motor_params: return self.motor_params[motor_idx]['reverse_speed'] else: print("[motors] Invalid motor index.") return None
[docs] def get_offset(self, motor_idx): """ Gets the offset value for the specified motor. Args: motor_idx (int): Index of the motor (1 or 2). Returns: int: The offset value of the motor, in the range [-100, 100]. Example: >>> # Returns 0 (default offset for motor 1) >>> motors.get_offset(1) >>> # Returns 10 (if motor 2's offset is set to 10) >>> motors.get_offset(2) """ if motor_idx in self.motor_params: return self.motor_params[motor_idx]['offset'] else: print("[motors] Invalid motor index.") return None
def _speed_handler(self, speed): """ Converts a speed value to duty cycle values for two motor channels. Args: speed (int): Speed value to convert. Returns: tuple: A tuple containing the duty cycle values for \ the two motor channels. """ if speed > 0: pwm1 = int(speed * PERIOD / 2048) pwm2 = 0 elif speed < 0: pwm1 = 0 pwm2 = int(-speed * PERIOD / 2048) else: pwm1 = 0 pwm2 = 0 return pwm1, pwm2