https://chxtio.github.io/ocr_jekyll/

Table of Contents

Project Introduction

This instruction manual outlines the process of designing and building Sonar Viz Bot- a training project intended to introduce new OCR members to the engineering design process. It aims to quickly develop the core skills and competencies for rookies to meaningfully contribute to club projects and eventually compete in the University Rover Challenge (URC).

Timeline

picture 47

1. Software Setup

The configuration of Git, GitHub, and SSH and the software environment setup is described. To streamline the development process, we have created a Docker container with Ubuntu 22.04, ROS2 Humble, and dependencies.

1.0 Join the Github Organizations

~/ocr/
β”‚
β”œβ”€β”€ dev_ws/
β”‚   β”œβ”€β”€ build/
β”‚   β”œβ”€β”€ install/
β”‚   β”œβ”€β”€ log/
β”‚   └── src/
β”‚       └── differential_drive_robot/
β”‚
β”œβ”€β”€ ocr-docker/
β”‚   β”œβ”€β”€ Dockerfile
β”‚   β”œβ”€β”€ README.md
β”‚   └── docker-compose.yml
β”‚
└── training_ws/
       └── src/

1.2 Setting Up Git, GitHub, and SSH

Install Git

Mac

  • Install homebrew and follow the terminal instructions
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  • Install git
brew install git

Windows

  • Install Git for Windows, which provides Git Bash (terminal emulator for running Git commands)

  • Or- install using Windows Powershell

winget install --id Git.Git -e --source winget
  • Note: if the above command didn’t work, you may need to install winget first
$progressPreference = 'silentlyContinue'
Write-Host "Installing WinGet PowerShell module from PSGallery..."
Install-PackageProvider -Name NuGet -Force | Out-Null
Install-Module -Name Microsoft.WinGet.Client -Force -Repository PSGallery | Out-Null
Write-Host "Using Repair-WinGetPackageManager cmdlet to bootstrap WinGet..."
Repair-WinGetPackageManager
Write-Host "Done."

Ubuntu

  • Install Git
sudo apt install git

Configure Git

  • Configure Git, replacing "Your name" and "your.email@example.com" with your info (including the quotes) to link your local Git profile with GitHub
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
  • Verify configuration
git config --get user.name
git config --get user.email

Set up SSH

  • Create a new SSH key using your GitHub email as a label

Note: Press enter to skip through the 3 prompts that follow

ssh-keygen -t ed25519 -C "your.email@example.com"
  • Copy the public key to your GitHub account (See example)
cat ~/.ssh/id_ed25519.pub
ssh -T git@github.com
  • if successful, you should see:
Hi username! You've successfully authenticated, but GitHub does not provide shell access.

1.3 Create Initial Directory Structure

Preview

~/ocr/
β”‚
β”œβ”€β”€ dev_ws/
β”‚   └── src/
β”‚
β”œβ”€β”€ ocr-docker/
β”‚
β”œβ”€β”€ training_ws/
β”‚   └── src/

1. Create ocr folder and cd into it

mkdir ~/ocr && cd ~/ocr

2. Create the dev_ws and src folder inside it (ROS packages will be installed in src later)

mkdir -p dev_ws/src

3. Create training_ws folder and src folder inside it

mkdir -p training_ws/src

4. Create ocr-docker folder

mkdir ocr-docker

5. Verify that folders have been created inside ocr

ls
dev_ws  ocr-docker  training_ws

1.4 OCR Docker

Important: If you have already installed the container, skip to Step 3: Run the docker container.

Step 1: Install the container

cd ocr
git clone https://github.com/oc-robotics/ocr-docker.git
cd ocr-docker
  • Pull the base image from Docker Hub
docker pull mwoodward6/nekton:humble
  • Build the custom image
docker build -t ocr-docker:humble .

Step 2: Install any ROS pacakges

cd ~/ocr/dev_ws/src
  • Clone the repository
git clone git@github.com:oc-robotics/differential_drive_robot.git

Step 3: Run the docker container

  • Start the container in the background (detached mode)
docker-compose up -d
  • Optional: Open an interactive bash shell inside the container to run commands
docker exec -it ocr-humble-nekton-og bash

picture 45

  • Stop the container
exit # Exit the interactive shell
docker-compose stop
  • If you need to remove the container
docker-compose down

Troubleshooting

  • If you encounter an error due to port 6080 being in use, check which processes are using it
