Project Overview

July 30, 2026 · View on GitHub

Documentation Note: All project documentation is maintained in this README.md file. Whenever documentation is mentioned or requested, it refers to updates or additions to this file.

This project provides a C++ library for controlling servo motors on both embedded platforms (Arduino, ESP32-C3, etc.) and desktop environments (macOS, etc.). It includes:

  • Minimal Arduino emulator for desktop testing (ArduinoEmulator.h).
  • Auto-generated unit conversions for positions, velocities, times, temperatures, etc. (AutoGeneratedUnitConversions.*).
  • Servomotor class for motor control with advanced features like calibration, homing, e-stop, etc.
  • Example test programs: test_one_move.cpp, test_unit_conversions.cpp, and test_get_temperature.cpp.

Autogeneration of Parts of the Source Code

The library includes several Python scripts for code generation and maintenance:

  • generate_unit_conversion_code.py: Generates unit conversion code from a JSON configuration
  • generate_command_code.py: Generates command interface code

File List and Descriptions

Below is an updated overview of the key files after renaming and restructuring:

FileDescription
ArduinoEmulator.hEmulates Arduino's Serial, delay(), etc. for desktop builds.
AutoGeneratedUnitConversions.h / .cppFunctions to convert between various units (time, position, velocity, acceleration, etc.).
Commands.hAutogenerated list of servo command IDs.
Communication.h / .cppSimple Communication class for sending/receiving commands (stubbed for testing).
DataTypes.h / .cppDefinitions of data type structures and bounds.
Utils.h / .cppHelper utilities for endianness, packing, and general-purpose functionality.
Servomotor.h / .cppMain servo control class with features like calibration, homing, e-stop, etc.
test_one_move.cppMinimal example demonstrating a single trapezoid move (2 rotations over 3 seconds).
test_unit_conversions.cppDesktop test verifying unit-conversion logic in AutoGeneratedUnitConversions.*.
test_get_temperature.cppExample demonstrating how to read temperature from the motor.
test_emergency_stop.cppTest for emergency stop functionality to ensure proper queue clearing and MOSFET disabling.
test_move_with_velocity.cppTest for moveWithVelocity functionality with different units (rotations, degrees, encoder counts).
test_enable_disable_mosfets.cppTest for enabling and disabling MOSFETs.
test_one_move_two_motors.cppExample demonstrating control of two motors simultaneously.

Architecture

  1. Unit Conversion Module

    • Centralizes all unit transformations in AutoGeneratedUnitConversions.*, ensuring consistency.
    • Supports various units:
      • Position: SHAFT_ROTATIONS, DEGREES, RADIANS, ENCODER_COUNTS
      • Time: SECONDS, MILLISECONDS, MINUTES, TIMESTEPS
    • Automatic conversion between user units and internal units (encoder counts and timesteps)
  2. Communication Module

    • Communication.cpp is a lightweight stub for sending commands and reading responses. It can be extended or replaced with a hardware-specific protocol (RS-485, UART, etc.).
  3. Servo Control Class

    • Servomotor provides:
      • Automatic unit conversions between user units and internal units
      • Detailed debug output for all operations
      • Automatic serial port initialization
      • User-friendly interface for motor control
  4. Testing on Desktop vs. Arduino

    • If ARDUINO macros are defined, <Arduino.h> is used for real hardware.
    • Otherwise, ArduinoEmulator.h provides stubs for Serial/delay so the same code builds on desktop.
    • Test programs can be built via a standard C++ compiler on desktop or compiled as .ino/C++ sources on an Arduino platform.

RS485 Communication Protocol

The library implements a robust RS485 communication protocol for reliable communication between a controller (master) and one or more devices (slaves). The protocol supports both standard addressing (using device aliases) and extended addressing (using 64-bit Unique IDs).

Packet Format

