Fan speed to servo macro

Hello,

I am trying to convert my part cooling fan speed to a servo position to control an air valve. I found help in the general discussion on this topic, but can’t figure out how to make it work. I am very new to macros, so learning this as I go.
Currently I am getting a “unable to parse fan_speed” error. My current config is as follows,

[servo my_servo]
pin: PD0
initial_angle: 0
maximum_servo_angle = 90
minimum_pulse_width = 0.001
maximum_pulse_width = 0.002

[delayed_gcode set_servo_angle_timer]
initial_duration: 1
gcode:
# Delayed gcode will poll every second and update the servo angle
SET_SERVO_ANGLE
UPDATE_DELAYED_GCODE ID=set_servo_angle_timer DURATION=1

[gcode_macro SET_SERVO_ANGLE]
gcode:
# Set the servo angle based on the part cooling fan speed
# Fan = 0.0, servo angle = 0
# Fan = 0.5, servo angle = 45
# Fan = 1.0, servo angle = 90
{% set fan_speed = printer.fan.speed * 90 %}
SET_SERVO SERVO=my_servo ANGLE=fan_speed

[fan]
pin: PC6

Any help would be appreciated, Thank you

@Sineos @jjarosz
You guys helped another member about a year ago on this topic and I am still struggling to make it work. I’ve tried about two dozen different ways using @mental Macro Creation Tutorial and keep getting Error on ‘SET_SERVO SERVO=my_servo ANGLE=’: unable to parse
Can you help me understand how it should be written. Here is my current config file,

printer(1).cfg (3.6 KB)

I’m not really a macro expert but what comes to my mind from your config:

[gcode_macro SET_SERVO_ANGLE]
gcode:
    # Set the servo angle based on the part cooling fan speed
    # Fan = 0, servo angle = 0
    # Fan = 128, servo angle = 45
    # Fan = 255, servo angle = 90
    {% if params.fan %}
      {% set servo_angle = params.fan %}
    {% endif %}
    SET_SERVO SERVO=my_servo ANGLE={servo_angle}

[delayed_gcode set_servo_angle_timer]
initial_duration: 1
gcode:
    # Delayed gcode will poll every second and update the servo angle
    SET_SERVO_ANGLE
    UPDATE_DELAYED_GCODE ID=set_servo_angle_timer DURATION=1

{% set servo_angle = params.fan %} means that Klipper is expecting the macro to be called, for example, with:

SET_SERVO_ANGLE fan=90
  • Should use uppercase here as well, i.e. FAN
  • Where is FAN set? Something like {% set current_fan_speed = printer.fan.speed|float %}
  • You will need to update your current_fan_speed regularly, so this needs to go into the delayed gcode
[delayed_gcode set_servo_angle_timer]
initial_duration: 1
gcode:
    {% set current_fan_speed = printer.fan.speed|float %}
    # Delayed gcode will poll every second and update the servo angle
    SET_SERVO_ANGLE FAN={current_fan_speed}
    UPDATE_DELAYED_GCODE ID=set_servo_angle_timer DURATION=1

Of course all untested. YMMV

1 Like

Thank you for the input. This does correct my error as the macro appears to be operational, however the servo does not work. I have many unknowns right now such as if the signal is being output through the pin I designated, if I’m outputting the correct signal for the servo or if the servo even works. I have much work to do and even more learning to accomplish. Thanks for the help!

I also not a macro expert but i found the partial solution on another post and i mixed with your code and it worked.
The fan speed is reported from 0.0 to 1.0 however the parameter was receiving string and not converting properly , following the code working:

[gcode_macro SET_SERVO_ANGLE]
gcode:
    # Set the servo angle based on the part cooling fan speed
    # Fan = 0.0, servo angle = 0
    # Fan = 0.5, servo angle = 90
    # Fan = 1.0, servo angle = 180
    {% set fan_speed = params.FAN|default(0.0)|float %}
    {% set servo_angle = fan_speed * 180 %}
    SET_SERVO SERVO=my_servo ANGLE={servo_angle}
    
    
[delayed_gcode set_servo_angle_timer]
initial_duration: 1
gcode:
    {% set current_fan_speed = printer.fan.speed %}
    # Delayed gcode will poll every second and update the servo angle
    SET_SERVO_ANGLE FAN={current_fan_speed}
    UPDATE_DELAYED_GCODE ID=set_servo_angle_timer DURATION=1

I hope this is helpful

Also in your case you dont want to go to 180 i created one macro to translate the values according to the maximum and minimum range desired :

[gcode_macro SET_SERVO_ANGLE]
gcode:
    # Set the servo angle based on the part cooling fan speed
    {% set value =  params.FAN|default(0.0)|float %}
    {% set leftMin = 0.1|float %}
    {% set leftMax = 1.0|float %}

    {% set rightMin = 0|float %} # Minimun servo angle when fan is 0.1
    {% set rightMax = 90|float %} # Maximun servo angle when fan is 1.0

    {% set leftSpan = leftMax - leftMin %}
    {% set rightSpan = rightMax - rightMin %}
    {% set valueScaled = (value - leftMin) / leftSpan %}
    {% set servo_angle = rightMin + (valueScaled * rightSpan) %}
    
    SET_SERVO SERVO=my_servo ANGLE={servo_angle}

Thanks for working on this!
I haven’t been back to this thread and missed your post. I have been taking an Intro to Python class in hopes to better understand the scripting. Getting there, but still a lot to learn!
Anyway, I have loaded your work and my servo still does not work. I am connecting the servo signal wire to PC6 on my printer board which is the fan negative and controls the fan PWM. I did assign the [servo my_servo] to pin PC6. You said it worked for you. How did you connect the servo?
The servo is an MG996R and I have the supply power connected through a buck converter from the PSU.
Thanks!