2. Base Controller

Juan Miguel Jimeno edited this page Sep 2, 2018 · 23 revisions

ROS navigation stack drives the robot by publishing velocity commands to /cmd_vel topic using geometry/Twist messages. The base controller on the Teensy board receives the twist messages through rosserial_python and translates the velocites to motor commands. A PID controller maintains the robot's speed by calculating how much PWM signal must be generated to spin each motor based from the total error over time. Errors are derived by comparing the actual motor's speed to the desired speed sent by navigation stack. This section will show you how to tune the PID controller with lino_pid, wire up the components, and upload the base controller's code on the Teensy board.

2.1 Building the hardware

Before wiring up the components, build a base made up of wood plank, acrylic sheet or any material that you can mount the electronics, motors and wheels. Some ideas for your robot base:


Storage box from Ikea. (Photo by Ikea)


Plastic enclosure box. You can easily find this on hardwares stores.


Tin storage box. (More metallic look)

Once you have a base, wire up the components as shown below (2.1.2).

2.1.1 Wire up

The hardware is designed to be modular and scalable in the future. All the platforms are built using a L298N motor driver (2 Amperes) and motors with built-in encoders. If your robot requires a much higher motor rating or higher encoder resolution, you can opt for components with better specification and use the same pin assignments as below without rewriting the firmware.


Not all motors have built-in encoders especially high torque motors. Shall you need to use an external encoder, you can use a bi-shaft motor to leave the spare shaft for the encoder or use a pulley to drive both the wheels and the encoder.


A photo of a bi-shaft motor connected on a wheel (left side) and a wheel encoder (right side). Motor with built-in encoder


If you're replacing the motor driver with a higher specification, make sure the motor's power draw is less than the motor driver's power rating. You can use the same firmware and follow the same pin assignments below as long as your new motor driver has PWM, IN1, and IN2 pins.

2WD Wiring


4WD and Mecanum Drive wiring


Ackermann Steering wiring


2.2 Uploading the firmware

Before uploading the codes, identify and define your robot’s specification in the config file.

On your robot’s computer, open and edit the lino_base_config.h:

roscd linorobot/teensy/firmware/lib/config
nano lino_base_config.h

Make sure to define variable DEBUG as 1 for debugging later.

There's only one firmware for all the supported robot base so you have to define which one you're building.

//uncomment the base you're building
#define LINO_BASE DIFFERENTIAL_DRIVE // 2WD and Tracked robot w/ 2 motors
// #define LINO_BASE SKID_STEER      // 4WD robot
// #define LINO_BASE ACKERMANN       // Car-like steering robot w/ 2 motors
// #define LINO_BASE ACKERMANN1      // Car-like steering robot w/ 1 motor
// #define LINO_BASE MECANUM         // Mecanum drive robot

Define your Motor Driver:

//uncomment the motor driver you're using
#define USE_L298_DRIVER
// #define USE_BTS7960_DRIVER
// #define USE_ESC

Define your IMU:

//uncomment the IMU you're using
#define USE_GY85_IMU
// #define USE_MP6050_IMU (not supported yet)
// #define USE_MPU9150_IMU
// #define USE_MPU9250_IMU

Define your robot's specification:

//define your robot' specs here
#define MAX_RPM 330               // motor's maximum RPM
#define COUNTS_PER_REV 1550       // wheel encoder's no of ticks per rev
#define WHEEL_DIAMETER 0.10       // wheel's diameter in meters
#define PWM_BITS 8                // PWM Resolution of the microcontroller
#define LR_WHEELS_DISTANCE 0.235  // distance between left and right wheels
#define FR_WHEELS_DISTANCE 0.30   // distance between front and rear wheels. Ignore this if you're on 2WD/ACKERMANN
#define MAX_STEERING_ANGLE 0.415  // max steering angle. This only applies to Ackermann steering

If you are unsure what is the encoder’s PPR (COUNTS_PER_REV) – you can check the encoder’s total count from minimal.launch’s terminal (see 2.3.1). Get the recent count and rotate the wheel 360 degrees:


