Setting Things Up

HolonomicLib uses Okapi’s OdomChassisController for output. Thus, we must first create a OdomChassisController object as shown below.

Note

This assumes that you are using namespace okapi

 1std::shared_ptr<OdomChassisController> chassis = ChassisControllerBuilder()
 2    .withMotors(
 3        1,  // Top left
 4        -2, // Top right (reversed)
 5        -3, // Bottom right (reversed)
 6        4   // Bottom left
 7    )
 8    .withSensors(
 9        ADIEncoder{'A', 'B'}, // left encoder in ADI ports A & B
10        ADIEncoder{'C', 'D', true},  // right encoder in ADI ports C & D (reversed)
11        ADIEncoder{'E', 'F'}  // middle encoder in ADI ports E & F
12    )
13    // specify the tracking wheels diameter (2.75 in), track (7 in), and TPR (360)
14    // specify the middle encoder distance (1 in) and diameter (2.75 in)
15    .withOdometry({{2.75_in, 7_in, 1_in, 2.75_in}, quadEncoderTPR})
16    .buildOdometry();

Note

For more details on Okapi’s OdomChassisController, please checkout the Okapi documentation.

Next, create an AsyncHolonomicChassisController object using the AsyncHolonomicChassisControllerBuilder. This will be used to control the robot.

  1. The constructor takes an OdomChassisController that will be used to move the chassis.

std::shared_ptr<AsyncHolonomicChassisController> controller =
    AsyncHolonomicChassisControllerBuilder(std::shared_ptr<okapi::OdomChassisController> ichassis)
  1. Configure PID controllers - you need 2 controllers: one for turning and one for translation

One way you can configure the PID is by inputing the gains directly.

.withDistGains(const okapi::IterativePosPIDController::Gains &idistGains)
.withTurnGains(const okapi::IterativePosPIDController::Gains &iturnGains)

Another way is to supply the actual PID controller objects.

.withDistPID(std::unique_ptr<okapi::IterativePosPIDController> idistController)
.withTurnPID(std::unique_ptr<okapi::IterativePosPIDController> iturnController)
  1. (Optional) Configure the settle parameters for the PID controllers.

.withDistSettleParameters(okapi::QLength imaxError,
                          okapi::QSpeed imaxDerivative,
                          okapi::QTime iwaitTime)
.withTurnSettleParameters(okapi::QLength imaxError,
                          okapi::QSpeed imaxDerivative,
                          okapi::QTime iwaitTime)
  1. Finally, build the controller!

.build()

Here is a complete example of what you might do.

 1std::shared_ptr<OdomChassisController> chassis = ChassisControllerBuilder()
 2    .withMotors(
 3        1,  // Top left
 4        -2, // Top right (reversed)
 5        -3, // Bottom right (reversed)
 6        4   // Bottom left
 7    )
 8    .withSensors(
 9        ADIEncoder{'A', 'B'}, // left encoder in ADI ports A & B
10        ADIEncoder{'C', 'D', true},  // right encoder in ADI ports C & D (reversed)
11        ADIEncoder{'E', 'F'}  // middle encoder in ADI ports E & F
12    )
13    // specify the tracking wheels diameter (2.75 in), track (7 in), and TPR (360)
14    // specify the middle encoder distance (1 in) and diameter (2.75 in)
15    .withOdometry({{2.75_in, 7_in, 1_in, 2.75_in}, quadEncoderTPR})
16    .buildOdometry();
17
18std::shared_ptr<AsyncHolonomicChassisController> controller =
19  AsyncHolonomicChassisControllerBuilder(chassis)
20    // PID gains (must be tuned for your robot)
21    .withDistGains(
22        {0.05, 0.0, 0.00065, 0.0} // Translation gains
23    )
24    .withTurnGains(
25        {0.05, 0.0, 0.00065, 0.0} // Turn gains
26    )
27    // Tolerance (how close the chassis must be to the target before stopping)
28    .withDistSettleParameters(
29        0.5_in, // Max error
30        2.0_in / 1_s, // Max derivative
31        100_ms // Wait time
32    )
33    .withTurnSettleParameters(
34        1.0_in, // Max error
35        2.0_in / 1_s, // Max derivative
36        100_ms // Wait time
37    )
38    .build();

More information regarding the HolonomicLib API can be found here