All packets follow this basic structure:

  1. Size Bytes: First byte(s) indicating total packet size

    • For sizes 1-127: Single byte containing size (left-shifted 7 bits with LSB=1)
    • For sizes >127: Three bytes
      • First byte: 0xFF (encoded value of 127 with LSB=1)
      • Two additional bytes: Little-endian 16-bit size
  2. Address Bytes:

    • Standard Addressing: Single byte containing device alias
      • 255 (ALL_ALIAS): Broadcasts to all devices
      • 254 (EXTENDED_ADDRESSING): Indicates extended addressing mode
      • 253 and 252 are not allowed because they are used to indicate responses (see below)
      • 0-251: Normal device aliases
    • Extended Addressing: When address byte is 254, next 8 bytes contain 64-bit Unique ID (little-endian)
  3. Command Byte: 8-bit command identifier

  4. Payload Data: Variable length data specific to the command

  5. CRC32: Optional 4-byte CRC32 checksum (enabled by default but can be disabled)

Response Format

Responses from devices follow this structure:

  1. Size Bytes: Same format as command packet

  2. Response Character: Single byte indicating response and CRC32 state

    • 253 (RESPONSE_CHARACTER_CRC32_ENABLED): Response from device with CRC32 enabled
    • 252 (RESPONSE_CHARACTER_CRC32_DISABLED): Response from device with CRC32 disabled
  3. Command Byte: 8-bit value indicating status

    • 0: Success and there is no firther data in the response
    • 1: Success and there is some further data in the response
    • Other values: Currently not used and reserved for future use
  4. Payload Data: Variable length response data

  5. CRC32: Optional 4-byte checksum (enabled by default but can be disabled)

CRC32 Implementation

CRC32 checksums provide additional data integrity verification:

  • Uses polynomial 0xEDB88320

  • Initialized to 0xFFFFFFFF

  • Calculated over entire packet contents (including size, address/response character, command, and payload bytes)

  • Final value is inverted to get the final CRC32 value

  • The CRC32 calculation gives the same result as Pythons zlib.crc32() or binascii.crc32() functions

  • Control:

    • Enabled by default after device reset
    • Can be enabled or disabled on a per-device basis by sending a CRC32_CONTROL_COMMAND
    • The response has encoded in it whether the device has appended a CRC32 in the response or not
    • Error statistics can be retrieved by issuing a GET_CRC32_ERROR_COUNT_COMMAND to the device

Error Handling

The protocol includes robust error handling with specific error codes. The Communication class functions (particularly getResponse) return specific negative error codes on failure, or COMMUNICATION_SUCCESS (0) on success:

  • COMMUNICATION_ERROR_TIMEOUT (-1): Timed out waiting for response bytes at various stages:
    • First byte
    • Size bytes
    • Response character
    • Command byte
    • Payload
    • CRC (if enabled)
  • COMMUNICATION_ERROR_DATA_WRONG_SIZE (-2): Received data size does not match expected size
  • COMMUNICATION_ERROR_BAD_RESPONSE_CHAR (-3): The response character byte was not RESPONSE_CHARACTER_CRC32_ENABLED (253) or RESPONSE_CHARACTER_CRC32_DISABLED (252)
  • COMMUNICATION_ERROR_BUFFER_TOO_SMALL (-5): The provided buffer size did not match the calculated payload size in the received response
  • COMMUNICATION_ERROR_CRC32_MISMATCH (-6): Calculated CRC32 of the received response did not match the received CRC32 value (when CRC enabled)
  • COMMUNICATION_ERROR_BAD_FIRST_BYTE (-7): The first byte of a received packet did not have LSB=1, indicating a format error or corrupted data
  • COMMUNICATION_ERROR_BAD_THIRD_BYTE (-8): The third byte in the response (expected to be the Command Byte) was invalid

Buffer Handling

When using the Arduino library's getResponse function for commands that do not return any payload data, nullptr can be passed as the buffer. The library will still receive and validate the full response (including CRC32 check if applicable) but will not attempt to copy the (empty) payload.

