FruitBot Help Page

From startup to shutdown. This page covers the ins and outs of FruitBot.

FIRST CONNECTION



We will start simply with on and off.
To turn FruitBot ON, start by flipping the rocker switch to the right of the EGO battery. Next, connect the blue spade and prong at the front of the robot, tucked in to the left of the Raspberry Pi. The system should be ready in less than one minute.

To turn FruitBot OFF, press the Red button to the left of the Raspberry Pi. This will send a signal to start the shutdown process. Wait for the blue LED to turn off, then wait another 10 seconds before disconnecting the blue spade and prong connection. Once the Raspberry Pi is off, you can switch off the power in back to the right of the EGO battery.

To get 'under the hood' of FruitBot we will use several techniques to monitor and control the software and hardware. SFTP can be used as file sharing to review and edit the Python and Arduino code to manage all aspects of the robot. The Mac Terminal can be used to SSH into the Raspberry Pi device for live control. From there, you can update the Arduino .ino files and send them to either of the Arduino boards using arduino-cli.
SSH keys are used to log into Raspberry Pi so passwords are not needed. Below is the Terminal code that will copy your public SSH key over to FruitBot.

cat ~/.ssh/id_rsa.pub | ssh pi@fruitbot.local 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys'

If copying the SSH key fails, you may have to setup an SSH key pair for yourself.

Create SSH Key Pair
- On the client computer, make the hidden directory '.ssh' in the user folder, -p = if needed & without error message
mkdir -p ~/.ssh
- move into the directory and generate a key pair
cd ~/.ssh && ssh-keygen -b 1024 -t rsa -f id_rsa -P ''
- Make sure you are disconnected from the host, then copy your local public key to the server.
cat ~/.ssh/id_rsa.pub | ssh administrator@server2.example.com 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys'
- Type 'yes' if asked about a fingerprint.
- Enter the server password.
- The mkdir command is included in the key copy command to make the .ssh folder on the host computer if necessary.



To take control of the software that runs FruitBot, start by connecting to the Raspberry Pi using SSH.

ssh://pi@fruitbot.local

When you first login, you should be met with a VERY simple menu that allows you to quickly perform some basic tasks. This is the run by the 'menu.sh' file, and launches using the .bashrc config file. Modify the .bashrc to turn off the menu, and modify the menu.sh file to change the menu commands.

GENERAL



Robot Web Control interface.

http://fruitbot.local:5020/

UV4L Streaming Video.

https://fruitbot.local:8080/

There are some personal conventions I tend use in the code (inconsistently). Global variables start with 'v', local variables start with 'w' and functions start with 'fn'. This helps me distinguish language developed in code vs. functions that are part of the language. I have not memorized the list of functions for all the programming languages I use. Arduino code is indented with spaces, since that's what the Arduino IDE prefers, and everything else is indented with tabs. For files with lots of code, there should be a table of contents at the top. I use that to quickly copy a function name and search for it to jump to a section. Most comments and references have been moved to the bottom of the file. I am an experienced developer, so I do not rely on any cloud services, all support code has been loaded locally.

When booting up, it takes about 60 seconds for the FruitBot web page to be available. It used to be much faster (~20 seconds), but I installed some GUI tools to allow a locally connected display to be used for map navigation. That increased the startup time quite a bit.

To turn off FruitBot, use the power switch to turn off main power from the EGO battery. RPi monitors 5V power on GPIO 22, and when main power is turned off, RPi waits for 1 minute, than runs the shutdown process. If main power is turned back on before the minute is up, shutdown is cancelled.

This is a differential drive stem, with tow motors connected to two wheels. Turning is achieved by applying different speeds to different wheels. In the code, a spin is defined as one wheel forward and one wheel back. An even amount of space is needed all around the robot for the spin to work. A turn is defined as one wheel moving twice as fast as the other. No room is needed on the left when turning right, so a turn is useful when the robot is sitting against a wall and needs to move without scratching the wall. Not scratching the walls was an important factor in the build of this robot.

After 5 minutes of inactivity, ItsyBitsy will switch to low power mode. All the lights switch to a dim red and the system slows down to save power. Send any command to wake it up again. To prevent FruitBot from going to sleep, turn the headlights on or off. FruitBot can only go to sleep when the headlights are set to automatic.

