Last edited · 67 revisions   


SERVO Motor Driver Configuration

For OnStepX DC motors or Stepper motors, and encoders for position feedback.

This area of OnStepX is still in its early development phase so we're really not sure if everything works as intended, use at your own risk...

Servo Driver Settings

  • SERVO_EE - Enable/Enable type DC motor driver/servo
    • Driver where a one enable pin is held LOW and a PWM signal is applied to the other to control direction and rate of motion of a DC motor.
      • Two pins per axis are associated with this AXISn_SERVO_PH1_PIN and AXISn_SERVO_PH2_PIN and when present in a pinmap they are mapped to the AXISn_DIR_PIN and AXISn_STEP_PIN for that axis, respectively.
  • SERVO_PE - Phase/Enable type DC motor driver/servo
    • Driver where only one input pin takes a PWM signal to control the rate of motion and the other pin determines direction (logic HIGH or LOW) of a DC motor.
      • Two pins per axis are associated with this AXISn_SERVO_PH1_PIN (Phase/Dir) and AXISn_SERVO_PH2_PIN (Enable/PWM) and when present in a pinmap they are mapped to the AXISn_DIR_PIN and AXISn_STEP_PIN for that axis, respectively.
  • SERVO_TMC2209 - TMC2209 UART mode stepper motor driver/servo
    • Driver where a hardware UART programs the stepper driver velocity (using the VACTUAL register.)
      • The usual stepper driver setup/pins apply, except SERVO_TMC2209 is the driver type; see the TMC UART Advanced Configuration page for detailed setup information.
      • Notes:
        • This configuration option uses the TMC Stepper Library.
        • Using other (non-servo) TMC2209 step/dir drivers at the same time requires using the TMC Stepper Library for them as well.  This is accomplished by adding #define DRIVER_TMC_STEPPER to Config.h and requires having RX and TX connections to the drivers.
        • It is intended that you use a hardware serial UART to talk to the drivers for performance reasons.
        • The hardware serial interface is NOT automatically set up, you must follow the example at the bottom of the TMC UART Advanced Configuration page.
        • The _GOTO options in Config.h for this axis are ignored.
        • The driver decay mode is fixed in spreadCycle.


  • For the associated axis you should set the AXISn_STEPS_PER_DEGREE to match the encoder resolution.  The resolution should be within the operating range for this axis (see the Axes section of the Wiki for more information on AXISn_STEPS_PER_DEGREE.)
  • The AXISn_REVERSE option can be used to reverse the feedback loop control direction.
    • You can also sometimes reverse leads on the driver, encoder, or motor (depending on the type) to change directions.
  • Two pins per axis are associated with this AXISn_ENCODER_A_PIN and AXISn_ENCODER_B_PIN and when present in a pinmap they are mapped to the AXISn_M0_PIN and AXISn_M1_PIN for that axis, respectively.
    • For SERVO_TMC2209 the M0 and M1 pins are used for the TMC2209 so it is up to the user to specify other pins for the encoders in Config.h, as they see fit.
    • For some designs (MaxESP3, MaxSTM3.6) M0 and M1 form an SPI bus and are shared between Axis1 and Axis2 (etc.) so they are not suitable for this purpose.
  • There is code to detect servo stalls/run-away and oscillations.  If any of these events occur the servo motor is disabled.
    • During tuning it can be helpful disable this feature temporarily which can be done by adding the following line to Config.h:
      • #define SERVO_SAFETY_DISABLE
  • The following settings (for each axis) can be added Config.h to change the defaults (shown below) and configure the two sets of PID (Proportional, Integral, Derivative) parameters for each axis.  The PID parameters can also be changed at run-time (without rebooting) using the SWS (website) and that functionality is important as it is necessary to do a fair bit of trial and error testing to converge on effective settings.
      • Default Value: AB
      • Notes:
        • For servo drivers, specifies the encoder type:
          • AB for common AB quadrature encoders.
          • AB_ESP32 for common AB quadrature encoders with fast hardware decode on ESP32 micro-controllers.
          • CW_CCW for encoders with separate clockwise and counter-clockwise signals.
          • PULSE_DIR for encoders with pulse and direction signals.
          • PULSE_ONLY for encoders that send only a pulse.
            • This is the simplest type of encoder where even a small button magnet on a motor shaft along with an hall-effect sensor can establish how many turns the motors shaft has taken and the speed.
            • In this case the direction is inferred from the control input (which direction the OCS is telling the motor to run.)
          • AS37_H39B_B for Broadcom AS37-H39B BiSS-C absolute encoders.
            • Often its best to read the encoders at a high rate on fast micro-controllers, which can be set with:
              • #define AS37_CLOCK_RATE_KHZ 4000
              • In my tests the error rate was: ~2.0% at 500 KHz, ~0.5% @ 2000 KHz, ~0.01% at 4000KHz
              • The driver uses CRC to reject most errors.
            • These encoders use a battery to preserve the multi-turn count, if no battery is used it is best to instruct the driver to ignore the multi-turn part of the count:
              • #define AS37_SINGLE_TURN
          • SERIAL_BRIDGE uses a hardware Serial UART to communicate at high speed with another microcontroller that reads the encoders for Axis1 and/or Axis2.
            • The serial interface to use and its setup can be specified by adding lines similar to the following to OnStepX's Config.h file:
              • #define SERIAL_ENCODER Serial
              • #define SERIAL_ENCODER_BAUD 480600
            • This works with the Encoder Bridge firmware running on a second micro-controller.
              • You can download the Encoder Bridge here:
              • Its Config.h file has a subset of options for encoder setup similar to what you'd use in OnStepX.
              • The encoder pins are assigned in the same way as they are with a Smart Web Server (so this can plug into a Max series controller instead of an SWS.)
                • You can see the encoder pin assignments in the pinmap for the microcontroller you are using.
                • For this, and performance reasons, the WeMos D1 Mini footprint ESP32 devices on the market are most useful for the purpose.
                • Using a MaxESP3 or MaxESP4 also works out well as you can use the Website plugin to replace the functionality of the now absent SWS.
                • On an MaxPCB4 there is a spare UART serial port on the DB15 connector where you can add the SWS externally.
            • Tips:
              • You can also override the default baud rate (on both sides) and sometimes use an even faster rate, like 921200 baud.
              • The EB firmware does not use LX200 communications but rather sits and listens for commands from the SERIAL_BRIDGE part of OnStepX then sends a simple reply with the position count for the axis requested.  This provides very fast encoder readout and low latency.
      • Tips:
        • Running the encoder subsystem on OnStepX where other real-time processes are running may result in missed encoder pulses though some encoder types (AB_ESP32, SERIAL_BRIDGE) lean on micro-controller dedicated hardware resources to avoid this issue.
        • Very high encoder pulse rates can exceed microcontroller performance limits.  The fastest processors like the Teensy4.0 or those with hardware decode (AB_ESP32, AS37_H39B_B, SERIAL_BRIDGE) are expected to support the highest encoder pulse rates.
        • All encoders except AB_ESP32 have built-in support so no library needs to be installed for most (currently only CW_CCW and AS37_H39_B are tested though.)
        • If using AB_ESP32 the required encoder library is here:
      • Default Value: 0
      • Other Values: 0 to 4294967296 (counts)
      • Notes:
        • OnStep assumes the encoder will be at a zero count in the home position.
        • Usually this is not the case for absolute encoders so this option sets the encoder origin so it returns 0 when in the home position.
      • Tips:
        • In OnStepX and the EncoderBridge absolute encoders must be initialized with this option.  To do so, with the mount in the home position, enable VERBOSE debug mode in OnStepX and watch the boot in the Arduino Serial Monitor.  There will be messages telling you what to set the AXISn_ENCODER_ORIGIN for each axis to.  Add the AXISn_ENCODER_ORIGIN lines to Config.h and upload again then you're all set.
        • The Smart Web Server (SWS) has a button on the encoder tab to automatically set and remember the absolute encoder origin so using this option is not necessary or supported in this case.
      • Default Value: OFF
      • Other Values: OFF, ON
      • Notes:
        • Reverses encoder count direction
      • Default Value: 0
      • Recommended Values: 0 to 120 (arc-seconds)
      • Notes:
        • Servos don't always arrive exactly at the target coordinate and this allows a small margin of error so gotos end quickly.
      • Default Value: 100
      • Recommended Values: 0 to 1000000 (% or steps/s)
      • Notes:
        • Velocity limit, in % for DC, in steps/s for SERVO_TMC2209.
      • Default Value: 20
      • Recommended Values: 0 to 1000000 (% or steps/s)
      • Notes:
        • Acceleration limit, in %/s/s for DC, in steps/s/s for SERVO_TMC2209.
      • Default Value: OFF
      • Recommended Values: 0 to 100000 (counts)
      • Notes:
        • Sync threshold in counts (for absolute encoders) or OFF.
      • Default Value: OFF
      • Other Values: OFF, KALMAN
      • Notes:
        • The KALMAN filter smooths encoder readings trading resolution and responsiveness for accuracy.
      • Tips:
        • If using KALMAN the following two options must also be added to Config.h (for example):
          • #define AXIS1_SERVO_FLTR_MEAS_U      20 // kalaman measurement uncertainty, in encoder ticks
          • #define AXIS1_SERVO_FLTR_VARIANCE   0.1 // kalaman responsiveness, usually between 0.001 and 1
        • If using KALMAN the required encoder library is here:
    • AXISn_PID_P
      • Default Value: 2.0
      • Recommended Values: 0.0 to 200.0
      • Notes:
        • Proportional, scale of immediate response to position error.
    • AXISn_PID_I
    • AXISn_PID_D
      • Default Value: 5.0
      • Recommended Values: 0.0 to 200.0
      • Notes:
        • Derivative, overshoot suppression.
      • Default Value: 2.0
      • Recommended Values: 0.0 to 200.0
      • Notes:
        • Proportional, scale of immediate response to position error.
        • Applied during faster motion.
      • Default Value: 5.0
      • Recommended Values: 0.0 to 200.0
      • Notes:
        • Integral, rate of increasing response to position error over time.
        • Applied during faster motion.
      • Default Value: 5.0
      • Recommended Values: 0.0 to 200.0
      • Notes:
        • Derivative, overshoot suppression.
        • Applied during faster motion.
      • Default Value: 0
      • Recommended Values: 0, 1 to 100 (%)
      • Notes:
        • When the default setting (0) is used the Axis slewing state selects between the tracking or slewing PID sets.
          • When switching from tracking to slewing mode, the slewing PID (_GOTO) settings are immediately adopted.
          • When switching from slewing mode to tracking mode, the PID settings are changed over a one second period transitioning smoothly from slewing to tracking values to help prevent oscillation.
            • You can change the default one second period for this transition by adding the following setting to Config.h (for example, two seconds:)
              • #define PID_SLEWING_TO_TRACKING_TIME_MS 2000
        • For values between 1 and 100% the PID settings above are applied in a continuously variable way proportional to the motor power %.
          • When power is near 0% PID set one is used, then PID parameter values are scaled in a continuously variable way so that 100% of PID set two (_GOTO) is applied at or above the power (in %) that you specify here.
          • For example, if you specify a range of 20 and the motor is at 10% power, the actual P used is (AXISn_PID_P + ASIXn_PID_P_GOTO) / 2.
      • Default Value: pOnError
      • Recommended Values: See to read about these advanced settings.
      • Notes:
        • Add to Config.h to change the default QuickPID behavior, for example:
          • #define PID_PMODE pOnMeas
      • Default Value: iAwCondition
      • Recommended Values: See above link.
      • Default Value: dOnMeas
      • Recommended Values: See above link.
      • Default Value: 10000 (microseconds)
      • Recommended Values: See above link.


