Using Encoders with the Arduino Library

Spread the love

The Basicmicro Arduino library reads, sets, and resets RoboClaw encoder counts with a handful of functions: ReadEncM1 and ReadEncM2 return the current count, SetEncM1 and SetEncM2 write a value, ResetEncoders zeroes both channels, GetStatus reads both counts and speeds with the controller’s full status, and the SpeedAccelDeccelPosition commands move a motor to a target position.

The RoboClaw normally uses encoders in an automatic closed loop control scheme to maintain speed and position. However, there are situations where more custom control from a microcontroller is called for. This application note covers using an Arduino to read, set, and reset encoders with the Basicmicro Arduino library, and works with any RoboClaw motor controller and any motor with a quadrature encoder.

What You Need

How Do You Set Up the Hardware?

Connect the motor to the RoboClaw’s M1 channel and hook up main power as shown in the Dual Channel RoboClaw Quick Start Guide, and wire the motor’s encoder to the RoboClaw’s EN1 header as shown in Pololu Encoder Wiring. Then make the serial connections between the Arduino and the RoboClaw with the jumper cables: Arduino pin 11 (TX) to the RoboClaw’s S1 signal pin, Arduino pin 10 (RX) to the S2 signal pin, and a ground pin on the Arduino to a ground pin on the RoboClaw. This is the wiring the example at the end of this article uses over software serial. If the library is not installed yet, it is available in the Arduino Library Manager; see Using the RoboClaw Arduino Library for the install steps.

The functions in this article communicate with the RoboClaw using packet serial. Before running your Arduino code, connect the RoboClaw to Motion Studio and set it to Packet Serial mode, and note the address and baud rate configured there. The values used in your sketch must match the controller’s settings.

Encoder Functions in the Arduino Library

Below are the encoder functions available in the Arduino library. All of the functions are called on an existing Basicmicro object; creating that object and starting communication with begin() is covered in Using the RoboClaw Arduino Library. Every function takes the controller’s address as its first parameter.

Reading Encoders

There are two functions used to read the current encoder values, one for each channel. The functions return the count as a 32-bit unsigned value (uint32_t). The status and valid parameters are optional: status returns the encoder’s direction and underflow/overflow flags, and valid reports whether the read succeeded.

ReadEncM1(address, status, valid)
ReadEncM2(address, status, valid)

In this example ReadEncM1 is called to read the current encoder count of channel 1, and the value returned is saved to the variable motor_1_count:

// Read the current value of the encoder on channel 1
uint32_t motor_1_count = roboclaw.ReadEncM1(0x80);

Reading Speed

These two functions read the speed of each motor in encoder counts per second, returned as a 32-bit unsigned value. The optional status parameter returns the direction of motion and valid reports whether the read succeeded.

ReadSpeedM1(address, status, valid)
ReadSpeedM2(address, status, valid)

In this example ReadSpeedM1 is called to read the speed of motor 1 in encoder counts per second:

// Read the speed of motor 1 in encoder counts per second
uint32_t motor_1_speed = roboclaw.ReadSpeedM1(0x80);

Reading Everything at Once with GetStatus

When a sketch needs more than one value, GetStatus reads the controller’s entire status in a single command: both encoder counts, both speeds, temperatures, battery voltages, PWM values, motor currents, and speed and position error values. It is the efficient choice for telemetry and monitoring, replacing separate ReadEnc and ReadSpeed calls. Every value is returned through a reference parameter, and the function returns true when the read succeeds. Temperatures are in tenths of a degree, voltages in tenths of a volt, and currents in milliamps. A complete sketch demonstrating every value is in the library’s examples folder on GitHub.

GetStatus(address, tick, state, temp1, temp2,
          mainBattVoltage, logicBattVoltage,
          pwm1, pwm2, current1, current2,
          enc1, enc2, speed1, speed2,
          ispeed1, ispeed2, speedError1, speedError2,
          posError1, posError2)

In this example the full status is read in one command and the channel 1 encoder count and speed are taken from it:

// Declare a variable for every status value
uint32_t tick, state, enc1, enc2, speed1, speed2, ispeed1, ispeed2;
uint16_t temp1, temp2, mainBatt, logicBatt, speedErr1, speedErr2, posErr1, posErr2;
int16_t pwm1, pwm2, current1, current2;

// Read the full controller status in one command
if (roboclaw.GetStatus(0x80, tick, state, temp1, temp2, mainBatt, logicBatt,
                       pwm1, pwm2, current1, current2, enc1, enc2, speed1, speed2,
                       ispeed1, ispeed2, speedErr1, speedErr2, posErr1, posErr2)) {
  // The encoder counts and speeds are now in enc1, enc2, speed1, and speed2
}

Setting Encoders

These functions set their respective channel’s encoder count to a given value. The address of the RoboClaw and the val to be set must be passed to them.

SetEncM1(address, val)
SetEncM2(address, val)

In this example the count of the channel 1 encoder is set to 10,000 counts:

// Set the channel 1 encoder count to 10000
roboclaw.SetEncM1(0x80, 10000);

Resetting Encoders

Calling this function sets both encoder channels to zero. It returns true when the RoboClaw acknowledges the command.