Anyone can take manual control of the robot by using the joystick found near the back. Press the joystick down once to activate it. Press again to deactivate. To shift up one gear, double-click the joystick. Once in top gear, click once more to shift back to the bottom. Having the joystick on does interfere with regular navigation, so turn it off when done. The joystick is NOT tied in to any of the sensors, so it can run into walls and fall down the stairs when using the joystick.

Shutdown button is GPIO 17 connecting to ground. This is controlled by the 'shutdown_button.py' script that runs on boot. This script also monitors the main power source on GPIO 22. If the main power is turned off, a timer starts for 1 minute then shuts down the RPi. If power is restored before then, the shutdown is cancelled. To modify the shutdown script's boot process, edit the rc.local file.

sudo nano /etc/rc.local

To modify code, you can use SFTP as a form of file sharing.

sftp://pi@fruitbot.local

CyberDuck is a popular open-source SFTP client for Mac and Windows. It has been around since 2002. You can download it with the link below.

https://cyberduck.io/

Check the log file to find any problems with the Python program. The log file also records data received from the Arduino boards every 5 minutes (300 sec) controlled by a variable at the top of app.py.

cat ~/static/webserverlog.txt

Also, check the system log file to find any errors.

grep error /var/log/syslog
or
tail /var/log/syslog

Check the kernel log for any hardware problems.

dmesg | tail

Robot Web Control interface is run by a systemd service. Use these commands to control fruitbot service.
(sudo) systemctl status fruitbot - Restart the service to apply any code changes, 'sudo' is optional for status.
sudo systemctl restart fruitbot - Stop stops until next reboot.
sudo systemctl stop fruitbot
sudo systemctl start fruitbot - Disable prevents fruitbot from launching on boot.
sudo systemctl disable fruitbot
sudo systemctl enable fruitbot


Modify fruitbot systemd service.

sudo nano /etc/systemd/system/fruitbot.service

Components of the service.

[Unit]
Description=FruitBot
After=network.target

[Service]
Restart=on-failure
RestartSec=10
StartLimitBurst=3
StartLimitIntervalSec=600
Type=simple
User=pi
Group=www-data
WorkingDirectory=/home/pi/
ExecStart=/usr/bin/python3 /home/pi/app.py

[Install]
WantedBy=multi-user.target


Wait until network services are available.


Restart if the script crashes...
... after a 10 sec delay.
Attempt restart a maximum of 3 times.
If the script stays running for 10 minutes, reset the burst limit.

Run the script with this user's permissions.


This is the script to run.

See if a Python script is running in the background.

ps -aux | grep python

If a script is running in the background, you can kill the process by calling the script name.

pkill -f app.py

To test the fruitbot script, stop the process using systemctl (above) then start the script manually.

python3 app.py


Check to see if sensors are connected on the I2C port.

i2cdetect -y 1

Should return something like this:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- UU -- -- -- -- 1f
20: 20 21 -- -- -- -- -- -- -- 29 -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 69
70: 70 -- -- -- -- -- -- --


See next section for I2C Address Assignments

The CUPS printer driver service has been installed, but is not running because it tends to use 100% of a CPU while idle. This can be turned on again as needed.

sudo systemctl start cups
sudo systemctl stop cups
sudo systemctl enable cups
sudo systemctl disable cups



USB


List all USB devices.

lsusb

Result:
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP2102/CP2109 UART Bridge Controller [CP210x family]
Bus 001 Device 003: ID 239a:802b
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Metro Mini = Cygnal Integrated Products

Arduino boards are connected to RPi through USB so they can be updated directly from the command line. When a board is updated, the USB connection may change. For example if IB was on '/dev/ttyACM0' it could now be /dev/ttyACM1' after update. Restarting app.py should fix that issue because it checks multiple ports when starting. You'll have to change the corresponding part of the CLI command on the next update too.

./bin/arduino-cli compile -b arduino:avr:uno /home/pi/Arduino/FruitBot_NewPing && ./bin/arduino-cli upload -p /dev/ttyUSB0 -b arduino:avr:uno /home/pi/Arduino/FruitBot_NewPing

