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

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
- Add your GitHub username to the discord thread
 - You will be invited to the following
 
1.1 Recommended Directory Structure
~/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 gitWindows
- 
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."- You can also install Linux for Windows via WSL (Windows Subsystem for Linux)
- Once setup, Git can be installed using the Linux package manager
 
 
Ubuntu
- Install Git
 
sudo apt install gitConfigure 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.emailSet 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- 
In GitHub, navigate to Settings β SSH and GPG keys β New SSH Key and paste it there (example)
 - 
Confirm that your SSH key is connected to your GitHub account
 
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 ~/ocr2. Create the dev_ws and src folder inside it (ROS packages will be installed in src later)
mkdir -p dev_ws/src3. Create training_ws folder and src folder inside it
mkdir -p training_ws/src4. Create ocr-docker folder
mkdir ocr-docker5. Verify that folders have been created inside ocr
lsdev_ws  ocr-docker  training_ws1.4 OCR Docker
Step 1: Install the container
- 
Install and open Docker Desktop
 - 
Clone the repo and cd into it
 
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
- As an example, we will install differential_drive_robot in 
src 
cd ~/ocr/dev_ws/src- Clone the repository
 
git clone git@github.com:oc-robotics/differential_drive_robot.gitStep 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- Browse http://localhost:6080/ to access the remote desktop via VNC
 

- Stop the container
 
exit # Exit the interactive shell
docker-compose stop- If you need to remove the container
 
docker-compose downTroubleshooting
- 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 10011.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
- 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_controlplugin, /cmd_vel must be remapped as follows: 
ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/diff_cont/cmd_vel_unstamped1.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
- Install Arduino IDE
 
2.2 L293D Motor Driver
- Wire the circuit for the motor driver
 

- Upload the following 
L293D_motor_driver.inosketch 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));
}