Command Processing Flow

  1. Controller sends command packet
  2. Device receives and processes command
  3. Device sends response packet (if required)
  4. Controller receives and validates response

Communication Class Methods

The Communication class provides the following key methods:

  • Communication(HardwareSerial& serialPort): Constructor, requires a HardwareSerial port (e.g., Serial1)
  • sendCommand(uint8_t alias, uint8_t commandID, const uint8_t* payload, uint16_t payloadSize): Sends a command using standard alias addressing
  • sendCommandByUniqueId(uint64_t uniqueId, uint8_t commandID, const uint8_t* payload, uint16_t payloadSize): Sends a command using extended 64-bit Unique ID addressing
  • getResponse(uint8_t* buffer, uint16_t bufferSize, uint16_t& receivedSize): Waits for, receives, validates, and processes a response packet from a device. Returns COMMUNICATION_SUCCESS or a negative error code. Fills buffer with payload and receivedSize with payload length on success
  • enableCRC32() / disableCRC32(): Manages the library's expectation of whether CRC32 should be included in outgoing commands. Note: The library automatically updates its internal CRC state based on the response character received from the device
  • isCRC32Enabled(): Returns true if the library currently expects CRC32 to be used
  • flush(): Discards any unread incoming serial data and waits for outgoing data to finish transmitting

Installation

  1. Download the Arduino library
  2. Import it into the Arduino IDE
  3. Include the library in your project by including "Servomotor.h"

Example Usage

A typical Arduino .ino or .cpp file might look like:

#include "Servomotor.h"

void setup() {
  Serial.begin(115200);  // For debug output

  // Create a Servomotor instance (note the lower-case 'm' - ServoMotor with a
  // capital M is a different, unrelated Arduino library)
  Servomotor motor('X', Serial1);  // Initialize with alias 'X' and Serial1 port
  
  // Set desired units (debug output will show the conversions)
  motor.setPositionUnit(PositionUnit::SHAFT_ROTATIONS);
  motor.setTimeUnit(TimeUnit::SECONDS);
  
  // Move 2 rotations over 3 seconds
  motor.trapezoidMove(2.0f, 3.0f);
}

void loop() {
  // ...
}

The debug output will show:

[Motor] Initialized with standard addressing, Alias: 88
[Motor] setPositionUnit called
[Motor] setTimeUnit called
[Motor] trapezoidMove called.
  displacement in chosen unit: 2.00
  duration in chosen unit: 3.00
[Motor] trapezoidMoveRaw called.

Two things to note about this output. The alias prints as its decimal character code, so 'X' appears as 88. And a unit-converting call such as trapezoidMove() prints several lines, because the wrapper echoes each argument and then calls the internal ...Raw() variant, which prints as well.

These messages are printed unconditionally by every command; there is currently no compile-time flag to switch them off. Bear that in mind before putting a command inside a fast polling loop.

Checking whether a command actually worked

No command method returns a success flag. Each one records the outcome of its last exchange with the motor, and you read it with getError():

motor.enableMosfets();
if (motor.getError() != 0) {
  Serial.print("enableMosfets failed, getError() = ");
  Serial.println(motor.getError());
}

getError() returns 0 on success, a positive value that is the motor's own fatal error code, or a negative value for a host-side communication failure (-1 is a timeout: wrong alias, wrong pins, motor unpowered, or motor in the bootloader). This matters because a motor that has latched a fatal error disables itself and silently ignores every later command except Get status and System reset — your sketch keeps running normally and the motor simply stops moving.

Watch out for one trap: when a read fails, the getters return a zero-initialised default rather than an error value. Serial.println(motor.getHallSensorPosition()) printing 0.00 can mean "the call failed", not "the shaft is at zero". Always check getError() before trusting a returned value.

See the Arduino Essentials section of the Servomotor Arduino API documentation for the full treatment, including the recommended startup sequence.