./bin/arduino-cli compile -b adafruit:samd:adafruit_itsybitsy_m4 /home/pi/Arduino/FruitBot_Sabertooth && ./bin/arduino-cli upload -p /dev/ttyACM0 -b adafruit:samd:adafruit_itsybitsy_m4 /home/pi/Arduino/FruitBot_Sabertooth


Other Arduino commands:

./bin/arduino-cli board list - shows a list of connected boards

Result:
/dev/ttyACM0 Serial Port (USB) Adafruit ItsyBitsy M4 (SAMD51)
adafruit:samd:adafruit_itsybitsy_m4 adafruit:samd
/dev/ttyAMA0 Serial Port Unknown
/dev/ttyUSB0 Serial Port (USB) Unknown

Metro Mini = /dev/ttyUSB0

./bin/arduino-cli board listall - shows a list of all compatible boards

When uploading new code to an Arduino unit, you may experience communication problems afterward. This is probably because the board has changed ports (from ttyUSB0 to ttyUSB1 or from ttyACM0 to ttyACM1). All you have to do is restart the FruitBot service, and it will pickup the new port.

sudo systemctl restart fruitbot


VIDEO CAMERA


Verify the camera is attached and working. You should get something like: '/dev/video0'.

ls /dev/video*

Show information about the camera.

ls -l /dev/video0

Take a picture.

raspistill -o cam.jpg

Record a 7 second video

raspivid -o video.h264 -t 7000

Control UV4L streaming webcam (service and systemctl are interchangable commands, just swap the positions of the action and module).
sudo service uv4l_raspicam status
-OR- sudo systemctl status uv4l_raspicam
sudo service uv4l_raspicam restart
sudo service uv4l_raspicam stop

UV4L control panel.

https://fruitbot.local:8080/panel


Modify UV4L configuration. This controls the webcam.

sudo nano /etc/uv4l/uv4l-raspicam.conf

UV4L configuration can also be modified from this password protected web page.
https://fruitbot.local:8080/config
user: config
pass: mypw

Modify UV4L service.

sudo nano /etc/systemd/system/uv4l_raspicam.service




RESOURCES



Make an Autonomous "Follow Me" Cooler by Aaron Tainter (atainter) 2017 or on GitHub - The 'Follow Me Cooler' was the inspiration that started the FruitBot project. Unfortunately, GPS navigation is only accurate to a city block, so indoor navigation needed different resources.


Drawing Route For Car On The Office's Map - This project provided the indoor navigation possibilities I needed. They used a totally Arduino solution. I opted for a combination of Raspberry Pi and Arduino to leverage the WiFi hardware and server software capabilities already found in the RPi4.


How to Make an Object Tracking Robot Using Raspberry Pi by Automatic Addison 2019 - This was one of my early prototypes. It was easy to build, and worked quite well. FruitBot might be able to follow a person based on the color of their clothes that day. Addison's articles are very clear and easy for me to understand. He also has some good obstacle avoiding robot articles. Fari warning, some articles get very heady very quickly, so brace yourself.


DIY Web Controlled Raspberry Pi Surveillance Robotic Car 2017 - Sets up the live webcam using Motion. This was very easy to set up. But I eventually moved to UV4L software for its low latency and peer-to-peer WebRTC services.


Build a Robot Car with Speed Sensors by DroneBot Workshop 2017 - Deals with the TT motor encoders and optical interrupt sensors. After testing with the TT motors, I switched to stepper motors for better control. Then I got the Power Wheels gearboxes with RS 550 motors for the final FruitBot v1 drive motors. If the project goes well, I may switch to hub motors (like from an electric skateboard) because they are powerful and quiet.


Pathfinding Visualizer by Abdallah Hemdan 2020 or on GitHub


A* (AStar) Search Algorithm in JavaScript by Brian Grinstead (bgrins) 2015 or on GitHub


A* (AStar) Search Algorithm in JavaScript by Brian Grinstead (bgrins) 2015 or on GitHub


