Skip to content

martinbudden/SelfBalancingRobot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Radio Controlled Self Balancing Robot Framework

This software forms a framework for a Radio Controlled Self Balancing Robot. It is designed to be configurable and to support a variety of motor types, with and without encoders.

The radio control uses the ESP-NOW protocol.

Additionally there is a backchannel - this supports telemetry and also has a command interface to allow remote PID tuning.

Current Implementations

There are four currently implementations:

  1. one for the M5Stack Bala2Fire,
  2. one for the M5Stack BalaC,
  3. Lego version using 2 Power Functions XL Motors (8882) and the M5Stack GoPlus2 Module,
  4. 3D printed version using JGA25_370 Metal Geared Motors with encoders and the M5Stack 4EncoderMotor Module.

PID tuning for the Lego version is currently stalled - I burnt out one of the motor drivers on the GoPlus2 module during PID tuning.

PID tuning for the JGA25_370 is currently stalled - I ordered the wrong the JGA25_370 motors for the 3D printed version, the ones I ordered don't have enough torque, so I've ordered new motors (same motors with lower gearing).

M5Stack Bala2Fire M5Stack BalaC Lego version JGA25_370 motor version

These are controlled with the M5Stack AtomJoyStick.

M5Stack AtomJoyStick

Telemetry and PID tuning is using the M5Stack Cardputer

M5Stack Cardputer

Modularity of Implementation

The Self Balancing Robot Framework is implemented in a modular way, with the different components split off into separate libraries. These libraries are designed so they may be used in other projects.

Library Function Location
VectorQuaternionMatrix General purpose 3D vector, quaternion, and 3x3 matrix classes https://github.com/martinbudden/Library-VectorQuaternionMatrix
PIDF PID controller with feed-forward https://github.com/martinbudden/Library-PIDF
Filters Collection of general purpose filters https://github.com/martinbudden/Library-Filters
SensorFusion Sensor Fusion including Complementary Filter, Mahony Filter, Madgwick Filter, VQF https://github.com/martinbudden/Library-SensorFusion
IMU Inertial Measurement Unit - gyroscopes and accelerometers. https://github.com/martinbudden/Library-IMU
Stabilized Vehicle AHRS (Attitude and Heading Reference System) https://github.com/martinbudden/Library-StabilizedVehicle.git
Receiver Receiver base class and implementations, including implementation using ESP-NOW https://github.com/martinbudden/Library-Receiver
Backchannel Backchannel over ESP-NOW for telemetry, PID tuning, and benchmarking https://github.com/martinbudden/Library-Backchannel

Class structure

Simplified outline of main classes.

Classes with <eg> suffix are specific instances for Bala2 self balancing robot.

All objects are statically allocated in Main::setup().