Important Usage Notes

Using moveWithVelocity and moveWithAcceleration: When using moveWithVelocity or moveWithAcceleration, you must queue a second move to stop the motor properly. If the final velocity is not zero when the queue becomes empty, the motor will trigger a fatal error.

Example with moveWithVelocity:

// First move at desired velocity
motor.moveWithVelocity(2.0f, 1.0f);  // 2 rotations/sec for 1 second

// Then queue a stop command
motor.moveWithVelocity(0.0f, 0.1f);  // 0 rotations/sec for 0.1 seconds

Example with moveWithAcceleration:

// First move with positive acceleration
motor.moveWithAcceleration(2.0f, 1.0f);  // 2 rotations/sec² for 1 second

// Then queue a move with negative acceleration to stop
motor.moveWithAcceleration(-2.0f, 1.0f);  // -2 rotations/sec² for 1 second

Using multiMove for Complex Motion Sequences: The multiMove function allows you to queue multiple velocity and acceleration moves in a single command. This is useful for creating complex motion sequences without having to send multiple commands.

There are two versions of the multiMove function:

  • multiMove: Handles unit conversions based on your configured units
  • multiMoveRaw: Uses raw internal units without conversion

The library provides two structures for defining move sequences:

  1. multiMoveListConverted_t: For user-friendly units with floating-point values

    typedef struct {
        float value;       // velocity or acceleration in user units
        float duration;    // duration in user units (seconds, milliseconds, etc.)
    } multiMoveListConverted_t;
    
  2. multiMoveList_t: For raw internal units

    typedef struct {
        int32_t value;     // acceleration or velocity value (internal units)
        uint32_t timeSteps; // duration in time steps (internal units)
    } multiMoveList_t;
    

Example with multiMove (using user units):

// Create a sequence of moves
const uint8_t multiMoveCount = 4;
uint32_t multiMoveTypes = 0b1001;  // 1st and 4th are velocity moves, 2nd and 3rd are acceleration moves

// Create move list with user units
multiMoveListConverted_t multiMoveList[multiMoveCount] = {
    {2.0f, 1.0f},    // Velocity move: 2 rot/sec for 1 sec
    {2.0f, 1.0f},    // Acceleration move: 2 rot/sec² for 1 sec
    {-2.0f, 1.0f},   // Acceleration move: -2 rot/sec² for 1 sec
    {0.0f, 0.1f}     // Velocity move: 0 rot/sec for 0.1 sec (stop)
};

// Execute the multi-move sequence with automatic unit conversion
motor.multiMove(multiMoveCount, multiMoveTypes, multiMoveList);

Example with multiMoveRaw (using internal units):

// Create a sequence of moves
const uint8_t multiMoveCount = 2;
uint32_t multiMoveTypes = 0b11;  // Both are velocity moves

// Create move list with internal units
// For velocity: CONVERSION_FACTOR_ROTATIONS_PER_SECOND = 109951162.777600005f
// For time: CONVERSION_FACTOR_SECONDS = 31250.000000000f
multiMoveList_t multiMoveList[multiMoveCount] = {
    {219902325, 31250},  // Velocity move: 2 rot/sec for 1 sec in internal units
    {0, 3125}            // Velocity move: 0 rot/sec for 0.1 sec in internal units
};

// Execute the multi-move sequence with raw units
motor.multiMoveRaw(multiMoveCount, multiMoveTypes, multiMoveList);

The moveTypes parameter is a 32-bit number where each bit specifies the type of move:

  • 0: MOVE_WITH_ACCELERATION
  • 1: MOVE_WITH_VELOCITY

For example, 0b1001 means the 1st and 4th moves are velocity moves, while the 2nd and 3rd are acceleration moves.

The last move in a sequence should always set the motor's velocity to 0 for a period of time (e.g., 0.1 seconds) to allow the motor to stop properly. Otherwise, the motor will enter a fatal error state when the queue becomes empty with a non-zero velocity on the motor.