Control of Mobile Robots
by Dr. Magnus Egerstedt and Jean Pierre de la Croix
from Corsera 2013
This is how the primary navigation functions were developed. It employs activity states like go-to-goal, avoid-obstacle, and follow wall to make it to its destination. A 'state machine' is used to switch among the techniques until the goal is reached.
http://pysimiam.sourceforge.net
55 video lessons - https://www.youtube.com/playlist?list=PLp8ijpvp8iCvFDYdcXqqYU5Ibl_aOqwjr
To run the simulator, you need Python 2.7 and PyQt4. Old software can be hard to find and even harder to install properly. The best way for PySimiam is to download the full Anaconda 3 virtual machine and install some of the included libraries https://repo.anaconda.com/archive/Anaconda3-2.4.1-MacOSX-x86_64.pkg
- Removed 'conda' lines from ~/.bash_profile
- Left the two Anaconda3 2.4.1 lines.
- deleted the folders ~/opt, ~/.conda, ~/.continuum but left the ~/.condarc file alone.
- reloaded bash profile
source ~/.bash_profile
- now conda is v3.18.8
- looks like pyqt4 is available
- creating new environment
conda create -n pysimiam python=2.7
source activate pysimiam
conda install numpy sip pyqt=4 --use-local
- install seemed to work
python qtsimiam_week1.py
- WORKED!! (I think)

Sobot Rimulator by Nick McCrea - Nick upgraded the code to Python 3, replaced the QtPy4 GUI with Gtk3, and uses a Khepera III robot instead of a QuickBot.
https://www.toptal.com/robotics/programming-a-robot-an-introductory-tutorial

pysimiam_simulator by Delijati (2014)
https://github.com/delijati/pysimiam-simulator

Path Tracking With PID Controller Simulation for Differential Drive Robots in Python by BurakDmb (2019). This is a very simple simulator, but it deals with PID, one of the foundation pieces for the 'Control of Mobile Robots' course. Requires scipy.
https://github.com/BurakDmb/DifferentialDrivePathTracking

Rahul-Ratheesh released his version of PySimiam (2019)
https://github.com/Rahul-Ratheesh/pysimiam
- It has been updated for Python3 and PyQt5.
- Downloaded and tried to run with Python3 on TouchMBP.
- Error - cannot import name 'clock' from 'time'.
- seems clock was depreciated in python 3.3
- Open the 'scripts/simulator.py' file and delete clock import from




Hopefully, some useful docs.
FruitBot ItsyBitsy M4 circuit.pdf
FruitBot Metro Mini circuit.pdf
FruitBot Power diagram 2021-10.pdf
FruitBot RPi GPIO circuit.pdf


GPIO pins Description
2 & 3 (I2C) NXP Compass, Servo HAT, VL53 Laser cliff sensor, GPIO Expander
4 Reset ItsyBitsy
5, 6, 12, 17, 18, 19, 20, 21 Voice Bonnet
13 3 watt LEDs
14 & 15 (UART) MakerFocus UPSpack V3P battery board
16 & 25 GPIO Expander interrupt signals
17 Shutdown Button (shared with Voice Bonnet)
22 Reset VL53 Laser cliff sensor
23 Monitor main power from servo HAT for auto-shutdown
24 Reset NXP compass
7, 8, 9, 10, 11, 13, 26, 27 AVAILABLE

I2C Addresses Description
0x1A or UU Voice Bonnet
0x1F NXP 9DoF Accelerometer, Magnetometer
0x20 GPIO Expander Bonnet
0x21 NXP 9DoF Gyroscope
0x29 VL53L0X laser distance cliff sensor
0x40 & 0x70 Servo HAT

Ultrasonic Connections
FR BR BM BL FL FM ML MR

The ultrasonic connection configuration assumes the top of the robot is upside-down and you are looking at the pins from the back of the robot. A copy of this table should be affixed near these connections as well.

Ultrasonic range is set in the Arduino code to 3cm minimum and 400cm maximum.



These instructions assume you are connected to FruitBot throught the SSH terminal.

- Check the last 10 lines of the kernel log for anything odd.
    dmesg | tail
- Show medium problems, the -T option adds timestamp.
    dmesg --level=err,warn -T

- Check the log file to find any problems with the Python program. The log file also records data received from the Arduino boards every 5 minutes (300 sec) controlled by a variable at the top of app.py.
    cat ~/logs/webserver.log