ResetEncoders(address)

In this example the encoder counts for both channels are set to zero:

// Reset both encoder channels to zero
roboclaw.ResetEncoders(0x80);

Position Commands

These functions move the motor on a given channel to a specific position in encoder counts. Accel and deccel set the acceleration and deceleration of the motor, speed sets the speed in encoder counts per second, and position is the target in encoder counts. Flag controls whether the command is executed immediately or stored until any previous commands are finished; a value of 0 stores the command and a value of 1 executes it immediately. The M1M2 version positions both motors independently at the same time. Position PID parameters must be set and tuned, in Motion Studio or with SetM1PositionPID/SetM2PositionPID, before these commands will work correctly.

SpeedAccelDeccelPositionM1(address, accel, speed, deccel, position, flag)
SpeedAccelDeccelPositionM2(address, accel, speed, deccel, position, flag)
SpeedAccelDeccelPositionM1M2(address, accel1, speed1, deccel1, position1, accel2, speed2, deccel2, position2, flag)

In this example motor 1 is moved to a position of 15,000 counts with acceleration and deceleration values of 10,000, a speed of 2,000 counts per second, and the flag set to 1 so the command executes immediately:

// Move motor 1 to position 15000
roboclaw.SpeedAccelDeccelPositionM1(0x80, 10000, 2000, 10000, 15000, 1);

Complete Example

The sketch below demonstrates each function from this article in order. It reads and prints the channel 1 encoder count, sets the count to 10,000 and reads it back, runs motor 1 and prints its speed, resets both encoders, and finally moves motor 1 to a position of 15,000 counts. Results print to the Arduino serial monitor. The sketch uses software serial on pins 10 and 11 to match the wiring above; to use a hardware serial port instead, see Using Hardware Serial with the RoboClaw Arduino Library.

This sketch uses two serial connections. Serial is the Uno’s built-in hardware serial port, which connects to the USB port and is only used to print results to the Arduino IDE serial monitor. controllerSerial is the SoftwareSerial object created in the sketch, and is what the Basicmicro library uses to communicate with the RoboClaw. On an Uno there is no way around using both: the only hardware serial port is the USB connection, so a sketch that prints results must put the RoboClaw on software serial.

// Include the necessary libraries
#include <Basicmicro.h>
#include <SoftwareSerial.h>

// Address of the motor controller as set in Motion Studio
#define ADDRESS 0x80

// Create the software serial object for the RoboClaw (RX, TX)
// Pin 10 connects to the RoboClaw's S2 pin, pin 11 to S1
SoftwareSerial controllerSerial(10, 11);

// Create the Basicmicro object with a 10ms (10000 microsecond) timeout
Basicmicro roboclaw(&controllerSerial, 10000);

void setup() {
  // Start the serial monitor connection for printing results
  Serial.begin(115200);

  // Start communicating with the RoboClaw
  // The baud rate must match the one set in Motion Studio
  roboclaw.begin(38400);

  // Read and print the current encoder count for channel 1
  uint32_t motor_1_count = roboclaw.ReadEncM1(ADDRESS);
  Serial.print("Encoder 1 count: ");
  Serial.println(motor_1_count);

  // Set the channel 1 encoder to 10000 counts and read it back
  roboclaw.SetEncM1(ADDRESS, 10000);
  motor_1_count = roboclaw.ReadEncM1(ADDRESS);
  Serial.print("Encoder 1 count after SetEncM1: ");
  Serial.println(motor_1_count);

  // Run motor 1 at about 50% duty cycle and read its speed
  roboclaw.DutyM1(ADDRESS, 16384);
  delay(2000);
  uint32_t motor_1_speed = roboclaw.ReadSpeedM1(ADDRESS);
  Serial.print("Motor 1 speed (counts per second): ");
  Serial.println(motor_1_speed);

  // Stop motor 1
  roboclaw.DutyM1(ADDRESS, 0);

  // Reset both encoders to zero and read channel 1 back
  roboclaw.ResetEncoders(ADDRESS);
  motor_1_count = roboclaw.ReadEncM1(ADDRESS);
  Serial.print("Encoder 1 count after reset: ");
  Serial.println(motor_1_count);

  // Move motor 1 to position 15000
  // Position PID parameters must be set and tuned first
  roboclaw.SpeedAccelDeccelPositionM1(ADDRESS, 10000, 2000, 10000, 15000, 1);
}

void loop() {
}

Troubleshooting

If there is no response from the RoboClaw to the commands the Arduino is sending, there are a few things to check. First, ensure there is a ground connection between the Arduino and the RoboClaw; without it the two boards cannot communicate properly. Then check that the RX and TX connections between the Arduino and RoboClaw are not reversed: pin 10 of the Arduino should be attached to the RoboClaw’s S2 signal pin and pin 11 of the Arduino attached to the RoboClaw’s S1 signal pin. Finally, confirm the address and baud rate in the sketch match the values set in Motion Studio.

Next Steps

For the general pattern of using the library and a reference of its most commonly used functions, see Using the RoboClaw Arduino Library. The position commands depend on a tuned position PID; Auto Tuning with Motion Studio covers setting those values automatically.