Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ jobs:
target: esp32
- path: 'components/monitor/example'
target: esp32
- path: 'components/motorgo-axis/example'
target: esp32s3
- path: 'components/motorgo-mini/example'
target: esp32s3
- path: 'components/motorgo-plink/example'
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/upload_components.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ jobs:
components/max1704x
components/mcp23x17
components/monitor
components/motorgo-axis
components/motorgo-mini
components/motorgo-plink
components/mt6701
Expand Down
6 changes: 6 additions & 0 deletions components/motorgo-axis/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
idf_component_register(
INCLUDE_DIRS "include"
SRC_DIRS "src"
REQUIRES base_component bldc_driver esp_driver_gpio i2c led lsm6dso math mt6701 spi task
REQUIRED_IDF_TARGETS "esp32s3"
)
31 changes: 31 additions & 0 deletions components/motorgo-axis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# MotorGo Axis Board Support Package (BSP) Component

[![Badge](https://components.espressif.com/components/espp/motorgo-axis/badge.svg)](https://components.espressif.com/components/espp/motorgo-axis)

The MotorGo Axis is an ESP32-S3 motor-control board from Every Flavor
Robotics. It combines:

- two 6-PWM BLDC motor outputs
- two MT6701-compatible SSI encoder chip-selects on a shared bus
- one onboard LSM6DS33 IMU on the internal I2C bus
- a Qwiic I2C bus plus a second internal I2C bus
- user and status LEDs

The `espp::MotorGoAxis` component provides a singleton board abstraction for
those documented pin mappings, plus convenient helpers for:

- initializing the two BLDC motor driver channels with `espp::BldcDriver`
- initializing the shared encoder SPI/SSI bus and creating two
`espp::Mt6701<SSI>` encoder instances
- initializing the onboard LSM6DS33 IMU on the hidden I2C bus via the shared
`espp::Lsm6dso` driver
- controlling the user/status LEDs with simple brightness setters or a Gaussian
breathing effect
- accessing the external Qwiic and internal I2C buses

## Example

The [example](./example) initializes the board, logs the MotorGo Axis pin map,
starts the onboard LEDs breathing, initializes the onboard IMU, initializes the
two BLDC driver channels in a disabled state, and can optionally poll the two
encoder inputs.
21 changes: 21 additions & 0 deletions components/motorgo-axis/example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.20)

set(ENV{IDF_COMPONENT_MANAGER} "0")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)

set(EXTRA_COMPONENT_DIRS
"../../../components/"
)

set(
COMPONENTS
"main logger motorgo-axis"
CACHE STRING
"List of components to include"
)

project(motorgo_axis_example)

set(CMAKE_CXX_STANDARD 20)
47 changes: 47 additions & 0 deletions components/motorgo-axis/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# MotorGo Axis Example

This example demonstrates how to use the `espp::MotorGoAxis` component to
initialize the hardware on the MotorGo Axis board.

By default the example is intentionally safe:

- it logs the documented motor, encoder, I2C, and LED pin mappings
- it starts the user and status LEDs breathing out of phase
- it initializes the two BLDC driver channels and then leaves them disabled

Optional `menuconfig` flags let you also initialize and poll the two encoder
inputs.

## How to use example

### Hardware Required

This example is designed for the MotorGo Axis board.

The default configuration does not require motors or encoders to be connected.
If you enable encoder polling, connect the matching hardware first.

### Configuration

Open the example configuration menu if you want to enable encoder polling:

```bash
idf.py menuconfig
```

Then open **MotorGo Axis Example Configuration** and enable:

- **Enable encoder polling**

### Build and Flash

Build the project and flash it to the board, then run monitor tool to view
serial output:

```bash
idf.py -p PORT flash monitor
```

(Replace PORT with the name of the serial port to use.)

(To exit the serial monitor, type `Ctrl-]`.)
2 changes: 2 additions & 0 deletions components/motorgo-axis/example/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS ".")
7 changes: 7 additions & 0 deletions components/motorgo-axis/example/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
menu "MotorGo Axis Example Configuration"
config MOTORGO_AXIS_EXAMPLE_ENABLE_ENCODER_POLLING
bool "Enable encoder polling"
default n
help
Initialize the two encoder inputs and log their measured angles.
endmenu
129 changes: 129 additions & 0 deletions components/motorgo-axis/example/main/motorgo_axis_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#include <array>
#include <system_error>
#include <thread>

#include <esp_timer.h>

#include "logger.hpp"
#include "motorgo-axis.hpp"