The latest SWS (and Website plugin) have the option in Config.h to enable servo monitoring for any axis:

For a higher temporal resolution there is also a debug option in Extended.config.h DEBUG_SERVO 1 which can be enabled (for a given Axis, in this example Axis1) to provide an useful position error output for that axis (use the Arduino Serial Plotter) to help with tuning.  Be sure to use DEBUG ON (not VERBOSE) and configure the debug serial channel for a fast baud rate.

Here's what a Celestron Pittman Servo from a CGEM looks like while tracking, the encoder ticks are 0.125 arc-second for that mount:

Here its doing a slew (note the large position error is ok and even desirable in this case as it "loosens up control" to allow the motor to run smoothly at high speeds:)


There are two interfaces required for operating a servo motor with OnStepX; you need a motor driver output and you need an encoder input.

The motor driver can be a TMC2209 in UART mode running a stepper motor or it can be a DC motor.

  • For DC motor drivers SERVO_EE and SERVO_PE, two microcontroller pins are associated with each Axis they are AXISn_SERVO_PH1_PIN and AXISn_SERVO_PH2_PIN.  These carry Enable/Enable or Phase/Enable signals.
    • The pinmaps for Max series controllers have defaults for Axis1 and Axis2 so that:
      • AXISn_SERVO_PH1_PIN is on the AXISn_STEP_PIN.
      • AXISn_SERVO_PH2_PIN is on the AXISn_DIR_PIN.
      • The AXISn_ENABLE_PIN is used.
      • The AXISn_FAULT_PIN is used.
  • For TMC2209 UART mode drivers an serial interface UART port must be used.
    • The pinmaps for Max series controllers that support TMC2209 UART drivers have this already designed in.