If you have the encoder and motor’s specification:


The first time you upload your codes using platformio, it will prompt if you want to install the framework (ie. ‘teensy’) you are using. Press ‘y’ to proceed with the installation. Once the framework is installed, plug in the Teensy board to the robot’s computer and upload the codes:

roscd linorobot/teensy/firmware
platformio run --target upload

If you are using MPU6050 IMU, remember to set use_mag param on imu_madgwick_filter to false since it has no magnetometer. Open imu.launch:

roscd linorobot/launch/include/imu
nano imu.launch

Set the second parameter to false:

<node pkg="imu_filter_madgwick" type="imu_filter_node" name="imu_filter_madgwick" output="screen" respawn="false" >
    <param name="fixed_frame" value="base_footprint" />
    <param name="use_mag" value="true" />
    <param name="publish_tf" value="false" />
    <param name="use_magnetic_field_msg" value="true" /> 
    <param name="world_frame" value="enu" />
    <param name="orientation_stddev" value="0.05" />

2.3 Running the robot

2.3.1 Driving the robot

Now check if the wheels’ direction is correct. Lift the robot off the ground so the wheels can move freely.

If you’re building a mecanum drive robot take note of the roller’s orientation below:

Mecanum Orientation

On your robot's computer, run the launch file to start ROS and rosserial_python:

roslaunch linorobot minimal.launch

On your development computer, run teleop_twist_keyboard:

rosrun teleop_twist_keyboard teleop_twist_keyboard.py

Follow the instructions on the terminal to move the robot.

For Ackermann steering robots, the angular velocity is translated to the robot's steering angle since it can’t rotate in-place. Check if the front wheels steer left and right when you press ‘j’ and ‘l’ respectively.

2.3.2 Check the encoder readings

Next, check if the encoder readings are correct from the terminal where you ran minimal.launch. All encoder readings must increase as you drive forward, and decrease as you drive in reverse.

2.3.3 Troubleshooting

If the wheel’s direction is wrong as you drive forward or reverse, swap the pin assignments for MOTOR*_IN_A and MOTOR*_IN_B in the config file found in section 2.1.1.

If the encoder returns opposite results, swap the pin assignments for MOTOR*_ENCODER_A and MOTOR*_ENCODER_B in the config file found in section 2.1.1

If the front wheels on the Ackermann robot are steering in the opposite direction, swap PI and 0 in steer() function.

servo_steering_angle = mapFloat(steering_angle, -MAX_STEERING_ANGLE, MAX_STEERING_ANGLE, PI, 0) * (180 / PI);

2.4 Calibrating PID

In order to maintain the speed sent by navigation stack, your PID controller has to be tuned properly. You can use lino_pid to tune your PID constants.

On your robot’s computer, open a new terminal:

Run minimal.launch:

roslaunch linorobot minimal.launch

On your development computer, open 3 new terminals:

Run pid_configure:

rosrun lino_pid pid_configure

Run teleop_twist_keyboard:

rosrun teleop_twist_keyboard teleop_twist_keyboard.py

Open rqt:


Once the dashboard is open, import the .perspective file by clicking Perspective > Import and choose lino_pid.perspective from lino_pid package: ~/catkin_ws/src/lino_pid/lino_pid.perspective.

PID Graph

Click pid_configure under Dynamic Reconfigure window and slide the parameters at the bottom right window to tune your PID constants. Drive the robot and see the results from the graph.

Here are some tips how to configure your PID constants (Page 13).

Once your PID constants are tuned, record the values and edit the config file:

roscd linorobot/teensy/firmware/lib/config
nano lino_base_config.h

and change the values of K_P, K_I, K_D to the PID values you have recorded. Also, remember to change back variable DEBUG to 0.

#define K_P 0.6 // P constant
#define K_I 0.3 // I constant
#define K_D 0.5 // D constant

Upload the updated PID constants to the Teensy board:

roscd linorobot/teensy/firmware
platformio run --target upload

3. Odometry

Great! The robot base is done and ready for dead reckoning. Proceed to Odometry page.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.