Wiki Search Terms
Servo issues, servo jerk, servo smooth movement
Controller Board
TMC2209 Pen/Laser CNC Controller
Machine Description
The wall drawing XY-plotter- BOTSY with a micro servo motor.
Input Circuits
Configuration file
z:
stepspermm: 400
maxratemmpermin: 8000
accelerationmmper_sec2: 3000
maxtravelmm: 30
soft_limits: true
homing:
cycle: 0
allowsingleaxis: true
positive_direction: false
mpos_mm: 0
feedmmper_min: 2000
seekmmper_min: 2000
settle_ms: 500
seek_scaler: 1.1
feed_scaler: 1.1
motor0:
limitnegpin: NO_PIN
limitpospin: NO_PIN
limitallpin: NO_PIN
hard_limits: false
pulloff_mm: 0.1
rc_servo:
pwm_hz: 50
output_pin: gpio.21
minpulseus: 2000
maxpulseus: 1000
timer_ms: 5
Startup Messages
>>> $ss
[MSG:INFO: FluidNC v3.9.6 https://github.com/bdring/FluidNC]
[MSG:INFO: Compiled with ESP32 SDK:v4.4.7-dirty]
[MSG:INFO: Local filesystem type is spiffs]
[MSG:INFO: Configuration file:BOTSYARTv4Amacros2.yaml]
[MSG:WARN: X Axis tmc_2209 homing current not in config. Using run current]
[MSG:WARN: Y Axis tmc_2209 homing current not in config. Using run current]
[MSG:INFO: Machine BOTSY Apr 17, 2025]
[MSG:INFO: Board FluidNC Pen/Laser 2209 V2]
[MSG:INFO: UART1 Tx:gpio.17 Rx:gpio.16 RTS:NO_PIN Baud:115200]
[MSG:INFO: UART2 Tx:gpio.4 Rx:gpio.15 RTS:NO_PIN Baud:5000000]
[MSG:INFO: uart_channel2 created at report interval: 75]
[MSG:INFO: SPI SCK:gpio.18 MOSI:gpio.23 MISO:gpio.19]
[MSG:INFO: SD Card cspin:gpio.5 detect:NOPIN freq:8000000]
[MSG:INFO: Stepping:RMT Pulse:3us Dsbl Delay:0us Dir Delay:1us Idle Delay:5ms]
[MSG:INFO: Axis count 3]
[MSG:INFO: Shared stepper disable gpio.13]
[MSG:INFO: Axis X (-1220.000,0.000)]
[MSG:INFO: Motor0]
[MSG:INFO: tmc2209 UART1 Addr:0 CS:NOPIN Step:gpio.14 Dir:gpio.12 Disable:NO_PIN R:0.110]
[MSG:INFO: Neg Limit gpio.36:low]
[MSG:INFO: Motor1]
[MSG:INFO: Axis Y (-2000.000,0.000)]
[MSG:INFO: Motor0]
[MSG:INFO: tmc2209 UART1 Addr:1 CS:NOPIN Step:gpio.25 Dir:gpio.26 Disable:NO_PIN R:0.110]
[MSG:INFO: Neg Limit gpio.39:low]
[MSG:INFO: Motor1]
[MSG:INFO: Axis Z (0.000,30.000)]
[MSG:INFO: Motor0]
[MSG:INFO: rc_servo Pin:gpio.21 Pulse Len(2000,1000 period:1048575)]
[MSG:INFO: Update timer for rc_servo at 5 ms]
[MSG:INFO: X Axis driver test passed]
[MSG:INFO: Y Axis driver test passed]
[MSG:INFO: safetydoorpin gpio.33:low]
[MSG:INFO: feedholdpin gpio.35:low]
[MSG:INFO: cyclestartpin gpio.34:low]
[MSG:INFO: Kinematic system: Cartesian]
[MSG:INFO: BT Started with FluidNC]
[MSG:INFO: Laser Ena:gpio.2 Out:gpio.27 Freq:5000Hz Period:8191]
ok
User Interface Software
UGS Platform, step size Z: 3 inch, feed rate: 8,000
What happened?
Bart,
Using Z-jog from the UGS Platform, I’m experiencing a servo glitch—please see the attached video.
The servo PWM normally switches between two values: 1ms (two columns) and 2ms (four columns). I press Z+ and Z– from the UGS Platform, and the servo executes the jog commands correctly a few times times. Then suddenly, the PWM signal becomes incorrect—either 0.5ms or 1.5ms. This happens if I press Z+/- quickly and slowly.
I’ve tested three different mini-servo models with different operating currents, including a brand-name Futaba, and the glitch occurs with all of them.
Also, I’ve noticed that the servo arm often jerks slightly in the opposite direction before beginning its movement.
Any suggestions would be greatly appreciated.
https://github.com/user-attachments/assets/70a1ccdc-81e6-439d-b575-1ae1eb03238e
GCode File
Z-Jog commands:
Z+: $J=G20G91Z3F8000
Z-: $J=G20G91Z-3F8000
Other Information
No response
评论 (18)
#2 – Liizam 于 2025-05-20
I’ve been testing servo behavior using various timer_ms settings. I measured the number of correct arm movements (from 0° to 90° and back) versus glitch actions**. The most reliable performance occurred at:
* timer_ms = 5, with a Z step = 1 inch and Z feed rate = 8000. I achieved over 100 successful Z-jogs in UGS.
* timer_ms = 10, same Z step and feed rate. Success ratios were approximately 62:1, 51:1, and 24:1 (correct\:glitch).
* timer_ms = 100 produced unreliable results, with ratios around 1:1 or 2:1.
Additionally, I noticed that the servo movement range is affected by the Z step and Z feed rate settings in the UGS Jog Controller.
From a mechanical design perspective, I expected the servo’s motion to depend solely on PWM signal parameters (e.g., minpulseus to maxpulseus defining the arm angles). During Z-jog commands in UGS (e.g., Z+: $J=G20G91Z2F500 or Z-: $J=G20G91Z-2F500), the servo moves only when the jog direction (Z+ or Z-) changes. The wall limits the pen/marker move.
Suggested YAML Features for FluidNC:
These features relate specifically to drawing plotters, where the physical limits—such as the wall or drawing surface—constrain pen/marker movement, not the precise servo angle itself.
* Add a transition time for the PWM signal to move from minpulseus to maxpulseus. This softens the servo motion, so the pen or marker doesn’t slam into the drawing surface.
* Include a servo dwell time (a configurable delay) after the PWM signal changes, to allow the motion to complete before the next G-code command executes. This accounts for the actual speed and mechanics of the servo.
I may be stuck in my current logic about how drawing plotters behave, especially when it comes to servo control. Open to corrections or suggestions. I’m happy to test any proposed changes or take additional measurements.
#3 – bdring 于 2025-05-20
Edit your first post to show your complete config file. I assume there is more to it.
#4 – bdring 于 2025-05-20
I have made many plotters using FluidNC.
The timerms is the time between updates of the PWM value as it is tracking the virtual Z axis. If you have a frequency of 50Hz, that is a 20ms period. If you have a timerms less than 20, then it is trying to update the PWM faster than the period. That is not good.
– Add a transition time for the PWM signal to move from minpulseus to maxpulseus. This softens the servo motion, so the pen or marker doesn’t slam into the drawing surface.
The PWM range is mapped the the range of travel for the axis. The axis will move through the range of travel per your maxratemmpermin value. You have a very high rate of travel so the servo will move quicky. If you did a G01 Z30 F30 it would take a full minute to do the move from Z0 to Z30
– Include a servo dwell time (a configurable delay) after the PWM signal changes, to allow the motion to complete before the next G-code command executes. This accounts for the actual speed and mechanics of the servo.
If you properly give maxratemmpermin the true rate of travel it will work fine.
#5 – bdring 于 2025-05-20
Here it is running at 2 different speeds.
Post your full config!
https://github.com/user-attachments/assets/45a84e82-9efb-4b3e-94cf-3804ec8b2700
#6 – Liizam 于 2025-05-21
Thank you very much for your attention to my issue.
name:
board: FluidNC Pen/Laser 2209 V2
meta:
arctolerancemm: 0.1
junctiondeviationmm: 0.1
stepping:
engine: RMT
idle_ms: 5
dirdelayus: 1
pulse_us: 3
disabledelayus: 0
start:
must_home: false
deactivate_parking: false
check_limits: false
uart1:
txd_pin: gpio.17
rxd_pin: gpio.16
rtspin: NOPIN
ctspin: NOPIN
baud: 115200
mode: 8N1
uart2:
txd_pin: gpio.4
rxd_pin: gpio.15
rtspin: NOPIN
ctspin: NOPIN
baud: 5000000
mode: 8N1
uart_channel2:
uart_num: 2
reportintervalms: 75
axes:
sharedstepperdisable_pin: gpio.13:high
x:
stepspermm: 40.18
maxratemmpermin: 10000
accelerationmmper_sec2: 40
maxtravelmm: 1220
soft_limits: false
homing: false
motor0:
limitnegpin: gpio.36:low
hard_limits: false
pulloff_mm: 5
tmc_2209:
uart_num: 1
addr: 0
rsenseohms: 0.11
run_amps: 0.7
hold_amps: 0.05
microsteps: 8
stallguard: 5
stallguard_debug: false
toff_disable: 1
toff_stealthchop: 6
toff_coolstep: 4
run_mode: SpreadCycle
homing_mode: SpreadCycle
use_enable: false
direction_pin: gpio.12
step_pin: gpio.14
motor1:
null_motor: null
y:
stepspermm: 40.08
maxratemmpermin: 10000
accelerationmmper_sec2: 50
maxtravelmm: 2000
soft_limits: false
homing: false
motor0:
limitnegpin: gpio.39:low
tmc_2209:
uart_num: 1
addr: 1
rsenseohms: 0.11
run_amps: 0.7
hold_amps: 0.05
microsteps: 8
stallguard: 5
stallguard_debug: false
toff_disable: 1
toff_stealthchop: 6
toff_coolstep: 4
run_mode: SpreadCycle
homing_mode: StallGuard
use_enable: false
direction_pin: gpio.26
step_pin: gpio.25
motor1:
null_motor: null
z:
stepspermm: 400
maxratemmpermin: 8000
accelerationmmper_sec2: 3000
maxtravelmm: 30
soft_limits: true
homing:
cycle: 0
allowsingleaxis: true
positive_direction: false
mpos_mm: 0
feedmmper_min: 2000
seekmmper_min: 2000
settle_ms: 500
seek_scaler: 1.1
feed_scaler: 1.1
motor0:
limitnegpin: NO_PIN
limitpospin: NO_PIN
limitallpin: NO_PIN
hard_limits: false
pulloff_mm: 0.1
rc_servo:
pwm_hz: 50
output_pin: gpio.21
minpulseus: 2000
maxpulseus: 1000
timer_ms: 5
spi:
miso_pin: gpio.19
mosi_pin: gpio.23
sck_pin: gpio.18
sdcard:
cs_pin: gpio.5
carddetectpin: NO_PIN
coolant:
floodpin: NOPIN
mistpin: NOPIN
probe:
pin: NO_PIN
control:
feedholdpin: gpio.35:low
cyclestartpin: gpio.34:low
safetydoorpin: gpio.33:low
laser:
pwm_hz: 5000
output_pin: gpio.27
enable_pin: gpio.2
disablewiths0: false
s0withdisable: true
tool_num: 0
speed_map: 0=0.000% 255=100.000%
macros:
startup_line0: G4 P0.2
startup_line1: G21&G90&G92 Z0&G0 Z30
#7 – bdring 于 2025-05-21
Set idle_ms to 255
Set timer_ms to 100
I will be changing the code to prevent low values of timer_ms
#8 – Liizam 于 2025-05-21
Yes, it works flawlessly now. The key setting is idle_ms=255, not =5 as I had.
If I set timer_ms= 100 it works flawlessly but the servo arm move visually not smooth, a little jerky.
If I set timer_ms= 10 it works flawlessly and the servo arm moves visually smooth as it should move.
Please postpone “changing the code to prevent low values of timer_ms.
You know your code but I’m sorry, I have an impression that setting like timerms define how fast the PWM signal is updated/regenerated. How fast the system will react on a request to change the PWM signal. In RC airplanes, the lower timerms is then quicker the plane servos react on the joystick commands.
#9 – Liizam 于 2025-05-21
If I set timer_ms = 100, it works flawlessly, but the servo arm doesn’t move smoothly—it appears a bit jerky.
If I set timer_ms = 10, it works flawlessly, and the servo arm moves smoothly, as it should.
https://github.com/user-attachments/assets/7d6e89ea-e587-4b08-a9b6-bdb1c07ed513
https://github.com/user-attachments/assets/87ed2a02-5ade-447c-b99b-82b634577eb3
#10 – bdring 于 2025-05-21
Do the math!
Try 25ms. 20 is going to be the minimum in the next revision.
#11 – bdring 于 2025-05-21
I will not support less than 20
#12 – Liizam 于 2025-05-21
Oh, I forgot about pwm_hz: 50.
That’s right 1/50Hz= 20ms. Why are there two variables defining the same PWM update frequency?
timer_ms = 25 works fine.
Thank you.
#13 – bdring 于 2025-05-21
timer_ms is different than the frequency.
#14 – Liizam 于 2025-05-21
I just tried pwmhz: 100 and timerms = 10 works fine with my specific digital servo.
#15 – Liizam 于 2025-05-21
> timer_ms is different than the frequency.
>
> http://wiki.fluidnc.com/en/config/axes#timer_ms
“timer_ms“ Wiki: This how often the the PWM value is recalculated and changed to match the position of the Z axis.
The servo motor does not have a feed back about its angular position. What does it mean “match the position of the Z axis”?
I will follow this as the recommendation.
Could you advise what is the best way to control the servo arm speed during custom Gcode execution, as you’ve demonstrated in your video?
Thank you.
#16 – bdring 于 2025-05-21
I used G1 Z5 F100 for one direction and a slower G1 Z0 F50 for the other direction.
the PWM value is recalculated and changed to match the position of the virtual Z axis
The wiki explains the RC Servo virtual axis.
#17 – MitchBradley 于 2025-05-21
pwm_hz is a general property that applies to all forms of PWM. Controlling RC Servos is not the only use for PWM, and in fact is a relatively uncommon usage compared to speed control for spindles and power control for lasers. It just happens that most RC Servos can be driven with a 50 Hz PWM signal with a suitably-limited duty cycle. Some RC Servos can handle higher frequencies.
timerms is specific to the RC Servo motor driver. Stepper motors are the most common case and FluidNC is optimized for driving them. RC Servos are an unusual motor type for which FluidNC is not optimized. The way it works is that there is a software task that wakes up periodically (every timerms milliseconds), looks at the expected position as computed by the stepping engine, and adjusts the PWM duty cycle accordingly.
We are unlikely to expend much effort to improve the RC Servo subsystem, since only a few people use it. Most of them have low-cost “for run” machines whose operation is not critical, and few of them sponsor the project. Thus we have little motivation to spend time on that compared to other higher-value tasks.
#18 – Liizam 于 2025-05-21
Thank you all for your support and for the FluidNC project.
#1 – bdring 于 2025-05-19
the update interval set by
timer_mslooks really fast at 5ms. That is just a fraction of the PWM period of 20ms. (50Hz).Try changing it to
timer_ms: 100.We might want to change the code to add a lower limit or something based on the frequency. The default is 20. I am not sure how the PWM period is affected when it is changed so fast.