Expected Position Calculation for Complex Sequences: When using a combination of velocity and acceleration moves, the final position can be calculated as follows:

  1. Velocity move: distance = velocity × duration
  2. Acceleration move:
    • Starting from a non-zero velocity: distance = (initial_velocity × duration) + (0.5 × acceleration × duration²)
    • Final velocity = initial_velocity + (acceleration × duration)

For example, in a sequence like:

multiMoveListConverted_t moves[4] = {
    {2.0f, 1.0f},    // Velocity move: 2 rot/sec for 1 sec
    {2.0f, 1.0f},    // Acceleration move: 2 rot/sec² for 1 sec
    {-2.0f, 1.0f},   // Acceleration move: -2 rot/sec² for 1 sec
    {0.0f, 0.1f}     // Velocity move: 0 rot/sec for 0.1 sec (stop)
};

The expected position calculation would be:

  1. Velocity move: 2 rot/sec × 1 sec = 2 rotations
  2. Acceleration move: Starting velocity 2 rot/sec, accelerating at 2 rot/sec²
    • Displacement = (2 rot/sec × 1 sec) + (0.5 × 2 rot/sec² × 1 sec²) = 2 + 1 = 3 rotations
    • Final velocity = 2 + (2 × 1) = 4 rot/sec
  3. Acceleration move: Starting velocity 4 rot/sec, decelerating at 2 rot/sec²
    • Displacement = (4 rot/sec × 1 sec) - (0.5 × 2 rot/sec² × 1 sec²) = 4 - 1 = 3 rotations
    • Final velocity = 4 - (2 × 1) = 2 rot/sec
  4. Velocity move: 0 rot/sec for 0.1 sec (stop)
    • Displacement = 0 rotations

Total displacement: 2 + 3 + 3 + 0 = 8 rotations

Testing

The library's test suite lives in Servomotor_TestSuite_ESP32S3/ (see its README for full details). It contains ~37 modular tests (tm_*.cpp, one per command group, ~580 assertions) that build TWO ways from the same sources:

  1. On-device (primary): all modules compile into one ESP32-S3 firmware that runs natively on the Gearotons ESP32-S3 RS485 controller — one test per boot, the ESP32 resets between tests, progress + pass/fail statistics persist in NVS, and a serial CLI triggers tests over the debug link.

    cd Servomotor_TestSuite_ESP32S3
    ./flash_suite.sh                 # refresh installed lib + compile + flash
    python3 run_suite_mac.py         # start a full run and collect results
    python3 run_suite_mac.py --only 5   # run a single test by index
    
  2. Host mode: the same modules compile on a desktop against the Arduino emulator (ArduinoEmulator.h) and talk to a motor through any USB-RS485 port — no flashing needed, useful for quick iteration and for testing a multi-motor bus from the desktop:

    cd Servomotor_TestSuite_ESP32S3
    ./build_host_suite.sh
    ./host_suite /dev/cu.usbserial-XXXX <16-hex-unique-id> all
    ./host_suite /dev/cu.usbserial-XXXX <16-hex-unique-id> multimove   # one test
    

Tests marked with known-bug annotations in test_registry.cpp assert the CORRECT behavior and are expected to fail until those library bugs are fixed; the suite summary counts them separately (unexpected=0 means a clean run).

