A C++ library for simulating Feetech servo motor actuators without real hardware. This system provides realistic motor physics simulation, protocol-level communication, and comprehensive testing capabilities for development and testing purposes.
Note: This is a simulation-only library. It does not connect to real hardware - all motor behavior is simulated through physics models and mock serial communication.
- Realistic Physics Simulation: Acceleration profiles, inertia, temperature modeling, voltage fluctuations
- Protocol Simulation: Complete Feetech SCS/STS protocol with checksum validation over mock serial
- Mock Serial Communication: Simulated serial buffers for protocol testing
- Thread-Safe Design: Safe for concurrent access and multi-motor systems
- Comprehensive Testing: Unit tests and example programs demonstrating all features
┌─────────────────────────────────────────┐
│ FeetechActuator (High-Level API) │
│ setPosition() | getPosition() | etc. │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ FeetechProtocol (Packet Handler) │
│ Encoding | Decoding | Timeout │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ MockSerialBuffer (Simulated Serial) │
│ Thread-safe circular buffer pairs │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ MotorSimulator (Physics Engine) │
│ Position | Velocity | Temperature │
└─────────────────────────────────────────┘
How it Works:
MotorSimulatorprovides realistic physics (acceleration, load, temperature)MockSerialBuffersimulates bidirectional serial communicationFeetechProtocolhandles packet encoding/decoding over the mock serialFeetechActuatorprovides high-level motor control API- All components work together to simulate real motor behavior without hardware
- C++17 compatible compiler (GCC 7+, Clang 6+, MSVC 2017+)
- CMake 3.16 or later
- (Optional) Google Test for unit tests
mkdir build && cd build
cmake ..
make -j$(nproc)# Basic position control
./basic_control
# Position tracking with data logging
./position_tracking
# Multi-motor coordination
./multi_motorcd build
ctest --output-on-failure#include "driver/FeetechActuator.hpp"
#include "driver/MotorSimulator.hpp"
#include "transport/MockSerialBuffer.hpp"
using namespace motor_sim;
int main() {
// Create simulated serial connection (no real hardware needed)
auto [host_port, device_port] = transport::createSerialPair();
// Create motor physics simulator
auto motor_sim = std::make_shared<driver::MotorSimulator>();
// Create actuator interface (simulation-only, no real Feetech motor)
driver::FeetechActuator actuator(1, host_port, motor_sim);
// Initialize and control the simulated motor
actuator.initialize();
actuator.setTorqueEnable(true);
actuator.setPositionDegrees(90.0f);
return 0;
}For realistic protocol testing, run a device simulator in the background:
// Device simulator responds to protocol commands
class DeviceSimulator {
void run() {
while (running_) {
motor_->update(0.01f); // Update physics
processIncomingPackets(); // Handle commands
}
}
};
DeviceSimulator device(device_port, motor_sim);
device.start(); // Runs in background thread
// Now actuator.setPosition() will trigger realistic responsesbool setPosition(uint16_t position, bool wait = false);
std::optional<uint16_t> getPosition();
bool setPositionDegrees(float degrees, bool wait = false);
std::optional<float> getPositionDegrees();bool setSpeed(uint16_t speed);
std::optional<uint16_t> getSpeed();
bool setSpeedRPM(float rpm);bool setAngleLimits(uint16_t cw, uint16_t ccw);
bool setTorqueEnable(bool enable);
bool setLED(bool on);std::optional<uint8_t> getTemperature();
std::optional<uint8_t> getVoltage();
std::optional<uint16_t> getLoad();
std::optional<bool> isMoving();void update(float dt); // Call at ~100Hz for realistic simulationvoid setGoalPosition(uint16_t position);
void setTorqueEnable(bool enable);
void setAngleLimits(uint16_t cw, uint16_t ccw);void injectError(ErrorFlag error);
void clearErrors();
void reset();[0xFF][0xFF][ID][LEN][INSTR][PARAM...][CHECKSUM]
- Header: 0xFF 0xFF
- ID: Motor ID (1-253)
- Length: Instruction + Parameters + Checksum
- Instruction: Command type (PING, READ, WRITE, etc.)
- Parameters: Command-specific data
- Checksum: ~(ID + Length + Instruction + Parameters)
PING(0x01): Check motor presenceREAD_DATA(0x02): Read from memoryWRITE_DATA(0x03): Write to memoryRESET(0x06): Factory reset
Key registers:
GOAL_POSITION(46-47): Target position (0-4095)GOAL_SPEED(48-49): Moving speedPRESENT_POSITION(56-57): Current positionPRESENT_TEMPERATURE(63): Temperature in °CTORQUE_ENABLE(40): Enable/disable torque
cd build
./unit_testsTests cover:
- Circular buffer operations
- Mock serial communication
- Protocol packet encoding/decoding
- Motor physics simulation
- Checksum validation
Create end-to-end tests combining all layers:
TEST(IntegrationTest, FullStack) {
auto [host, device] = createSerialPair();
auto sim = std::make_shared<MotorSimulator>();
DeviceSimulator dev(device, sim);
dev.start();
FeetechActuator actuator(1, host, sim);
ASSERT_TRUE(actuator.ping());
ASSERT_TRUE(actuator.setPosition(2048));
dev.stop();
}motor_sim->injectError(ErrorFlag::OVERHEATING);
// Motor will respond with error statusMotorSimulator::PhysicsConfig config;
config.max_acceleration = 1000.0f;
config.thermal_coefficient = 0.02f;
config.position_noise = 1.0f;
MotorSimulator sim(initial_state, config);actuator.setErrorCallback([](uint8_t error, const std::string& msg) {
std::cerr << "Motor error: " << msg << std::endl;
});
actuator.setPositionCallback([](uint16_t position) {
std::cout << "Position: " << position << std::endl;
});- Model number, firmware version
- Angle limits (CW/CCW)
- Temperature/voltage limits
- Max torque
- Acceleration limits
- Velocity limits
- Thermal properties
- Noise characteristics
if (!actuator.ping()) {
// Check serial connection
// Verify motor ID
// Check if device simulator is running
}// Ensure torque is enabled
actuator.setTorqueEnable(true);
// Check if in valid range
actuator.setAngleLimits(0, 4095);
// Update simulation
motor_sim->update(0.01f);// Enable debug logging
Logger::getInstance().setLevel(LogLevel::DEBUG);
// Check for communication errors
buffer->injectError(); // Test error handling- Update Rate: 100-1000 Hz typical
- Latency: <1ms (simulated)
- Memory: ~100KB per motor instance
- Thread Safety: Full concurrent access support
- ROS 2 integration
- Real-time plotting tools
- Trajectory planning utilities
- Multi-protocol support (Dynamixel, etc.)
- Hardware-in-the-loop testing
- Python bindings
Contributions welcome! Please ensure:
- Code follows existing style
- All tests pass
- New features include tests
- Documentation is updated
MIT License - See LICENSE file for details
- Feetech SCS Series Manual
- Serial Communication Protocol Design
- Professional Robotics Software Architecture Patterns
For questions or support, please open an issue on the project repository.
Built with ❤️ for robotics development and testing