classDiagram
    class SensorFusionFilterBase {
        <<abstract>>
        update() Quaternion *
        getOrientation() Quaternion const
    }
    link SensorFusionFilterBase "https://github.com/martinbudden/Library-SensorFusion/blob/main/src/SensorFusion.h"

    class IMU_Base {
        virtual readAccGyroRPS() accGyroRPS_t
    }
    link IMU_Base "https://github.com/martinbudden/Library-IMU/blob/main/src/IMU_Base.h"

    class IMU_FiltersBase {
        <<abstract>>
        setFilters() *
        filter() *
    }
    link IMU_FiltersBase "https://github.com/martinbudden/Library-StabilizedVehicle/blob/main/src/IMU_FiltersBase.h"
    IMU_FiltersBase <|-- IMU_Filters

    class VehicleControllerBase {
        <<abstract>>
        loop() *
        updateOutputsUsingPIDs() *
    }
    link VehicleControllerBase "https://github.com/martinbudden/Library-StabilizedVehicle/blob/main/src/VehicleControllerBase.h"

    VehicleControllerBase <|-- MotorPairController
    class MotorPairController {
        array~PIDF~ _pids
        updateSetpoints();
        updateMotorSpeedEstimates();
    }
    link MotorPairController "https://github.com/martinbudden/SelfBalancingRobot/blob/main/lib/SelfBalancingRobot/src/MotorPairController.h"

    class MotorPairMixer {
    }
    link MotorPairMixer "https://github.com/martinbudden/SelfBalancingRobot/blob/main/lib/SelfBalancingRobot/src/MotorPairMixer.h"

    class MotorPairBase {
        <<abstract>>
        readEncoder() *
        setPower() *
    }
    link MotorPairBase "https://github.com/martinbudden/SelfBalancingRobot/blob/main/lib/SelfBalancingRobot/src/MotorPairBase.h"
    MotorPairController *-- MotorPairBase
    MotorPairController *-- MotorPairMixer
    MotorPairController o-- CockpitBase

    MotorPairBase <|-- MotorsBala2
    class MotorsBala2["MotorsBala2(eg)"]
    link MotorsBala2 "https://github.com/martinbudden/SelfBalancingRobot/blob/main/lib/MotorPairs/src/MotorsBala2.h"

    class AHRS {
        bool readIMUandUpdateOrientation()
    }
    link AHRS "https://github.com/martinbudden/Library-StabilizedVehicle/blob/main/src/AHRS.h"
    AHRS *-- IMU_Base
    AHRS *-- SensorFusionFilterBase
    AHRS *-- IMU_FiltersBase
    AHRS o-- VehicleControllerBase
    VehicleControllerBase o-- AHRS

    class ReceiverBase {
        <<abstract>>
        WAIT_FOR_DATA_RECEIVED() int32_t *
        update() bool *
        getStickValues() *
        getAuxiliaryChannel() uint32_t *
    }
    link ReceiverBase "https://github.com/martinbudden/Library-Receiver/blob/main/src/ReceiverBase.h"

    class CockpitBase {
        <<abstract>>
        updateControls() *
        checkFailsafe() *
    }
    link CockpitBase "https://github.com/martinbudden/Library-Receiver/blob/main/src/CockpitBase.h"

    Cockpit o-- MotorPairController
    CockpitBase o--ReceiverBase
    CockpitBase <|-- Cockpit
    class Cockpit {
        updateControls() override
        checkFailsafe() override
        getFailsafePhase() uint32_t const
    }
    link Cockpit "https://github.com/martinbudden/SelfBalancingRobot/blob/main/lib/SelfBalancingRobot/src/Cockpit.h"

    IMU_Base <|-- IMU_MPU6886
    class IMU_MPU6886["IMU_MPU6886(eg)"]
    link IMU_MPU6886 "https://github.com/martinbudden/Library-IMU/blob/main/src/IMU_MPU6886.h"

    SensorFusionFilterBase  <|-- MadgwickFilter
    class MadgwickFilter["MadgwickFilter(eg)"] {
        update() Quaternion override
    }

    ReceiverBase <|-- ReceiverAtomJoyStick
    class ReceiverAtomJoyStick["ReceiverAtomJoyStick(eg)"]
    link ReceiverAtomJoyStick "https://github.com/martinbudden/Library-Receiver/blob/main/src/ReceiverAtomJoyStick.h"
    ReceiverAtomJoyStick *-- ESPNOW_Transceiver
    class ESPNOW_Transceiver
    link ESPNOW_Transceiver "https://github.com/martinbudden/Library-Receiver/blob/main/src/ESPNOW_Transceiver.h"
Loading

Task structure

Simplified outline of tasks.

On a dual-core processor AHRS_Task has the second core all to itself.

The AHRS_Task and the ReceiverTask may be either interrupt driven or timer driven.
All other tasks are timer driven.

Tasks are statically (build-time) polymorphic, not dynamically (run-time) polymorphic. They all have task and loop functions, but these functions are not virtual. This is deliberate.

BackchannelTask is optional tasks and are not required for motion.