The encoder can be an A/B, CW/CCW, AS37 BiSS-C, SERIAL_BRIDGE, etc.

  • For A/B, CW/CCW, and AS37 BiSS-C two microcontroller pins are associated with each Axis they are AXISn_ENCODER_A_PIN and AXISn_ENCODER_B_PIN.
    • The pinmaps for Max series controllers have defaults for Axis1 and Axis2 so that:
      • AXIS1_ENCODER_A_PIN is on the AXIS3_STEP_PIN.
      • AXIS1_ENCODER_B_PIN is on the AXIS3_DIR_PIN.
      • AXIS2_ENCODER_A_PIN is on the AXIS4_STEP_PIN.
      • AXIS2_ENCODER_B_PIN is usually on the AXIS4_M3_PIN.
  • For SERIAL_BRIDGE the configuration is covered in the section above and normally uses the hardware Serial interface associated with SERIAL_B, though SERIAL_B is disabled when it's active as this is not a command channel and replaces the SWS at the WeMos D1 Mini socket.  From there it uses the already present encoder input provision on the Max series controllers DB15 connector.

To support the above design and capabilities I developed Encoder interface and DC motor driver hardware that works using the StepStick sockets and/or DB15 connector of the Max series controllers.

Please note all of these are in various stages of testing and might not work or even might damage hardware!!!

The encoder interface modules for the DB15 connector of Max series controllers (all fit in this connectors plastic housing):

The encoder interface module for a StepStick socket (to hopefully) allow using the the Axis3 and Axis4 stepper driver provision of Max series controllers as A/B or CW/CCW encoder inputs.  This should allow plugging most encoders right into the RJ22 jacks on the back of a Max series controller:

And, finally, a StepStick style module to run some DC motors from the stepper driver sockets of Max series controllers (all except the MaxSTM3.6 should work AFAIK):