namespace {
static auto logger = espp::Logger({
.tag = "MotorGoAxis Example",
.level = espp::Logger::Verbosity::INFO,
});

void log_board_info(espp::MotorGoAxis &board) {
auto qwiic = board.qwiic_pins();
auto hidden_i2c = board.hidden_i2c_pins();
auto leds = board.led_pins();
auto enc_bus = board.encoder_bus_pins();
auto encoder_cs = board.encoder_cs_pins();

logger.info("Qwiic I2C: SDA={}, SCL={}", qwiic.sda, qwiic.scl);
logger.info("Hidden I2C: SDA={}, SCL={}", hidden_i2c.sda, hidden_i2c.scl);
logger.info("LEDs: user={}, status={}", leds.user, leds.status);
logger.info("Encoder bus: SCLK={}, MISO={}", enc_bus.sclk, enc_bus.miso);
logger.info("Encoder CS: [{}, {}]", encoder_cs[0], encoder_cs[1]);
for (size_t i = 0; i < espp::MotorGoAxis::num_motor_channels(); i++) {
auto pins = board.motor_pins(i);
logger.info("Motor {} pins: uh={}, ul={}, vh={}, vl={}, wh={}, wl={}", i + 1, pins.u_high,
pins.u_low, pins.v_high, pins.v_low, pins.w_high, pins.w_low);
}
}

void log_imu_data(espp::MotorGoAxis &board) {
auto imu = board.imu();
if (!imu) {
logger.warn("IMU is not initialized");
return;
}

static int64_t last_update_us = esp_timer_get_time();
int64_t now_us = esp_timer_get_time();
float dt = (now_us - last_update_us) / 1'000'000.0f;
last_update_us = now_us;

std::error_code ec;
if (!imu->update(dt, ec)) {
logger.warn("Failed to update IMU: {}", ec.message());
return;
}

auto accel = imu->get_accelerometer();
auto gyro = imu->get_gyroscope();
auto temp = imu->get_temperature();
logger.info("IMU accel [g]: {:.3f}, {:.3f}, {:.3f} | gyro [dps]: {:.3f}, {:.3f}, {:.3f} | "
"temp [C]: {:.1f}",
accel.x, accel.y, accel.z, gyro.x, gyro.y, gyro.z, temp);
}

#if CONFIG_MOTORGO_AXIS_EXAMPLE_ENABLE_ENCODER_POLLING
void log_encoder_angles(espp::MotorGoAxis &board) {
std::array<float, espp::MotorGoAxis::num_motor_channels()> angles{};
for (size_t i = 0; i < angles.size(); i++) {
auto encoder = board.encoder(i);
if (!encoder) {
logger.warn("Encoder {} is not initialized", i + 1);
return;
}
std::error_code ec;
encoder->update(ec);
if (ec) {
logger.warn("Failed to update encoder {}: {}", i + 1, ec.message());
return;
}
angles[i] = encoder->get_radians();
}

logger.info("Encoder angles [rad]: {:.3f}, {:.3f}", angles[0], angles[1]);
}
#endif
} // namespace

extern "C" void app_main() {
//! [motorgo-axis example]
auto &board = espp::MotorGoAxis::get();

if (!board.initialize_leds()) {
logger.warn("Failed to initialize indicator LEDs");
} else {
board.start_led_breathing();
}

if (!board.initialize_motors()) {
logger.warn("Failed to initialize BLDC motor drivers");
} else {
logger.info("Motor drivers initialized and left disabled");
}

if (!board.initialize_imu()) {
logger.warn("Failed to initialize onboard IMU");
} else {
logger.info("IMU initialized");
}

log_board_info(board);

#if CONFIG_MOTORGO_AXIS_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

while (true) {
#if CONFIG_MOTORGO_AXIS_EXAMPLE_ENABLE_ENCODER_POLLING
log_encoder_angles(board);
#endif

log_imu_data(board);

using namespace std::chrono_literals;
std::this_thread::sleep_for(500ms);
}
//! [motorgo-axis example]
}
1 change: 1 addition & 0 deletions components/motorgo-axis/example/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_IDF_TARGET="esp32s3"
34 changes: 34 additions & 0 deletions components/motorgo-axis/idf_component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## IDF Component Manager Manifest File
license: "MIT"
description: "MotorGo Axis Board Support Package (BSP) component for ESP-IDF"
url: "https://github.com/esp-cpp/espp/tree/main/components/motorgo-axis"
repository: "git://github.com/esp-cpp/espp.git"
maintainers:
- William Emfinger <waemfinger@gmail.com>
documentation: "https://esp-cpp.github.io/espp/motorgo_axis.html"
examples:
- path: example
tags:
- cpp
- Component
- ESP32S3
- MotorGo
- Axis
- BSP
- BLDC
- Encoder
- IMU
dependencies:
idf:
version: '>=5.0'
espp/base_component: '>=1.0'
espp/bldc_driver: '>=1.0'
espp/i2c: '>=1.0'
espp/led: '>=1.0'
espp/lsm6dso: '>=1.0'
espp/math: '>=1.0'
espp/mt6701: '>=1.0'
espp/spi: '>=1.0'
espp/task: '>=1.0'
targets:
- esp32s3
Loading
Loading