classDiagram
    class TaskBase {
        uint32_t _taskIntervalMicroseconds
    }
    link TaskBase "https://github.com/martinbudden/Library-TaskBase/blob/main/src/TaskBase.h"

    TaskBase <|-- MainTask
    class MainTask {
        loop()
    }
    MainTask o-- ButtonsBase : calls update
    MainTask o-- ScreenBase : calls update

    class CockpitBase {
        <<abstract>>
        updateControls() *
        checkFailsafe() *
    }
    class ReceiverBase {
        <<abstract>>
        WAIT_FOR_DATA_RECEIVED() int32_t *
        update() bool *
        getStickValues() *
        getAuxiliaryChannel() uint32_t *
    }

    CockpitBase o--ReceiverBase
    CockpitBase <|-- Cockpit
    Cockpit o-- MotorPairController : calls updateSetpoints

    TaskBase <|-- ReceiverTask
    class ReceiverTask {
        loop()
        -task() [[noreturn]]
    }
    link ReceiverTask "https://github.com/martinbudden/Library-Receiver/blob/main/src/ReceiverTask.h"
    class ReceiverWatcher {
        <<abstract>>
        newReceiverPacketAvailable() *
    }
    ReceiverTask o-- ReceiverWatcher : calls newReceiverPacketAvailable
    ReceiverTask o-- ReceiverBase : calls WAIT_FOR_DATA_RECEIVED update getStickValues
    ReceiverWatcher <|-- ScreenBase
    ReceiverTask o-- CockpitBase : calls updateControls checkFailsafe

    class VehicleControllerBase {
        <<abstract>>
        loop() *
        updateOutputsUsingPIDs() *
    }
    TaskBase <|-- VehicleControllerTask
    class VehicleControllerTask {
        loop()
        -task() [[noreturn]]
    }
    link VehicleControllerTask "https://github.com/martinbudden/Library-StabilizedVehicle/blob/main/src/VehicleControllerTask.h"
    VehicleControllerTask o-- VehicleControllerBase : calls loop
    VehicleControllerBase <|-- MotorPairController

    TaskBase <|-- AHRS_Task
    class AHRS_Task {
        loop()
        -task() [[noreturn]]
    }
    link AHRS_Task "https://github.com/martinbudden/Library-StabilizedVehicle/blob/main/src/AHRS_Task.h"
    AHRS_Task o-- AHRS : calls readIMUandUpdateOrientation

    class AHRS {
        bool readIMUandUpdateOrientation()
    }
    AHRS o-- VehicleControllerBase : calls updateOutputsUsingPIDs
    VehicleControllerBase o-- AHRS

    class Backchannel {
        processedReceivedPacket() bool
    }
    TaskBase <|-- BackchannelTask
    class BackchannelTask {
        loop()
        -task() [[noreturn]]
    }
    link BackchannelTask "https://github.com/martinbudden/Library-Backchannel/blob/main/src/BackchannelTask.h"
    BackchannelTask o-- Backchannel : calls processedReceivedPacket
Loading

Potential Future Implementations

This is more a list of ideas for possible future implementations rather than a plan to make those implementations. I might undertake some of these depending on availability of time and hardware:

  1. Hoverboard version using ODrive, ODesc, or Moteus drivers and probably the M5 Stack PwrCAN Module.
  2. 3D printed version using NEMA17 stepper motors.
  3. 3D printed version using M5Stack RollerCAN Units and M5 Stack PwrCAN Module.
  4. Tiny version using Carl Bugeja's Microbots CodeCell and two Microbots DriveCell - how small can I make it?
  5. Raspberry Pi Pico version. In particular I'd like to try and port the D-Shot ESC Protocol to the Raspberry Pi Pico Programmable I/O and use the Pico to control the motors. Since D-Shot is a bidirectional protocol it will be possible to obtain the motors' RPM and use that as part of the motor control loop. As I understand it, D-Shot only provides reliable motor RPM values for high RPM, but it might still be possible to use the values provided instead of using encoders. Something at least worth investigating.
  6. Port to Raspberry Pi and use Raspberry Pi Lego hat to make a Lego version using PoweredUp motors (which have encoders built in).
  7. Addition of wheels to the feet of Dan's Modular Biped Robot. The idea is they would be a bit like Heelys and allow the robot to lift itself onto it's heels and then propel itself.

Articles/videos about Self Balancing Robots

How to visually tune PID Control Loops - good explanation of how to do PID tuning.

Building an Arduino-based self-balancing robot. Good explanation of all the ins and outs of self balancing robots, by Mike Jacobs.

Other self balancing robots

J Pieper's Hoverbot uses hoverboard motors and moteus-c1 BLDC motor controllers. Code runs on a Raspberry Pi. Has an explanation of the build and the PID control system.

Stijns Projects self balancing robot uses hoverboard motors and ODrive/ODESC BLDC motor controllers. Code runs on two Arduinos. Has a good explanation of how to to set up ODrive.

Lukas Kaul's version of the HoverBot uses hoverboard motors and ODrive BLDC motor controllers Code runs on an Arduino. Has a good explanation of the build.

James Bruton's TallBalancer youtube video uses Turnigy 6374 148 kV motors and ODrive BLDC motor controllers. Code runs on a Teensy 3.6. The code is here

Noah Zipin's self balancing robot uses Pololu 156:1 Metal Gearmotors (20Dx44L mm 12V CB with Extended Motor Shaft and Hall effect encoders) and L298N (H-bridge) motor controllers. The code runs on an Arduino. The code is here

Your Arduino Balancing Robot uses NEMA-17 stepper motors. The code runs on an Arduino. Good overall explanation.

Arduino SimpleFOCBalancer - Modular Arduino two wheel balancing robot. Uses 4108 gimbal BLDC motors with AMT103 CUI encoders. Motors controlled by an Arduino SimpleFOCShield and the SimpleFOClibrary. Good explanation of the build and overview of the control algorithm.

About

Radio Controlled Self Balancing Robot Framework

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published