sudo lsof -i :6080
  • Sample output
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
docker-pr  995 root    4u  IPv4  27629      0t0  TCP *:6080 (LISTEN)
docker-pr 1001 root    4u  IPv6  26542      0t0  TCP *:6080 (LISTEN)
  • Stop the processes
sudo kill -9 995 1001

1.5 Differential Drive Robot

  • Open a terminal (run Terminator in NoVNC) and cd into dev_ws/src
cd dev_ws/src
  • Build the package
colcon build --symlink-install
  • Source the setup
source install/setup.bash
  • Run the Gazebo simulation `
ros2 launch differential_drive_robot launch_sim.launch.py

picture 42

  • Visualize in Rviz
rviz2 -d src/differential_drive_robot/config/diff-drive.rviz
  • Drive the Robot with Keyboard Input (open a new terminal inside Terminator and run the following command line)
ros2 run teleop_twist_keyboard teleop_twist_keyboard
  • Note: If using ros2_control plugin, /cmd_vel must be remapped as follows:
ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/diff_cont/cmd_vel_unstamped

1.6 Raspberry Pi Setup

This setup uses a Raspberry Pi 4. The OS must be configured by flashing the microSD card with Ubuntu 22.04 (see more) and installing ROS2 Humble.

Setup

  • Install Rapberry Pi Imager

  • Insert the microSD card and choose OS β†’ other general purpose SO β†’ Ubuntu Desktop 22.04 LTS (64-bit)

  • Set up Ubuntu desktop

  • Follow the instructions for installing ROS2 Humble on the Raspberry Pi

  • Todo: Set up SSH on the pi for remote connections

Connecting Peripherals to the Raspberry Pi

  • LCD Screen

    • Display: Connect the micro-HDMI port on the Raspberry Pi to the HDMI port on the screen
    • Power/touch screen: Use a micro-USB cable to connect the LCD screen to a USB port on the Raspberry Pi (not just for power, but also for data)
  • Raspberry Pi

  • Power: Connect the USB-C port on the Raspberry Pi to a power bank or wall outlet.

2. Electrical Setup

2.1 Software

2.2 L293D Motor Driver

  • Wire the circuit for the motor driver

picture 0

  • Upload the following L293D_motor_driver.ino sketch to the Arduino
// L293D Motor Driver pins for right motor (Motor A)
const int ENA = 11;    // PWM speed control for right motor
const int IN1 = 13;    // Direction control 1 for right motor
const int IN2 = 12;    // Direction control 2 for right motor
 
// L293D Motor Driver pins for left motor (Motor B)
const int ENB = 10;    // PWM speed control for left motor
const int IN3 = 8;     // Direction control 1 for left motor
const int IN4 = 9;     // Direction control 2 for left motor
 
const int switchPin = 7; // Switch to turn robot on/off
 
int motorSpeed = 0; // Starting motor speed
 
void setup() {
    pinMode(switchPin, INPUT_PULLUP);
 
    pinMode(IN1, OUTPUT);
    pinMode(IN2, OUTPUT);
    pinMode(ENA, OUTPUT);
 
    pinMode(IN3, OUTPUT);
    pinMode(IN4, OUTPUT);
    pinMode(ENB, OUTPUT);
 
    Serial.begin(9600);
    Serial.println("To infinity and beyond!");
    motorSpeed = 255;
    Serial.print("Motor Speed: ");
    Serial.println(motorSpeed);
}
 
void loop() {
    motorSpeed = 255;
    // if (digitalRead(switchPin) == LOW) { // Switch ON (pressed)
    if (digitalRead(switchPin) == HIGH) { // Switch OFF 
        rightMotor(motorSpeed);
        leftMotor(motorSpeed);
    } else { // Switch OFF
        rightMotor(0);
        leftMotor(0);
    }
}
 
void rightMotor(int speed) {
    if (speed > 0) {
        digitalWrite(IN1, HIGH);
        digitalWrite(IN2, LOW);
    } else if (speed < 0) {
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, HIGH);
    } else {
        digitalWrite(IN1, LOW);
        digitalWrite(IN2, LOW);
    }
    analogWrite(ENA, abs(speed));
}
 
void leftMotor(int speed) {
    if (speed > 0) {
        digitalWrite(IN3, HIGH);
        digitalWrite(IN4, LOW);
    } else if (speed < 0) {
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, HIGH);
    } else {
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
    }
    analogWrite(ENB, abs(speed));
}