TODO / Upcoming Changes

  1. Unit Conversion Tests to Implement (in order of priority)

    • test_position_conversions.cpp - Test position unit conversions in:

      • trapezoidMove / trapezoidMoveRaw
      • goToPosition / goToPositionRaw
      • getPosition / getPositionRaw
      • getHallSensorPosition / getHallSensorPositionRaw
      • getComprehensivePosition / getComprehensivePositionRaw
      • Multimove
    • test_time_conversions.cpp - Test time unit conversions in:

      • getCurrentTime / getCurrentTimeRaw
      • trapezoidMove (duration parameter)
      • goToPosition (duration parameter)
      • moveWithVelocity (duration parameter)
    • test_velocity_conversions.cpp - Test velocity unit conversions in:

      • setMaximumVelocity / setMaximumVelocityRaw
      • moveWithVelocity / moveWithVelocityRaw
    • test_acceleration_conversions.cpp - Test acceleration unit conversions in:

      • setMaximumAcceleration / setMaximumAccelerationRaw
      • moveWithAcceleration / moveWithAccelerationRaw
    • test_current_conversions.cpp - Test current unit conversions in:

      • setMaximumMotorCurrent / setMaximumMotorCurrentRaw
    • test_temperature_conversions.cpp - Test temperature unit conversions in:

      • getTemperature / getTemperatureRaw
    • test_limits_conversions.cpp - Test limit unit conversions in:

      • setSafetyLimits / setSafetyLimitsRaw
      • setMaxAllowablePositionDeviation / setMaxAllowablePositionDeviationRaw
  2. Code Generation Enhancements

    • ✅ Improve the autogeneration program that creates Servomotor.cpp and Servomotor.h
    • ✅ Make the code generation process more maintainable and flexible
    • ✅ Fix the conversion factors for current and voltage in the unit_conversions_M3.json file. Currently, these factors are missing or incorrect, resulting in a factor of 1.0 being used.
  3. Fix Some Problems With Servomotor.cpp, or Rather the Program that Generates this File, Which is generate_command_code.py

    • ✅ getComprehensivePosition obviously will return zeros, which is wrong. Seems the autogeneration program does not know how to convert this
    • ✅ getMaxPidError has the same problem
  4. Fix the Multimove Function

    • ✅ Fixed the moveList parameter type by defining a struct for move commands:
      typedef struct {
          int32_t value;  // acceleration or velocity value (internal units)
          uint32_t timeSteps;  // duration in time steps (internal units)
      } multiMoveList_t;
      
    • ✅ Added a new struct for user-friendly units with floating-point values:
      typedef struct {
          float value;  // velocity or acceleration in user units
          float duration;  // duration in user units (seconds, milliseconds, etc.)
      } multiMoveListConverted_t;
      
    • ✅ Implemented two versions of the multiMove function:
      • multiMoveRaw: Uses raw internal units without conversion
      • multiMove: Handles unit conversions based on configured units
    • ✅ Created example_multi_move.cpp to demonstrate how to use the multiMove function with a sequence of moves
    • ✅ Fixed the expected behavior calculation in example_multi_move.cpp to correctly account for velocity continuity between moves
    • ✅ Verified that the implementation works correctly with unit conversions
    • ✅ Created test_multi_move.cpp test program that extensively tests the multiMove and multiMoveRaw functions with all units for velocity, acceleration, and time
    • ✅ Added helper functions for calculating appropriate delay times for both user units and internal units
    • ✅ Updated documentation with detailed information about the multiMove functions, structures, and expected position calculations
    • ✅ Updated the autogeneration program (../autogeneration/generate_command_code.py) to correctly generate the Servomotor.h and Servomotor.cpp files with proper handling of list_2d type parameters in wrapper functions.
    • ✅ Verified that test_multi_move.cpp compiles and passes after the autogeneration program changes. All tests pass in fact.
  5. ✅ Rename ServomotorCommands.cpp to Servomotor.cpp (Completed)

    • ✅ Renamed ServomotorCommands.h to Servomotor.h
    • ✅ Updated all tests and programs to use Servomotor.h instead
    • ✅ Updated the generate_command_code.py script to generate the updated filenames
  6. test_unit_conversions test fails, need to fix

    • one test related to testAccelerationConversions() fails
  7. ✅ Make sure that the copy_stuff_to_Arduino.sh script copies all relevant file for the Arduino library to work

    • ✅ Updated the script to only copy core library files
    • ✅ Added proper handling of example files (example_one_move.cpp and example_one_move_two_motors.cpp)
    • ✅ Created proper Arduino library directory structure with src/ and examples/ folders
  8. Test the Arduino library on an actual Arduino board such as ESP32-C3

    • ✅ see if it compiles
    • ✅ see if it can control an actual motor
  9. Create more Arduino examples

    • Create additional simple examples for common use cases
    • Ensure examples demonstrate best practices for using the library
    • Consider examples for different motor control scenarios
  10. Launch this Arduino library into the Arduino marketplace

    • Anyone on the internet familiar with the Arduino IDE should be able to get it and easily use it
  11. Revamp the test_unit_conversion.cpp test

    • this test should do unit conversions in one direction (given unit to internal unit) and in the other direction (internal to given unit)
    • it should check the converted value against the validation numbers in the ../python_programs/servomotor/unit_conversions_M3.json file
    • the test should read in the above json file on the fly to get all units to be tested as well as the validation values
  12. Clean up magic numbers in the tests

  • ✅ many values look like magic numbers but are just a multiple of the MICROSTEPS_PER_ROTATION, so we should place a #define in the test for the MICROSTEPS_PER_ROTATION and then derive validation number based on this
  1. Revamp how magic numbers are defined in the AutoGeneratedUnitConversions.x files
  • ✅ Magic numbers should be moved to AutoGeneratedUnitConversions.h and should follow a simular naming convention as in the source file where the data is taken from, which is from the json file that is given as a parameter to generate_unit_conversion_code.py, where currently that file is ../python_programs/servomotor/unit_conversions_M3.json AutoGeneratedUnitConversions.cpp should be refined to use the #defines instead of holding the magic numbers within the functions.
  • ✅ For conversion that are more complex than multiplying or dividing by a scaling factor (temperature conversion being an exmaple), we need to add another field to ../python_programs/servomotor/unit_conversions_M3.json where we indicate an additional factor that is added. Please propse the new structure of the json file and let me confirm it.
  • ✅ Since ../python_programs/servomotor/unit_conversions_M3.json is also an autogenerated program, we will need to modify the program that autogenerates this, which is ../python_programs/servomotor/autogenerate_unit_conversions.py
  1. Unify autogeneration programs into one main executable
  • ✅ The current autogeneration programs are these: ../python_programs/servomotor/autogenerate_unit_conversions.py generate_unit_conversion_code.py generate_command_code.py ../firmware/generate_lookup_tables/BLDC_sin_lookup_table.py ../firmware/generate_lookup_tables/compute_hall_sensor_constants.py (this program needs to have a new parameter to specify if new weights should be calculated or skipped)
  • ✅ These should be moved to a separate directory in the root called autogeneration. All autogeneration programs should be moved into there.
  • ✅ a single executable called autogenerate.py should be created that essentially runs all of the other programs.
  • Optionally, the other programs should become Python modules that are called by importing them into the autogenerate.py program
  1. The Aurduino Library should have a optional verbose mode
  • Currently by deafault it is too verbose
  • Need a flag that is configurable by the user at compile time
  • The flag shoild affect hot Servomotor.cpp is compiled into the Arduino project
  • We can modify Servomotor.cpp manually at first to try out method but later we must modify the autogeneration program, which is ../autogeneration/generate_command_code.py
  1. Remove the commandID magic numbers from Servomotor.cpp
  • ✅ For example, this line: const uint8_t commandID = 14; should become: const uint8_t commandID = CMD_HOMING; after the change.
  • ✅ Make sure to change the autogeneration program called ../autogeneration/generate_command_code.py and not Servomotor.cpp directly
  • ✅ Make sure that all tests pass after the change

License

This library is released under the MIT License. See the LICENSE file for details.

Author

Tom Rodinger (tom@gearotons.com)