- Check the system log for errors.
    grep error /var/log/syslog

If the live video feed is not working, try these steps.
- Check to see if the original UV4L feed is working.
    https://fruitbot.local:8080/stream

- Verify the camera is attached and working.
    ls /dev/video*
- You should get something like: /dev/video0.

- Take a picture.
    raspistill -o cam.jpg

- Check UV4L status.
    sudo service uv4l_raspicam status
    sudo service uv4l-webrtc status

- Use the 'top' command to see which apps are using the most CPU and memory.
    top

- Stop the video streaming service if necessary.
    sudo service uv4l_raspicam stop

- Make sure the I2C devices are visible.
    i2cdetect -y 1

- I2C communicates with:
    0x1A or UU - Voice Bonnet
    0x1f & 0x21 - NXP board (accelerometer, gyroscope, magnetometer/compass)
    0x29 - VL53L0X (laser distance cliff sensor)
    0x40 & 0x70 - Servo HAT

- Make sure the SSL certificate is up-to-date.  Look for the 'Not After' date.
    openssl x509 -text -in /etc/ssl/certs/FruitBotCert.pem -noout

- Raspberry Pi stats
    https://www.raspberrypi.org/documentation/computers/configuration.html#firmware-warning-icons
    CPU Load - RPi4 has four cores, so 1 (100%) is not the maximum for the system. RPi Zero has only one core, so 1 (100%) is the max for that.
    CPU Temperature - 55C is typical indoor core temperature. 80-85C shows a warning. Over 85C means the system will throttle back to protect itself.  Without a fan, the small 14mm heatsink can drop 5 degrees  Larger 25mm heatsink can drop 20 degrees.
    Core Clock - RPi4 core clock is 500000992.
    Core Volts - RPi4 core volts is 0.89V.
    Throttling - Any messages here mean problems for performance and/or RPi longevity.


- Compass Offset Values
    If one or more of the compasses are pointing in the wrong direction, the first thing to do is to calibrate them.  On the Controls screen, switch to the Compass tab and click 'Calibrate Compass'  The robot will turn in circles until calibration is complete.
    If the Compasses are still not correct, you can force the direction of the pin by adding or subtracting degrees using the Compass Offset Value fields on the Console page.


MAP RULES:
Yellow cells are obstacle cells positioned on top of walls and 
furniture. This is the maze the robot must navigate around.
HTML span must be formatted like this: <span class='node empty' id='cell_1_20'></span>
Class first, then ID.  ID should have X coordinates, 
then Y coordinates both starting at zero.
Start must be class='node start' not class='node empty start'.
Goal must be class='node goal'.
In my version of this maze solver, once the goal is reached, 
it becomes the new start point.  My version also has hard-coded 
obstacles representing walls and furniture in the home map.

AStar.findPath is the call that produces the solution.
The outputGridAs2DArray function turns the HTML grid into a 
numeric array of arrays for AStar like this.
[[1,0,3,0],
 [0,0,0,2],
 [3,3,0,0]]
- It says, starting at 0,0 (first value in the upper-left corner) 
find a path to 3,1 (4th column, 2nd row).  Remember numbering starts 
at zero, not one.  If you imagine the zeros as flat space and the 
threes as block columns, you can kind of see a representation of 
the map in the numbers.
    0 = empty
    1 = start
    2 = goal
    3 = obstacle

AStar returns an array with cell coordinate objects for a path that looks like this.
[{"x": 0, "y": 1},
 {"x": 1, "y": 1},
 {"x": 2, "y": 1},
 {"x": 3, "y": 1}]
- It says, starting at 0,0 (not given in the results) go down 
  one cell (Y + 1) and right 3 cells (X + 1 + 1 + 1).


The apartment map table is 25 x 43 cells. Each cell represents 8".

Each wood square of our apartment floor is 9" square.
There are 20.5 squares across the living room (east-west).
    20.5 * 9 = 184.5" or 15.4'
    Grid is 25 squares wide - 2 for each wall = 23 squares
    184.5" / 23 squares = 8" per square
There are 25 squares + 7" through the living room (north-south) 
starting at the edge of the stairs.
    25 * 9 + 7 = 232" or 19.3'
    232 / 29 squares = 8" per square