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, andtest_get_temperature.cpp.
The library includes several Python scripts for code generation and maintenance:
generate_unit_conversion_code.py: Generates unit conversion code from a JSON configurationgenerate_command_code.py: Generates command interface code
Below is an updated overview of the key files after renaming and restructuring:
| File | Description |
|---|---|
| ArduinoEmulator.h | Emulates Arduino's Serial, delay(), etc. for desktop builds. |
| AutoGeneratedUnitConversions.h / .cpp | Functions to convert between various units (time, position, velocity, acceleration, etc.). |
| Commands.h | Autogenerated list of servo command IDs. |
| Communication.h / .cpp | Simple Communication class for sending/receiving commands (stubbed for testing). |
| DataTypes.h / .cpp | Definitions of data type structures and bounds. |
| Utils.h / .cpp | Helper utilities for endianness, packing, and general-purpose functionality. |
| Servomotor.h / .cpp | Main servo control class with features like calibration, homing, e-stop, etc. |
| test_one_move.cpp | Minimal example demonstrating a single trapezoid move (2 rotations over 3 seconds). |
| test_unit_conversions.cpp | Desktop test verifying unit-conversion logic in AutoGeneratedUnitConversions.*. |
| test_get_temperature.cpp | Example demonstrating how to read temperature from the motor. |
| test_emergency_stop.cpp | Test for emergency stop functionality to ensure proper queue clearing and MOSFET disabling. |
| test_move_with_velocity.cpp | Test for moveWithVelocity functionality with different units (rotations, degrees, encoder counts). |
| test_enable_disable_mosfets.cpp | Test for enabling and disabling MOSFETs. |
| test_one_move_two_motors.cpp | Example demonstrating control of two motors simultaneously. |
-
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)
- Centralizes all unit transformations in
-
Communication Module
Communication.cppis a lightweight stub for sending commands and reading responses. It can be extended or replaced with a hardware-specific protocol (RS-485, UART, etc.).
-
Servo Control Class
ServoMotorprovides:- 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
-
Testing on Desktop vs. Arduino
- If
ARDUINOmacros are defined,<Arduino.h>is used for real hardware. - Otherwise,
ArduinoEmulator.hprovides 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.
- If
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).
All packets follow this basic structure:
-
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
- First byte:
-
Address Bytes:
- Standard Addressing: Single byte containing device alias
255(ALL_ALIAS): Broadcasts to all devices254(EXTENDED_ADDRESSING): Indicates extended addressing mode253and252are 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)
- Standard Addressing: Single byte containing device alias
-
Command Byte: 8-bit command identifier
-
Payload Data: Variable length data specific to the command
-
CRC32: Optional 4-byte CRC32 checksum (enabled by default but can be disabled)
Responses from devices follow this structure:
-
Size Bytes: Same format as command packet
-
Response Character: Single byte indicating response and CRC32 state
253(RESPONSE_CHARACTER_CRC32_ENABLED): Response from device with CRC32 enabled252(RESPONSE_CHARACTER_CRC32_DISABLED): Response from device with CRC32 disabled
-
Command Byte: 8-bit value indicating status
0: Success and there is no firther data in the response1: Success and there is some further data in the response- Other values: Currently not used and reserved for future use
-
Payload Data: Variable length response data
-
CRC32: Optional 4-byte checksum (enabled by default but can be disabled)
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_COMMANDto the device
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 sizeCOMMUNICATION_ERROR_BAD_RESPONSE_CHAR(-3): The response character byte was notRESPONSE_CHARACTER_CRC32_ENABLED (253)orRESPONSE_CHARACTER_CRC32_DISABLED (252)COMMUNICATION_ERROR_BUFFER_TOO_SMALL(-5): The provided buffer size did not match the calculated payload size in the received responseCOMMUNICATION_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 dataCOMMUNICATION_ERROR_BAD_THIRD_BYTE(-8): The third byte in the response (expected to be the Command Byte) was invalid
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.
- Controller sends command packet
- Device receives and processes command
- Device sends response packet (if required)
- Controller receives and validates response
The Communication class provides the following key methods:
Communication(HardwareSerial& serialPort): Constructor, requires aHardwareSerialport (e.g.,Serial1)sendCommand(uint8_t alias, uint8_t commandID, const uint8_t* payload, uint16_t payloadSize): Sends a command using standard alias addressingsendCommandByUniqueId(uint64_t uniqueId, uint8_t commandID, const uint8_t* payload, uint16_t payloadSize): Sends a command using extended 64-bit Unique ID addressinggetResponse(uint8_t* buffer, uint16_t bufferSize, uint16_t& receivedSize): Waits for, receives, validates, and processes a response packet from a device. ReturnsCOMMUNICATION_SUCCESSor a negative error code. Fillsbufferwith payload andreceivedSizewith payload length on successenableCRC32() / 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 deviceisCRC32Enabled(): Returns true if the library currently expects CRC32 to be usedflush(): Discards any unread incoming serial data and waits for outgoing data to finish transmitting
- Download the Arduino library
- Import it into the Arduino IDE
- Include the library in your project by including "Servomotor.h"
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
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] Serial1 initialized at 230400 baud.
[Motor] setPositionUnit to SHAFT_ROTATIONS
[Motor] setTimeUnit to SECONDS
[Motor] trapezoidMove called.
distance in chosen unit: 2
time in chosen unit: 3
-> distance in encoder_counts: 6.5536e+06
-> duration in timesteps: 93750
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 secondsExample 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 secondUsing 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 unitsmultiMoveRaw: Uses raw internal units without conversion
The library provides two structures for defining move sequences:
-
multiMoveListConverted_t: For user-friendly units with floating-point valuestypedef struct { float value; // velocity or acceleration in user units float duration; // duration in user units (seconds, milliseconds, etc.) } multiMoveListConverted_t;
-
multiMoveList_t: For raw internal unitstypedef 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:
- Velocity move: distance = velocity × duration
- 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:
- Velocity move: 2 rot/sec × 1 sec = 2 rotations
- 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
- 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
- Velocity move: 0 rot/sec for 0.1 sec (stop)
- Displacement = 0 rotations
Total displacement: 2 + 3 + 3 + 0 = 8 rotations
The library includes an Arduino emulator (ArduinoEmulator.h and ArduinoEmulator.cpp) that allows testing on desktop machines without actual hardware. Test files include:
test_unit_conversions.cpp: Validates unit conversion accuracytest_one_move.cpp: Demonstrates unit conversions and motor control with detailed debug outputtest_get_temperature.cpp: Demonstrates reading temperature from the motortest_emergency_stop.cpp: Tests emergency stop functionalitytest_move_with_velocity.cpp: Tests moveWithVelocity functionality with different units (rotations, degrees, encoder counts) and includes comprehensive error checkingtest_move_with_acceleration.cpp: Tests moveWithAcceleration functionality with different units (rotations, degrees, radians, counts) and ensures proper stopping
The test framework (test_framework.h and test_framework.cpp) provides utilities for test reporting and error checking:
TEST_RESULTmacro: Reports test results with pass/fail statuscheckMotorErrorfunction: Checks for communication errors after motor commands and provides detailed error messages
To compile the test programs, use the provided build_tests.sh script which handles linking all necessary dependencies:
# Run the script to build all test programs
./build_tests.shThe build_tests.sh script:
- Automatically builds ALL test programs in the project (does not accept parameters)
- Defines common source files needed by all tests
- Sets compiler flags (C++17 standard)
- Adds the REQUIRE_SERIAL_PORT flag for tests that need hardware communication
- Creates executable files with the same name as the test file (without the .cpp extension)
After building the tests, you can run them individually or use the run_all_tests.sh script to run all tests:
# Run all tests with default settings (alias 'X' and unique ID '0123456789ABCDEF')
./run_all_tests.sh
# Run all tests with a specific serial port
./run_all_tests.sh -p /dev/ttys004
# Run all tests with a specific alias
./run_all_tests.sh -a Y
# Run all tests with a specific unique ID
./run_all_tests.sh -u FEDCBA9876543210
# Run all tests in alias mode only
./run_all_tests.sh -s -a X
# Run all tests in unique ID mode only
./run_all_tests.sh -s -u 0123456789ABCDEFThe run_all_tests.sh script:
- By default, runs each test twice: once with alias addressing and once with unique ID addressing
- Provides command-line options to customize the test execution:
-p, --port PORT: Specify the serial port to use (default: /dev/ttys014)-a, --alias ID: Specify the alias to use (default: X)-u, --unique-id ID: Specify the unique ID to use (default: 0123456789ABCDEF)-s, --single-mode: Run tests only in the mode specified by -a or -u-h, --help: Show help message
You can also run individual test programs directly. Most test programs require a serial port parameter because they interact with the physical motor or the motor simulator:
# Example: Run the emergency stop test with a serial port
./test_emergency_stop /dev/ttys004 X # On macOS, using alias 'X'
./test_emergency_stop /dev/ttys004 0123456789ABCDEF # On macOS, using Unique ID
./test_emergency_stop /dev/ttyUSB0 X # On Linux, using alias 'X'
./test_emergency_stop COM3 X # On Windows, using alias 'X'The serial port parameter is required for any test that communicates with the motor. This includes all movement tests, status queries, and configuration commands. The only tests that might not require a serial port are those that exclusively test unit conversions without motor communication.
Each test program requires:
- C++17 standard (-std=c++17)
- REQUIRE_SERIAL_PORT define for hardware communication
- Linking with core library source files (ArduinoEmulator.cpp, Servomotor.cpp, etc.)
-
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
-
-
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.
-
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
-
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 conversionmultiMove: 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.
- ✅ Fixed the moveList parameter type by defining a struct for move commands:
-
✅ 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
-
test_unit_conversions test fails, need to fix
- one test related to testAccelerationConversions() fails
-
✅ 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
-
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
-
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
-
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
-
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
-
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
- 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
- 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
- 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
- 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
This library is released under the MIT License. See the LICENSE file for details.
Tom Rodinger (tom@gearotons.com)