Home

Awesome

Build status

<!-- Build Status populated by Github Actions runs -->
ROS 2 DistroBranchBuild status
RollingrollingRolling Firmware Build
HumblehumbleHumble Firmware Build
GalacticgalacticGalactic Firmware Build
FoxyfoxyFoxy Firmware Build

Installation

All software mentioned in this guide must be installed on the robot computer.

1. ROS2 and linorobot2 installation

It is assumed that you already have ROS2 and linorobot2 package installed. If you haven't, go to linorobot2 package for installation guide.

2. Download linorobot2_hardware

cd $HOME
git clone https://github.com/linorobot/linorobot2_hardware -b $ROS_DISTRO

3. Install PlatformIO

Download and install platformio. Platformio allows you to develop, configure, and upload the firmware without the Arduino IDE. This means that you can upload the firmware remotely which is ideal on headless setup especially when all components have already been fixed.

curl -fsSL -o get-platformio.py https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py
python3 get-platformio.py

Add platformio to your $PATH:

echo "PATH=\"\$PATH:\$HOME/.platformio/penv/bin\"" >> $HOME/.bashrc
source $HOME/.bashrc

4. UDEV Rule

Download the udev rules from Teensy's website:

wget https://www.pjrc.com/teensy/00-teensy.rules

and copy the file to /etc/udev/rules.d :

sudo cp 00-teensy.rules /etc/udev/rules.d/

5. Install Screen Terminal

sudo apt install screen

Building the robot

1. Robot orientation

Robot Orientation:

-------------FRONT-------------

WHEEL1 WHEEL2 (2WD)

WHEEL3 WHEEL4 (4WD)

--------------BACK--------------

If you're building a 2 wheel drive robot, assign MOTOR1 and MOTOR2 to the left and right motors respectively.

For mecanum robots, follow the wheels' orientation below.

mecanum_wheels_orientation

2. Motor Drivers

Supported Motor Drivers:

The motor drivers are configurable from the config file explained in the later part of this document.

3. Inertial Measurement Unit (IMU)

Supported IMUs:

4. Connection Diagram

Below are connection diagrams you can follow for each supported motor driver and IMU. For simplicity, only one motor connection is provided but the same diagram can be used to connect the rest of the motors. You are free to decide which microcontroller pin to use just ensure that the following are met:

Alternatively, you can also use the pre-defined pin assignments in lino_base_config.h. Teensy 3.x and 4.x have different mapping of PWM pins, read the notes beside each pin assignment in lino_base_config.h carefully to avoid connecting your driver's PWM pin to a non PWM pin on Teensy.

All diagrams below are based on Teensy 4.0 microcontroller and GY85 IMU. Click the images for higher resolution.

4.1 GENERIC 2 IN

generic_2_in_connection

4.2 GENERIC 1 IN

generic_1_in_connection

4.3 BTS7960

bts7960_connection

4.4 IMU

imu_connection

Take note of the IMU's correct orientation when mounted on the robot. Ensure that the IMU's axes are facing the correct direction:

4.5 System Diagram

Reference designs you can follow in building your robot.

A minimal setup with a 5V powered robot computer. minimal_setup

A more advanced setup with a 19V powered computer and USB hub connected to sensors. advanced_setup

For bigger robots, you can add an emergency switch in between the motor drivers' power supply and motor drivers.

Setting up the firmware

1. Robot Settings

Go to the config folder and open lino_base_config.h. Uncomment the base, motor driver and IMU you want to use for your robot. For example:

#define LINO_BASE DIFFERENTIAL_DRIVE
#define USE_GENERIC_2_IN_MOTOR_DRIVER
#define USE_GY85_IMU

Constants' Meaning:

ROBOT TYPE (LINO_BASE)

MOTOR DRIVERS

INERTIAL MEASUREMENT UNIT (IMU)

Next, fill in the robot settings accordingly:

#define K_P 0.6
#define K_I 0.8
#define K_D 0.5

