Configure a Motor with an Encoder

Use an encoder with a motor to create a closed feedback loop for better control of your machine. Instead of sending speed or position commands without a way to verify the motor’s behavior, the encoder lets the computer know how the motor is actually rotating in the real world, so adjustments can be made to achieve the desired motor movement.

Some motors come with encoders integrated with or attached to them. You can also add an encoder to a motor. See the encoder component documentation for more information on encoders.

Viam supports gpio model motors with encoders. To configure an encoded motor, you must configure the encoder per the encoder documentation and then configure a gpio motor with an encoder attribute in addition to the standard gpio model attributes.

Physically connect your motor to a suitable driver chip, and connect that to your board, as well as connecting the encoder. Connect the system to power if you want to test it while configuring. Configure the board and the encoder. Then, configure the motor:

Here’s an example configuration:

An encoded motor config in the Viam app UI.

{
  "components": [
    {
      "name": "<your-board-name>",
      "model": "<your-board-model>",
      "type": "board",
      "namespace": "rdk",
      "attributes": {},
      "depends_on": []
    },
    {
      "name": "<your-encoder-name>",
      "model": "<your-encoder-model>",
      "type": "encoder",
      "namespace": "rdk",
      "attributes": {
        ... // insert encoder model specific attributes
      },
      "depends_on": []
    },
    {
      "name": "<your-motor-name>",
      "model": "gpio",
      "type": "motor",
      "namespace": "rdk",
      "attributes": {
        "board": "<your-board-name>",
        "pins": {
          <...> // insert pins struct
        },
        "encoder": "<your-encoder-name>",
        "ticks_per_rotation": <int>,
        "control_parameters": {
          "p": <int>,
          "i": <int>,
          "d": <int>
        }
      },
      "depends_on": []
    }
  ]
}

Here’s an example configuration:

{
  "components": [
    {
      "name": "local",
      "model": "pi",
      "type": "board",
      "namespace": "rdk",
      "attributes": {},
      "depends_on": []
    },
    {
      "name": "myEncoder",
      "model": "incremental",
      "type": "encoder",
      "namespace": "rdk",
      "attributes": {
        "board": "local",
        "pins": {
          "a": "13",
          "b": "15"
        }
      },
      "depends_on": []
    },
    {
      "name": "myMotor1",
      "model": "gpio",
      "type": "motor",
      "namespace": "rdk",
      "attributes": {
        "board": "local",
        "pins": {
          "pwm": "16",
          "dir": "18"
        },
        "encoder": "myEncoder",
        "ticks_per_rotation": 9600,
        "control_parameters": {
          "p": 0.2,
          "i": 0.5,
          "d": 0.0
        }
      },
      "depends_on": []
    }
  ]
}

Same example JSON as on the JSON example tab, with notes alongside it. See attribute table below for all the same information.

In addition to the attributes for a non-encoded motor, the following attributes are available for encoded DC motors:

NameTypeRequired?Description
encoderstringRequiredname of the encoder.
ticks_per_rotationintRequiredNumber of ticks in a full rotation of the encoder and motor shaft.
ramp_ratefloatOptionalRate to increase the motor’s input voltage (power supply) per second when increasing the speed the motor rotates (RPM).
Range = (0.0, 1.0]
Default: 0.05
control_parametersobjectOptionalA JSON object containing the coefficients for the proportional, integral, and derivative terms. If you want these values to be auto-tuned, you can set all values to 0: { "p": 0, "i": 0, "d": 0 }, and viam-server will auto-tune and log the calculated values. Tuning takes several seconds and spins the motors. Copy the values from the logs and add them to the configuration once tuned for the values to take effect. For more information see Control motor velocity with encoder feedback.

Wiring example

Here’s an example of an encoded DC motor wired with the MAX14870 Single Brushed DC Motor Driver Carrier. This wiring example corresponds to the example config above.

Example wiring diagram with a Raspberry Pi, brushed DC motor, 12V power supply, and Pololu MAX14870 motor driver. The DIR pin of the driver is wired to pin 18 on the Pi. PWM goes to pin 16. The motor’s encoder signal wires (out a and out b) go to pins 11 and 13 on the Pi. The motor’s main power wires are connected to the motor driver while its encoder logic power wires are connected to the Pi.

Test the motor

Once your motor is configured and connected, go to the CONTROL tab and click on the motor’s dropdown panel. Use the buttons to try turning your motor forwards or backwards at different power levels and check whether it moves as expected.

Motor control panel.

For example, a Viam Rover with encoded motors following both an angular and linear velocity command:

The position, orientation, and linear and angular velocity of the rover changing as it moves, as measured by a movement sensor:

If the motor does not appear on the CONTROL tab, or if you notice unexpected behavior, check your machine’s LOGS tab for errors, and review the configuration.

Control motor velocity with encoder feedback

If you want to control your motor by specifying the distance and velocity in terms of distance and distance/time, for example 2 rotations at 5 m/s, and you have an encoder, you can use the position of your encoder to adjust the distance and velocity.

You can do this in two ways:

The first just uses the encoder feedback to increase or decrease the power being set on the motors in increments of 10%.

The second requires setting the control_parameters attribute, which sets up a PID control loop to adjust the distance and velocity of the motor. Setting the control_parameters will automatically set up the required PID loop for an encoded motor. For more information on PID or to set up a more complex control loop, see the controls package

If you want these values to be auto-tuned, you can set all values to 0: { "p": 0, "i": 0, "d": 0 }, and viam-server will auto-tune and log the calculated values. Tuning takes several seconds and spins the motor. Copy the values from the logs and add them to the configuration once tuned for the values to take effect.

Troubleshooting

If your motor is not working as expected, follow these steps:

  1. Check your machine logs on the LOGS tab to check for errors.
  2. Review this motor model’s documentation to ensure you have configured all required attributes.
  3. Check that all wires are securely attached to the correct pins.
  4. Click on the TEST panel on the CONFIGURE or CONTROL tab and test if you can use the motor there.

If none of these steps work, reach out to us on the Community Discord and we will be happy to help.

Next steps

For more configuration and usage info, see:

Have questions, or want to meet other people working on robots? Join our Community Discord.

If you notice any issues with the documentation, feel free to file an issue or edit this file.