MotorGo Plink
MotorGo Plink
The MotorGo Plink is a four-channel ESP32-S3 motor-control board from Every Flavor Robotics. The espp::MotorGoPlink component provides a singleton board abstraction for the documented pin mapping of its DC motor outputs, encoder chip-selects, servo signal header, onboard LSM6DS33 IMU, Qwiic and internal I2C buses, and user/status LEDs.
It also provides helper methods for:
initializing the four dual-PWM motor channels via
espp::BdcDriveron MCPWM and commanding normalized motor speeds, where positive commands drivepwm_aand negative commands drivepwm_binitializing the shared SSI/SPI encoder bus and creating four espp::Mt6701<SSI> helpers
initializing the onboard LSM6DS33 IMU on the hidden I2C bus via the espp::Lsm6dso helper
accessing the four RC-servo signal pins for use with an external servo driver
controlling the user and status LEDs with direct brightness setters or a Gaussian breathing effect
API Reference
Header File
Classes
-
class MotorGoPlink : public espp::BaseComponent
MotorGoPlink is a lightweight board-support component for the MotorGo Plink hardware.
It exposes the documented pin mapping for the board’s:
four dual-PWM DC motor outputs
four encoder chip-selects on a shared SSI/SPI bus
four RC-servo signal pins
one onboard LSM6DS33 IMU on the hidden I2C bus
Qwiic and hidden I2C buses
user and status LEDs
The class is a singleton and can be accessed with get().
MotorGo Plink Example
auto &board = espp::MotorGoPlink::get(); if (!board.initialize_leds()) { logger.warn("Failed to initialize indicator LEDs"); } else { board.start_led_breathing(); } #if CONFIG_MOTORGO_PLINK_EXAMPLE_ENABLE_MOTOR_SWEEP if (!board.initialize_motors()) { logger.error("Failed to initialize motor drivers"); } else { board.stop_all_motors(); } #else logger.info("Motor drivers not initialized because motor sweep is disabled"); #endif if (!board.initialize_imu()) { logger.warn("Failed to initialize onboard IMU"); } else { logger.info("IMU initialized"); } log_board_info(board); #if CONFIG_MOTORGO_PLINK_EXAMPLE_ENABLE_ENCODER_POLLING if (!board.initialize_encoders(false)) { logger.warn("Failed to initialize encoders"); } else { logger.info("Encoder polling enabled"); } #else logger.info("Encoder polling disabled"); #endif #if CONFIG_MOTORGO_PLINK_EXAMPLE_ENABLE_MOTOR_SWEEP logger.warn("Motor sweep enabled; using an aggressive {:.0f}% to {:.0f}% duty sweep after a " "{:.0f}% zero window. Ensure the board is connected to a safe test setup", 35.0f, 85.0f, 5.0f); #else logger.info("Motor sweep disabled; all motors remain stopped"); #endif #if CONFIG_MOTORGO_PLINK_EXAMPLE_ENABLE_MOTOR_SWEEP float motor_phase = 0.0f; #endif while (true) { #if CONFIG_MOTORGO_PLINK_EXAMPLE_ENABLE_MOTOR_SWEEP update_motor_demo(board, motor_phase); log_motor_outputs(board); #endif #if CONFIG_MOTORGO_PLINK_EXAMPLE_ENABLE_ENCODER_POLLING log_encoder_angles(board); #endif log_imu_data(board); using namespace std::chrono_literals; std::this_thread::sleep_for(500ms); }
Public Types
-
using Encoder = espp::Mt6701<espp::Mt6701Interface::SSI>
Alias for the SSI-based magnetic encoder helper used on each motor channel.
Public Functions
-
MotorGoPlink(const MotorGoPlink&) = delete
Deleted copy constructor.
-
MotorGoPlink &operator=(const MotorGoPlink&) = delete
Deleted copy assignment operator.
-
MotorGoPlink(MotorGoPlink&&) = delete
Deleted move constructor.
-
MotorGoPlink &operator=(MotorGoPlink&&) = delete
Deleted move assignment operator.
-
I2c &get_external_i2c()
Get the external Qwiic I2C bus.
- Returns:
Reference to the initialized external I2C bus.
-
I2c &qwiic_i2c()
Get the external Qwiic I2C bus.
- Returns:
Reference to the initialized external I2C bus.
Get the internal hidden I2C bus.
- Returns:
Reference to the initialized internal I2C bus.
-
std::array<MotorPins, 4> motor_pins() const
Get the documented motor pin mappings for all four channels.
- Returns:
Array containing the two PWM pins for each motor channel.
-
MotorPins motor_pins(size_t index) const
Get one motor channel pin mapping.
- Parameters:
index – Zero-based motor index in the range [0, num_motor_channels()).
- Returns:
The motor pin mapping for the requested channel, or a default `MotorPins{}` with `GPIO_NUM_NC` entries if the index is invalid.
-
EncoderBusPins encoder_bus_pins() const
Get the shared encoder bus pin mapping.
- Returns:
The shared SCLK, MISO, and dummy MOSI pins used for the encoder bus.
-
std::array<gpio_num_t, 4> encoder_cs_pins() const
Get the four encoder chip-select pins.
- Returns:
Array containing the chip-select pin for each encoder channel.
-
gpio_num_t encoder_cs_pin(size_t index) const
Get one encoder chip-select pin.
- Parameters:
index – Zero-based encoder index in the range [0, num_motor_channels()).
- Returns:
The requested encoder chip-select pin, or `GPIO_NUM_NC` if the index is invalid.
-
std::array<gpio_num_t, 4> servo_pins() const
Get the four servo signal pins.
- Returns:
Array containing the four documented RC-servo signal GPIOs.
-
gpio_num_t servo_pin(size_t index) const
Get one servo signal pin.
- Parameters:
index – Zero-based servo index in the range [0, num_servo_channels()).
- Returns:
The requested servo signal pin, or `GPIO_NUM_NC` if the index is invalid.
-
I2cPins qwiic_pins() const
Get the external Qwiic I2C pin mapping.
- Returns:
The external Qwiic SDA/SCL pin mapping.
Get the hidden internal I2C pin mapping.
- Returns:
The internal SDA/SCL pin mapping.
-
LedPins led_pins() const
Get the user/status LED pins.
- Returns:
The documented user and status LED GPIOs.
-
bool initialize_motors(size_t pwm_frequency_hz = motor_default_pwm_frequency_hz())
Initialize the four MCPWM-backed motor driver helpers.
- Parameters:
pwm_frequency_hz – PWM carrier frequency for all four motor channels.
- Returns:
True if the motor driver helpers were initialized; false if the PWM frequency is invalid or any motor channel could not be configured.
-
bool set_motor_speed(size_t index, float speed)
Set a normalized motor speed in the range [-1, 1].
- Parameters:
index – Zero-based motor index in the range [0, num_motor_channels()).
speed – Normalized motor command. Values are clamped to [-1.0, 1.0], with positive values driving `pwm_a`, negative values driving `pwm_b`, and zero disabling both PWM outputs for that motor.
- Returns:
True if the motor command was applied; false if the motor PWM subsystem has not been initialized or the index is invalid.
-
float motor_speed(size_t index) const
Get the last commanded normalized motor speed.
- Parameters:
index – Zero-based motor index in the range [0, num_motor_channels()).
- Returns:
The last commanded normalized speed for that channel, or 0.0f if the index is invalid.
-
void stop_motor(size_t index)
Stop one motor channel.
- Parameters:
index – Zero-based motor index in the range [0, num_motor_channels()).
-
void stop_all_motors()
Stop all motor channels.
If the motor PWM subsystem has been initialized, each motor is actively commanded to zero speed. Otherwise the cached command values are simply reset to zero.
-
std::shared_ptr<MotorDriver> motor_driver(size_t index) const
Get one motor driver helper.
- Parameters:
index – Zero-based motor index in the range [0, num_motor_channels()).
- Returns:
Shared pointer to the requested motor driver helper, or `nullptr` if the index is invalid or that motor has not been initialized yet.
-
bool initialize_encoders(bool run_tasks = true)
Initialize the shared encoder bus and create the four MT6701 SSI helpers.
- Parameters:
run_tasks – If true, each encoder starts its own update task after initialization. If false, callers must invoke `Encoder::update()` manually.
- Returns:
True if the shared bus and all four encoder helpers were initialized successfully; false otherwise.
-
std::shared_ptr<Encoder> encoder(size_t index)
Get one encoder helper.
- Parameters:
index – Zero-based encoder index in the range [0, num_motor_channels()).
- Returns:
Shared pointer to the requested encoder helper, or `nullptr` if the index is invalid or that encoder has not been initialized yet.
-
void reset_encoder_accumulator(size_t index)
Reset one encoder’s accumulator.
If the encoder has not been initialized, the request is ignored after logging an error.
- Parameters:
index – Zero-based encoder index in the range [0, num_motor_channels()).
- bool initialize_imu (const Imu::filter_fn &orientation_filter=nullptr, const Imu::ImuConfig &imu_config={ .accel_range=Imu::AccelRange::RANGE_2G,.accel_odr=Imu::AccelODR::ODR_104_HZ,.gyro_range=Imu::GyroRange::DPS_1000,.gyro_odr=Imu::GyroODR::ODR_104_HZ, })
Initialize the onboard IMU on the hidden I2C bus.
- Parameters:
orientation_filter – Optional orientation filter callback used by the IMU driver when update() is called.
imu_config – Basic accelerometer / gyroscope configuration to apply during initialization.
- Returns:
True if the hidden-bus I2C device and IMU helper were initialized successfully; false otherwise.
-
std::shared_ptr<Imu> imu() const
Get the onboard IMU helper.
- Returns:
Shared pointer to the initialized IMU helper, or `nullptr` if initialize_imu() has not been called yet.
-
bool initialize_leds(float breathing_period = 3.5f)
Initialize the user/status LED helpers.
- Parameters:
breathing_period – Default breathing period in seconds for start_led_breathing().
- Returns:
True if the indicator LED PWM helper and breathing task were created successfully; false if they were already initialized or the LEDs could not be driven after setup.
-
void start_led_breathing()
Start breathing both indicator LEDs.
This uses the shared Gaussian waveform returned by gaussian().
-
void stop_led_breathing()
Stop breathing and turn both indicator LEDs off.
-
bool set_user_led_brightness(float brightness)
Set the user LED brightness in the range [0, 1].
- Parameters:
brightness – Desired brightness, clamped to [0.0, 1.0].
- Returns:
True if the user LED duty cycle was updated; false if the LEDs have not been initialized or the breathing task is currently running.
-
float get_user_led_brightness()
Get the user LED brightness in the range [0, 1].
- Returns:
Current user LED brightness normalized to [0.0, 1.0], or 0.0f if the LEDs have not been initialized or the duty cycle could not be read.
-
bool set_status_led_brightness(float brightness)
Set the status LED brightness in the range [0, 1].
- Parameters:
brightness – Desired brightness, clamped to [0.0, 1.0].
- Returns:
True if the status LED duty cycle was updated; false if the LEDs have not been initialized or the breathing task is currently running.
-
float get_status_led_brightness()
Get the status LED brightness in the range [0, 1].
- Returns:
Current status LED brightness normalized to [0.0, 1.0], or 0.0f if the LEDs have not been initialized or the duty cycle could not be read.
-
bool set_led_breathing_period(float period)
Set the LED breathing period in seconds.
- Parameters:
period – Breathing period in seconds. Must be greater than zero.
- Returns:
True if the period was accepted; false if the value is not positive.
-
float get_led_breathing_period()
Get the LED breathing period in seconds.
- Returns:
The configured LED breathing period in seconds.
-
std::shared_ptr<espp::Led> leds()
Get the LED helper used for the indicator LEDs.
- Returns:
Shared pointer to the indicator LED helper, or `nullptr` if initialize_leds() has not been called yet.
-
espp::Gaussian &gaussian()
Get the Gaussian waveform used for LED breathing.
- Returns:
Reference to the Gaussian waveform object used by the LED breathing task.
-
inline const std::string &get_name() const
Get the name of the component
Note
This is the tag of the logger
- Returns:
A const reference to the name of the component
-
inline void set_log_tag(const std::string_view &tag)
Set the tag for the logger
- Parameters:
tag – The tag to use for the logger
-
inline espp::Logger::Verbosity get_log_level() const
Get the log level for the logger
See also
See also
- Returns:
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- Parameters:
level – The verbosity level to use for the logger
-
inline void set_log_verbosity(espp::Logger::Verbosity level)
Set the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls set_log_level
- Parameters:
level – The verbosity level to use for the logger
-
inline espp::Logger::Verbosity get_log_verbosity() const
Get the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls get_log_level
- Returns:
The verbosity level of the logger
-
inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
Set the rate limit for the logger
See also
Note
Only calls to the logger that have _rate_limit suffix will be rate limited
- Parameters:
rate_limit – The rate limit to use for the logger
Public Static Functions
-
static inline MotorGoPlink &get()
Access the singleton board instance.
- Returns:
Reference to the singleton MotorGoPlink object.
-
static inline constexpr size_t num_motor_channels()
Get the number of supported motor channels.
- Returns:
The number of motor channels exposed by the board.
-
static inline constexpr size_t num_servo_channels()
Get the number of exposed servo signal pins.
- Returns:
The number of servo channels exposed by the board.
-
static inline constexpr size_t motor_default_pwm_frequency_hz()
Get the default PWM frequency used for motor outputs.
- Returns:
Default motor PWM frequency in Hz.
-
static inline constexpr size_t encoder_spi_clock_speed_hz()
Get the encoder bus clock speed.
- Returns:
Default encoder SSI/SPI clock speed in Hz.
-
static inline constexpr gpio_num_t user_led_pin()
Get the user LED GPIO.
- Returns:
User LED pin.
-
static inline constexpr gpio_num_t status_led_pin()
Get the status LED GPIO.
- Returns:
Status LED pin.
-
struct EncoderBusPins
Shared encoder SSI/SPI bus pins.
-
struct I2cPins
I2C pin mapping.
-
struct LedPins
User-visible LED pin mapping.
-
struct MotorPins
Pin mapping for one DC motor channel.