#define MOTOR_MAX_RPM 100             
#define MAX_RPM_RATIO 0.85          
#define MOTOR_OPERATING_VOLTAGE 24
#define MOTOR_POWER_MAX_VOLTAGE 12
#define MOTOR_POWER_MEASURED_VOLTAGE 11.7

#define COUNTS_PER_REV1 2200    
#define COUNTS_PER_REV2 2200      
#define COUNTS_PER_REV3 2200      
#define COUNTS_PER_REV4 2200      

#define WHEEL_DIAMETER 0.09  
#define LR_WHEELS_DISTANCE 0.2  

#define PWM_BITS 10
#define PWM_FREQUENCY 20000

Constants' Meaning:

2. Hardware Pin Assignments

Only modify the pin assignments under the motor driver constant that you are using ie. #ifdef USE_GENERIC_2_IN_MOTOR_DRIVER. You can check out PJRC's pinout page for each board's pin layout.

The pin assignments found in lino_base_config.h are based on Linorobot's PCB board. You can wire up your electronic components based on the default pin assignments but you're also free to modify it depending on your setup. Just ensure that you're connecting MOTORX_PWM pins to a PWM enabled pin on the microcontroller and reserve SCL and SDA pins for the IMU, and pin 13 (built-in LED) for debugging.

// INVERT ENCODER COUNTS
#define MOTOR1_ENCODER_INV false 
#define MOTOR2_ENCODER_INV false 
#define MOTOR3_ENCODER_INV false 
#define MOTOR4_ENCODER_INV false 

// INVERT MOTOR DIRECTIONS
#define MOTOR1_INV false
#define MOTOR2_INV false
#define MOTOR3_INV false
#define MOTOR4_INV false

// ENCODER PINS
#define MOTOR1_ENCODER_A 14
#define MOTOR1_ENCODER_B 15 

#define MOTOR2_ENCODER_A 11
#define MOTOR2_ENCODER_B 12 

#define MOTOR3_ENCODER_A 17
#define MOTOR3_ENCODER_B 16 

#define MOTOR4_ENCODER_A 9
#define MOTOR4_ENCODER_B 10

// MOTOR PINS
#ifdef USE_GENERIC_2_IN_MOTOR_DRIVER
    #define MOTOR1_PWM 21 //Pin no 21 is not a PWM pin on Teensy 4.x, you can swap it with pin no 1 instead.
    #define MOTOR1_IN_A 20
    #define MOTOR1_IN_B 1 

    #define MOTOR2_PWM 5
    #define MOTOR2_IN_A 6
    #define MOTOR2_IN_B 8

    #define MOTOR3_PWM 22
    #define MOTOR3_IN_A 23
    #define MOTOR3_IN_B 0

    #define MOTOR4_PWM 4
    #define MOTOR4_IN_A 3
    #define MOTOR4_IN_B 2

    #define PWM_MAX pow(2, PWM_BITS) - 1
    #define PWM_MIN -PWM_MAX
#endif  

Constants' Meaning:

Calibration

Before proceeding, ensure that your robot is elevated and the wheels aren't touching the ground. 5.1

1. Motor Check

Go to calibration folder and upload the firmware:

cd linorobot2_hardware/calibration
pio run --target upload -e <your_teensy_board>

Available Teensy boards:

Some Linux machines might encounter a problem related to libusb. If so, install libusb-dev:

sudo apt install libusb-dev

Start spinning the motors by running:

screen /dev/ttyACM0

On the terminal type spin and press the enter key.

The wheels will spin one by one for 10 seconds from Motor1 to Motor4. Check if each wheel's direction is spinning forward and take note of the motors that are spinning in the opposite direction. Set MOTORX_INV constant in lino_base_config.h to true to invert the motor's direction. Reupload the calibration firmware once you're done. Press Ctrl + a + d to exit the screen terminal.

cd linorobot2_hardware/calibration
pio run --target upload -e <your_teensy_board>

