Unit Conversions
The TMC51x0 driver (TMC5130 & TMC5160) works internally with steps, but most applications need to work with physical units like millimeters, degrees, RPM, or revolutions per second. This guide shows how to use the unit conversion functions and unit-aware API to work with intuitive units.
Important: All unit-aware functions require explicit unit specification. Always specify the unit parameter to ensure clarity and prevent accidental use of step-based values.
Overview
The driver provides unit-aware functions and free conversion functions for working with:
- Physical units: millimeters, degrees, RPM, revolutions per second (RevPerSec), mm/s, mm/sΒ²
- Driver units: steps, steps/s, steps/sΒ²
Note: All unit-aware functions require explicit unit specification. Recommended units: Unit::Deg for position, Unit::RPM for velocity, and Unit::RevPerSec for acceleration.
All conversion functions require knowledge of your motorβs steps per revolution and mechanical system parameters (e.g., lead screw pitch).
When to Use Unit Conversions
- β Setting target positions in millimeters for lead screw systems
- β Setting speeds in RPM instead of steps per second
- β Working with belt drives using pulley teeth
- β Converting encoder readings to physical positions
- β Low-level register access (use raw steps)
- β When maximum performance is critical (direct step calculations may be faster)
Basic Usage
Including the Header
1
#include "tmc51x0/features/tmc51x0_units.hpp"
Lead Screw Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Motor: 200 steps/rev, Lead screw: 2mm pitch
constexpr uint16_t STEPS_PER_REV = 200;
constexpr float LEAD_SCREW_PITCH_MM = 2.0f;
// Move 10mm
int32_t steps = tmc51x0::MmToSteps(10.0f, STEPS_PER_REV, LEAD_SCREW_PITCH_MM);
driver.rampControl.SetTargetPosition(steps);
// Or use SetTargetPosition with Unit parameter (requires mechanical system in DriverConfig)
driver.rampControl.SetTargetPosition(10.0f, tmc51x0::Unit::Mm);
// Get current position in mm
auto pos_result = driver.rampControl.GetCurrentPosition(tmc51x0::Unit::Mm);
if (pos_result) {
float current_mm = pos_result.Value();
// Use current_mm
} else {
printf("Error reading position: %s\n", pos_result.ErrorMessage());
}
Speed in Revolutions Per Second (Recommended Default)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Set maximum speed to 0.5 rev/s (30 RPM) - Unit::RevPerSec is now the default
driver.rampControl.SetMaxSpeed(0.5f); // No unit parameter needed!
// Or explicitly specify the unit
driver.rampControl.SetMaxSpeed(0.5f, tmc51x0::Unit::RevPerSec);
// Or use RPM (converts to rev/s internally)
driver.rampControl.SetMaxSpeed(30.0f, tmc51x0::Unit::Rpm); // 30 RPM = 0.5 rev/s
// Or use degrees per second
driver.rampControl.SetMaxSpeed(180.0f, tmc51x0::Unit::Deg); // 180 deg/s = 0.5 rev/s
// Or convert manually (if needed)
float steps_per_sec = tmc51x0::RpmToStepsPerSec(30.0f, STEPS_PER_REV);
driver.rampControl.SetMaxSpeed(steps_per_sec, tmc51x0::Unit::Steps);
Belt Drive Example
1
2
3
4
5
6
// Motor: 200 steps/rev, Pulley: 20 teeth
constexpr uint16_t PULLEY_TEETH = 20;
// Move 100 belt teeth
int32_t steps = tmc51x0::BeltTeethToSteps(100, STEPS_PER_REV, PULLEY_TEETH);
driver.rampControl.SetTargetPosition(steps);
Available Conversion Functions
Position Conversions
| Function | Description | Example |
|---|---|---|
MmToSteps() |
Convert mm to steps | MmToSteps(10.0f, 200, 2.0f) |
StepsToMm() |
Convert steps to mm | StepsToMm(1000, 200, 2.0f) |
DegreesToSteps() |
Convert degrees to steps | DegreesToSteps(90.0f, 200) |
StepsToDegrees() |
Convert steps to degrees | StepsToDegrees(50, 200) |
BeltTeethToSteps() |
Convert belt teeth to steps | BeltTeethToSteps(100, 200, 20) |
StepsToBeltTeeth() |
Convert steps to belt teeth | StepsToBeltTeeth(1000, 200, 20) |
Speed Conversions
| Function | Description | Example |
|---|---|---|
RpmToStepsPerSec() |
Convert RPM to steps/s | RpmToStepsPerSec(100.0f, 200) |
StepsPerSecToRpm() |
Convert steps/s to RPM | StepsPerSecToRpm(333.3f, 200) |
MmPerSecToStepsPerSec() |
Convert mm/s to steps/s | MmPerSecToStepsPerSec(10.0f, 200, 2.0f) |
StepsPerSecToMmPerSec() |
Convert steps/s to mm/s | StepsPerSecToMmPerSec(333.3f, 200, 2.0f) |
Note: The driver now supports Unit::RevPerSec (revolutions per second) as the default unit for velocity functions. This makes it much easier to work with intuitive units without manual conversions. For example:
SetMaxSpeed(0.5f)sets speed to 0.5 rev/s (30 RPM) - no unit parameter needed!SetMaxSpeed(30.0f, Unit::Rpm)also works and converts automaticallySetMaxSpeed(180.0f, Unit::Deg)sets speed to 180 deg/s (0.5 rev/s)
Acceleration Conversions
| Function | Description | Example |
|---|---|---|
AccelerationMmToSteps() |
Convert mm/sΒ² to steps/sΒ² | AccelerationMmToSteps(100.0f, 200, 2.0f) |
AccelerationStepsToMm() |
Convert steps/sΒ² to mm/sΒ² | AccelerationStepsToMm(5000.0f, 200, 2.0f) |
Complete Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include "tmc51x0.hpp"
#include "tmc51x0/features/tmc51x0_units.hpp"
// Motor and mechanical system parameters
constexpr uint16_t STEPS_PER_REV = 200; // 1.8Β° stepper
constexpr float LEAD_SCREW_PITCH_MM = 2.0f; // 2mm pitch lead screw
void setupMotor() {
// Initialize driver with mechanical system configuration
tmc51x0::DriverConfig cfg{};
cfg.motor_spec.steps_per_rev = STEPS_PER_REV;
cfg.mechanical.system_type = tmc51x0::MechanicalSystemType::LeadScrew;
cfg.mechanical.lead_screw_pitch_mm = LEAD_SCREW_PITCH_MM;
auto init_result = driver.Initialize(cfg);
if (!init_result) {
printf("Initialization error: %s\n", init_result.ErrorMessage());
return; // or handle error appropriately
}
// Set speeds in revolutions per second (default unit - no parameter needed!)
auto speed_result = driver.rampControl.SetMaxSpeed(1.67f); // 1.67 rev/s = 100 RPM - Unit::RevPerSec is default
if (!speed_result) {
printf("Error setting max speed: %s\n", speed_result.ErrorMessage());
return;
}
// Or use RPM (converts automatically)
auto rpm_result = driver.rampControl.SetMaxSpeed(100.0f, tmc51x0::Unit::Rpm);
if (!rpm_result) {
printf("Error setting max speed: %s\n", rpm_result.ErrorMessage());
return;
}
// Set acceleration in rev/sΒ² (default unit)
auto accel_result = driver.rampControl.SetAcceleration(0.83f); // 0.83 rev/sΒ² - Unit::RevPerSec is default
if (!accel_result) {
printf("Error setting acceleration: %s\n", accel_result.ErrorMessage());
return;
}
// Or use mm/sΒ² (uses mechanical system from DriverConfig)
auto accel_mm_result = driver.rampControl.SetAcceleration(50.0f, tmc51x0::Unit::Mm); // 50 mm/sΒ²
if (!accel_mm_result) {
printf("Error setting acceleration: %s\n", accel_mm_result.ErrorMessage());
return;
}
}
void moveToPosition(float target_mm) {
// Move to position in millimeters (uses mechanical system from DriverConfig)
auto pos_result = driver.rampControl.SetTargetPosition(target_mm, tmc51x0::Unit::Mm);
if (!pos_result) {
printf("Error setting target position: %s\n", pos_result.ErrorMessage());
return; // or handle error appropriately
}
// Wait for completion
while (true) {
auto reached = driver.rampControl.IsTargetReached();
if (reached && reached.Value()) {
break; // Target reached
}
if (!reached) {
printf("Error checking target: %s\n", reached.ErrorMessage());
break;
}
// Monitor position in mm (uses mechanical system from DriverConfig)
auto pos_result2 = driver.rampControl.GetCurrentPosition(tmc51x0::Unit::Mm);
if (pos_result2) {
printf("Current position: %.2f mm\n", pos_result2.Value());
} else {
printf("Error reading position: %s\n", pos_result2.ErrorMessage());
// Continue monitoring despite read error
}
}
}
Performance Considerations
- Compile-time evaluation: All conversion functions are
constexprand can be evaluated at compile time for constant inputs - Runtime overhead: Minimal - simple arithmetic operations
- Precision: Uses
floatfor physical units,int32_tfor steps
Troubleshooting
Incorrect Movement Distance
Problem: Motor moves wrong distance
Solution:
- Verify
steps_per_revmatches your motor (typically 200 for 1.8Β° motors) - Check mechanical system parameters (lead screw pitch, pulley teeth)
- Ensure consistent units (mm vs inches)
Speed Too Fast/Slow
Problem: Motor speed doesnβt match expected RPM
Solution:
- Verify
steps_per_revis correct - Check the configured microstep resolution (
chopper.mres) - If you change microstep resolution (MRES) at runtime, do it at standstill:
- The driver will preserve physical meaning by default (position + ramp profile are rescaled)
- If you intentionally want a "raw" change (no rescaling), use
SetMicrostepResolution()withMicrostepChangeOptions{ .preserve_physical_units = false }
Quick Verification: MRES Change Preserves Physical Units
At standstill:
- Record position in full steps:
GetCurrentPosition(Unit::Steps) - Record configured max speed in RPM:
GetCurrentSpeed(Unit::RPM)(or track your configured VMAX) - Change MRES (e.g. 256 β 128) using
SetMicrostepResolution() - Verify:
GetCurrentPosition(Unit::Steps)is unchanged- A move of N full steps still moves the same physical distance
Note on Quantization and Rounding
All motion and position settings are ultimately written to integer-valued driver registers.\nThis means values expressed in real units (RPM/deg/mm) are quantized to the nearest representable register value.\nThe driver uses a consistent policy of round-to-nearest (ties away from zero) when converting float inputs to register values.\n
Navigation <- Examples | Next: Motor Setup -> | Back to Index