2. Encoder Check

Open your terminal and run:

screen /dev/ttyACM0

Type sample and press the enter key. Verify if all the wheels are spinning forward. Redo the previous step if there are motors still spinning in the opposite direction.

You'll see a summary of the total encoder readings and counts per revolution after the motors have been sampled. If you see any negative number in the MOTOR ENCODER READINGS section, invert the encoder pin by setting MOTORX_ENCODER_INV in lino_base_config.h to true. Reupload the calibration firmware to check if the encoder pins have been reconfigured properly:

cd linorobot2_hardware/calibration
pio run --target upload -e <your_teensy_board>
screen /dev/ttyACM0

Type sample and press the enter key. Verify if all encoder values are now positive. Redo this step if you missed out any.

3. Counts Per Revolution

On the previous instruction where you check the encoder reads for each motor, you'll see that there's also COUNTS PER REVOLUTION values printed on the screen. If you have defined MOTOR_OPERATING_VOLTAGE and MOTOR_POWER_MEASURED_VOLTAGE, you can assign these values to COUNTS_PER_REVX constants in lino_base_config.h to have a more accurate model of the encoder.

Upload the firmware

Ensure that the robot pass all the requirements before uploading the firmware:

Run:

cd linorobot2_hardware/firmware
pio run --target upload -e <your_teensy_board>

Testing the robot

1. Run the micro-ROS agent.

This will allow the robot to receive Twist messages to control the robot, and publish odometry and IMU data straight from the microcontroller. Compared to Linorobot's ROS1 version, the odometry and IMU data published from the microcontroller use standard ROS2 messages and do not require any relay nodes to reconstruct the data to complete sensor_msgs/Imu and nav_msgs/Odometry messages.

Run the agent:

ros2 run micro_ros_agent micro_ros_agent serial --dev /dev/ttyACM0

2. Drive around

Run teleop_twist_keyboard package and follow the instructions on the terminal on how to drive the robot:

ros2 run teleop_twist_keyboard teleop_twist_keyboard 

3. Check the topics

Check if the odom and IMU data are published:

ros2 topic list

Now you should see the following topics:

/cmd_vel
/imu/data
/odom/unfiltered
/parameter_events
/rosout

Echo odometry data:

ros2 topic echo /odom/unfiltered

Echo IMU data:

ros2 topic echo /imu/data

URDF

Once the hardware is done, you can go back to linorobot2 package and start defining the robot's URDF.

Troubleshooting Guide

1. One of my motor isn't spinning.

2. Wrong wheel is spinning during calibration process

3 One of my encoders has no reading (0 value).

4. The wheels only spin in one direction

5. The motor doesn't change it's direction after setting the INV to true.

6. Nothing's printing when I run the screen app.

7. The firmware was uploaded but nothing's happening.

8. The robot's forward motion is not straight

9. The robot rotates after braking

Developers

Adding firmware compilation tests for a new ROS distro

To add a new distro to the CI tests, modify the rolling (default) branch. Inside of .github/workflows, duplicate an existing distro workflow YAML file. For example, to add ROS2 Iron support, one could copy humble-firmware-build.yml to iron-firmware-build.yml. Assuming that an iron branch exists (if not one could create one using the humble branch as a base and modify as necessary), inside of iron-firmware-build.yml, rename all instances of the word humble with iron. It would be as simple as using 'find and replace' in many IDEs. Commit these changes to a feature branch, create a PR to merge into the rolling branch, and then backport the PR to other branches. It is only necessary to have iron-firmware-build.yml on the rolling and iron branch, however it may be simpler to keep the branches in sync by having every workflow file on all branches.

Lastly, the new branch must be added to the CI table written in Markdown at the top of README.md that displays the status of each branch using badges. This table is organized with the most current ROS2 branch at the top, which is always rolling, and then in descending chronological order. Adding a new distro can be done by copying an existing row of the table, pasting in the appropriate position, and changing the titles and branch names in the relative paths.