Mowbot Design & Implementation
User Manual
This section describes how to operate the system.
Raspberry Pi Configuration
Before you can operate the system as described here, you have to configure the Raspberry Pi (rpi4 or rpi zero 2w) board. Follow the instructions in the section "RPi4 and Rpi Zero 2W" to update board firmware, install the Raspberry Pi OS and needed software (including docker) and build the docker image.
Network configuration
The Picostation2 in the robot electronics box is configured for DHCP. Plug the LAN port of its POE injector into any DHCP-enabled network and look on the DHCP server to see which IP device Picostation2-A was given. Send a browser to that IP, log in, and configure the SSID it should connect to. Disconnect from the DHCP-enabled network and power-cycle. The Picostation and rpi should get an IP from DHCP on the wifi network. If the Picostation doesn't show up on the list of DHCP leases, power-cycle it.
Vnc
rpi4 has tiger-vnc-server installed. It starts automatically. Get access to a GUI on the rpi by running:
xtigervncviewer rpi4Note that RealVnc doesn't work on Raspberry Pi OS (bookworm version) as of this writing.
ROS_MASTER_URI (ros1-only)
The default .bashrc sets ROS_MASTER_URI to http://rpi4:11311. It can be changed with the master() bashrc function to, for example, localhost, to run simulation
Mower Startup
Before anything can happen, you must start the ROS SW on the rpi.
ssh rpi4roslaunch mowbot_bringup start.launchTeleoperation
The mower can be driven manually with an X-box compatible game controller. I use a Voyee bluetooth controller. It powers itself off after 5 minutes of inactivity, and the ROS launch must be stopped, gamepad powered back on, and ROS launch restarted.
First, power on the game controller by pressing P3. The red lights on the front of the unit blink then settle with light 1 on. Check laptop bluetooth to ensure the gamepad is communicating. On the laptop, run the xbox launch:
roslaunch mowbot_bringup xbox360_teleop.launchPress the Deadman button 'X' to enable driving. The left joystick controls forward/back, left/right
Basic Autonomous Movement
The runner.py script runs on the laptop and allows stringing together a bunch of commands that are executed autonomously in sequence. Example to rotate 90 degrees CCW them move 0.5m forward:
rosrun mowbot_bringup runner.py roto 90 movo 0.5Without arguments, runner.py prints supported commands
Many example scripts that use runner.py are in catkin_ws/scripts. They should work on both the simulation and hardware.
RTK GPS
Manually start the RTK GPS app by running the launch file on rpi
ssh rpiroslaunch mowbot_hardware F9PRun u-center if needed by plugging the F9P into the dev laptop USB and running it under windows:
Note: I could not get map view to work, despite creating a Google maps API key and installing it into u-center.
Simulation
Set master to localhost. Then run the simulation with the simulation launch file:
master localhostroslaunch mowbot_gazebo gz_mower.launchrosrun mowbot_bringup drive_straight_odom.py 2Tips & Tricks
The ESP32 puts the robot into BIT-mode when it starts. If the robot is not powered on when ESP32 starts, you can re-send the BIT sequence using dynamic reconfigure when start.launch is running on the rpi. Or by power-cycling the ESP32 presumably?
Backups
Backups are on laptop in ~/Documents/Robotics/Mowbot/Backups. To back up the /boot and / partitions of the RPi SSD, plug the SSD into laptop and run:
sudo rsync -aAXv /media/bouchier/writable --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} writableROS 1 Docker Operation
Build the docker container ros1_laptop in ~/Documents/Robotics/Mowbot/Docker/ros1_laptop by running command ./build_it.sh. The container contains the libraries needed to run Mowbot ROS1 SW. It can support a GUI by using vnv
active_docker ros1_x86_linux
docker_build
$ dr # alias for docker run that launches a container with the proper options
$ roscore
$ de # starts a new shell in the running container. Defined in .bashrc
$ rostopic list
Docker tips & tricks
docker system prune # removes stopped containers, dangling images etc
Engineering Documentation
System Requirements
Use Cases
Reset/Restart Autonomy Layer or Motion Control Layer and system resumes operation
Stop Autonomy Layer and robot stops in safe state
Run Autonomy + Motion SW in simulation (for system test/dev purposes)
System cannot complete mission, so cancels it. (Examples: cannot escape bumper press, critically low battery)
Analyze logs & bags from runs, with visibility into all important aspect
Requirements
System shall transport packets between Autonomy Layer and Motion Control Layer with integrity checking
System shall drop packets that fail checks
System design shall be tolerant of dropped packets (Hi-want)
System shall provide realtime performance for motion control loops
System shall ramp wheel velocity to requested level at an achievable rate. Rationale: steps in motor power may produce perturbations.
System shall log important motion-control layer data to bag files
- Non-functional requirements
System shall have modular design (non-functional)
System Description
Mowbot is based on a modified Friendly Robotics RL500 robotic mower. (Friendly Robotics is now Robomow - a division of MTD.) The mower was built and sold around the year 2000, and is a second-generation unit. (Robomow is now on their 5th generation).
The grey battery box in the rear of the unit, which used to house two 12V 18Ah SLA batteries has been repurposed to hold some LiPo batteries and the custom electronics. It is now called "The Electronics Box".
The stock RL500 electronics is used as-is to run the drive motors and blade motors and provide overload/overtemp and other protection. A diagnostic port on the back of the Mower Controller is wired to the electronics box, from where custom software issues drive and blade motor commands and senses robot status. The protocol for talking to the mower is proprietary and has not been released.
The system-design approach taken is to use the OEM mower as-is (as much as possible) to gain the benefits of its mechanical design and low-level motor control HW and FW, and to install smarter, RTK-GPS-based navigation hardware and software to provide improved operation. The goals of the upgraded design are:
Mow in a back-and-forth fashion, as a human would do
Support arbitrary-shaped mowing and navigation zones which have fixed obstacles that can be mapped
Eliminate the boundary-wire
Avoid sensed obstacles before collision (to the degree possible) and react to unsensed obstacles with which the mower collides
Navigate between mowing areas
Return to a charging station / home when necessary or when not in use
The picture below shows the mower with its major components. The mower controller can be used to drive the mower, but apart from the diagnostic port, is otherwise unused. The lid of the electronics box has the GPS antenna and a depth camera on it. RTK-GPS is used for localization, and the depth camera for obstacle detection and remote teleop control. A buck-boost DC-DC converter is powered from a scavenged laptop power brick, and provides shore power and charging power to the mower and electronics box.
Electronics Box Block Diagram
The block diagram is shown below.
Electronics Box Components Function
The electronics box has a 2-layer architecture:
Autonomy layer, provided by Raspberry Pi running ROS
Realtime layer, provided by ESP32 running FreeRTOS in an Arduino environment
The Autonomy layer provides mission planning and execution control, including overall direction control and vision-handling. The Realtime layer provides the interface to the mower, and odometry and other low-level data that should be handled in a realtime manner.
The Raspberry Pi is network connected by a Picostation Wifi device which allows communication to the home Wifi access point and thereon to the internet. RTK GPS corrections are obtained over Wifi from an internet corrections source (rtk2go).
The ESP32 runs the realtime software at a 20Hz loop rate. The realtime software comprises:
The RL500Comms task which drives the mower via a serial link wired to a jack that plugs into the back of the grey control box recessed into the top of the mower.
The Odometry task, which measures the time between odometer sensor pulses and reports odometry data
The PiLink task, which passes messages back and forth to the Raspberry Pi.
HW Configuration
Mobot's HW configuration is:
Compute Subsystem
Raspberry Pi 4B with 8GB memory, 16GB SD card, for autonomy processing. Serial ports connected for console access, connectivity to ESP32
StarTech.com SATA to USB Cable - USB 3.0 to 2.5" SATA III Hard Drive Adapter (Amazon)
Samsung Electronics 870 EVO 500GB 2.5 Inch SATA III Internal SSD (for faster boot, updates, log storage) (Amazon)
Atolla 4-port powered USB hub with USB 3.0 Data Ports (Amazon) - used to power camera, SSD from external power (Amazon)
Sparkfun Thing Plus ESP32 board with under-mounted protoboard for wiring, level shifters
Sensors
Sparkfun GPS-RTK-SMA breakout ZedF9P
Adafruit 9-DOF Absolute Orientation IMU Fusion Breakout - BNO055
Comms
Ubiquity Picostation 2 - network bridge that connects to Rocket2 access point. It's old tech, but I had a Ubiquity Rocket M2 in my attic already.
POE injector to provide 24V to Picostation
Power Subsystem
Daly Smart BMS 7S 24V 30A Li-ion BMS (Amazon)
SSR-25DD Solid State Relay Input 3-32V DC output 5-60V DC) with heatsink (Amazon)
DROK DC-DC Buck Converter 12V/24V to 5V 5A/25W to power robot electronics (Amazon)
Maxmartt 50A Solar Panel Battery Charging Ideal Diode (Amazon)
Turnegy 4S 5Ah battery from Hobbyking.com
Turnegy 3S 5Ah battery from Hobbyking.com
External equipment
Voyee Wireless PS3 gamepad for teleop-ing robot
Laptop 19V 3A power supply for shore power / charging
DC DC Buck Boost Converter Variable Voltage Regulator CC CV 0.5 - 30V adjustable power supply
Ubiquity Rocket 2 access point mounted in attic. Associated POE injector to connect to home network router
Electronics Box
This section shows the construction of the electronics box and associated HW. The picture below shows the electronics box without its lid, wired to the controller. The mower-encoder signals are tapped into inside the mower chassis and brought to the electronics box via a connector under the box.
The rear of the box is a flap that can be opened for maintenance when the box is removed from the mower. Mounted to it are a Raspberry Pi running ROS and ethernet-connected to the wifi station. Beside the Raspberry Pi is a box containing an ESP32 microcontroller running FreeRTOS in the Arduino environment, and a Ublox ZED-F9P GPS receiver. Under the ESP32 is a level-shifter proto board, which converts the 5V encoder pulses to 3.3V.
The picture below shows the rear view of the electronics box with its flap open and its lid beside it. Labels identify the RPi, GPS receiver, ESP32 on the flap, as well as the Picostation which provides wifi access, and the powered USB hub which provides power to the high-power devices (camera, SSD). The lid with GPS antenna and the depth camera are identified.
A clear plastic mid-plane mounting plate holds the wifi station, POE injector, USB hub and SSD. The wifi station is a Ubiquity pico-station that links to a Ubiquity Rocket M2 access point in the attic of my house. The SSD is mounted to the back side of the midplane. See the picture below.
The front wall of the box is the power plane, with an ideal diode, 24v->5V converter, SSR and terminal strips. See the Power Subsystem section for design details. See the picture below, which is taken with the midplane removed from its mount and folded rearward. The SSD on the midplane can be seen. The antenna for the Picostation can be seen mounted to the front right wall.
Looking down from the top of the electronics box, the BMS and IMU are labeled. They are mounted to the base of the electronics box, below the rear flap and midplane assemblies..
Mowbot is shown below without its cover. The 3 blade motors and two drive motors can be seen, encircling the single large control board which handles the serial protocol from the electronics box and contains the motor drivers..
Power Subsystem Design
See the power wiring diagram below for detailed design. The major features of the design are:
Included BMS protects LiPo batteries
External Buck-boost DC-DC converter can charge batteries at up to 1 amp, and and run electronics indefinitely. Charger connects to "Charge" connector for charging batteries, and BMS disconnects batteries when they are charged. Charger is set to 30V 1 amp (current-limited), so supplied voltage folds back to battery charge voltage during charging when batteries ask for more than 1 amp. Charger connects to "Shore Power" connector to provide power to electronics indefinitely without consuming battery energy.
Ideal diode presents minimal power loss when running off batteries, and allows batteries to "back up" the charger during momentary power surges or when running motors, by providing current requirements that exceed the 1 amp the charger can provide.
mower_5V (active when mower is powered on) turns on SSR which powers the custom electronics through a 24V->5V DC-DC converter. Switched power sw_5V and sw_24V power microcontrollers, USB sensors, POE wireless station power, etc. When mower powers down (e.g. timeout after inactivity), relay removes power from custom electronics, so as to avoid draining batteries. Electronics-powerdown can be overridden with the override switch through a switching diode, which keeps electronics awake independent of mower power-down state.
SW Operation
Use Cases
Reset/Restart Autonomy Layer or Motion Control Layer and system resumes operation
Stop Autonomy Layer and robot stops in safe state
Run Autonomy + Motion SW in simulation (for system test/dev purposes)
System cannot complete mission, so cancels it. (Examples: cannot escape bumper press, critically low battery)
Analyze logs & bags from runs, with visibility into all important aspects
SW Requirements
System shall transport packets between Autonomy Layer and Motion Control Layer with integrity checking
System shall drop packets that fail checks
System design shall be tolerant of dropped packets (Hi-want)
System shall have modular design (non-functional)
System shall provide realtime performance for motion control loops
System shall ramp wheel velocity to requested level at an achievable rate. Rationale: steps in motor power may produce perturbations.
System shall log important motion-control layer data to bag files
SW design
The image below shows the block diagram of the SW that runs in the electronics box.
The ROS SW repo is at https://github.com/PaulBouchier/Mowbot
The ESP32 FW is in several repos:
MowbotRealtime - the main project that instantiates the library components and provides the Mediator pattern: https://github.com/PaulBouchier/MowbotRealtime
PiLink - the ESP32 side of the link to the RPi: https://github.com/PaulBouchier/PiLinkTest.git
Encoder task: https://github.com/PaulBouchier/PiLinkTest.git
RL500CommTask. This repo is not public, because it currently contains the proprietary RL500 comms protocol. It may be released in part in the future (without the proprietary mower messages).
Odometry & Drive Train
Mowbot Drive Train Measurements
Gear Sizes
Motor gear: 18 teeth
2nd gear: large: 87 teeth, small: 21 teeth => ratio: 4.83 from motor
3rd gear: large: 81 teeth, small: 17 teeth => ratio: 3.85 from 2nd gear
4th gear (wheel drive): 60 teeth => ratio: 3.52 from 3rd gear
Total gear reduction: 65.45
Wheel diameter: 26cm => wheel circumference: 0.817m
Hall effect sensor toggles each time a magnet goes by. Two magnet passes/motor revolution. Sensor holds output from last sensor until the one on the opposite side passes over it, when it toggles. i.e. output toggles each half motor rotation, complete cycle each rotation.
At max speed (manual operation on blocks), wheels turned 19 times in 30 sec, i.e. 0.63 rot/s => 0.517m/s => 41 motor revs/sec at max speed. Therefore I will see 41 cycles (80 transitions) per sec at max speed. Each cycle represents 0.817m/65.45 = 0.012m of wheel movement. Each transition represents 0.0062m of wheel movement. At full speed, transitions will happen every 12ms, at 1/4 speed every 48ms. i.e. with a 50ms control loop, only get 4 transitions/cycle at full speed, 1 transition/cycle at 1/4 speed. IOW not enough transitions to control wheel speed.
Proposal: Control period between transitions
Block diagram and sample timing diagram shown below.
Encoder ISRs place timestamps into queues each time a left or right encoder changes state (each half motor revolution). The MowbotOdometry task pulls the encoder change timestamps out of the queue every 50ms and processes them to develop leftSpeed and rightSpeed, and the robot pose x, y, and theta.
ESP32 Design
The ESP32 embedded computer is mounted on a carrier which contains TTL->3V converter logic, and terminations for other electronics managed by the ESP32. The HW block diagram is shown below.
The ESP32 runs FreeRTOS as shipped from the factory. It is used to ensure that the IP stack gets sufficient run-time on CPU-0. The PlatformIO development environment is used to create the software system, which spawns several tasks when it starts:
RL500CommsTask: handles a queue of requests going to the mower serial port and status coming back
PiCommsTask: handles the COBs protocol used to pass messages between the ESP32 and the RPi
EncoderTask: Handles encoder transitions and computes odometry. Reads magnetic heading from BNO55 and populates odom_extra
The design is highly object-oriented, with each spawned task running in an object which may contain other objects appropriate to its function.
The design uses the mediator pattern, in which a mediator object acts as an interface to each of the other classes, so that none of the other classes (MowbotOdometry, RL500CommsTask, PiLink, TxLog, TxOdometry) need have direct interfaces to each other - they all go through the MowbotMediator object to communicate with each other. This simplifies testing each object by itself - a dummy mediator sufficient for that object's interfaces is all that's needed.
Dev Environment
ESP32 code is developed with the PlatformIO extension to VS-Code. The workspace definition is on Paul's laptop in ~/Documents/PlatformIO/Projects/MowbotEsp32-workspace.code-workspace. There are 4 projects that make up the codebase:
MowbotRealtime: Contains the MowbotMediator object, and instantiates the other major objects (RL500CommsTask, MowbotOdometry, PiLink), to which it retains references. It passes a reference to itself to each of the other major objects. It does not run its own task - tasks call through it to communicate with mediated objects. Code is in https://github.com/PaulBouchier/MowbotRealtime
MowbotOdometry: Contains the MowbotOdometry object. Code is in https://github.com/PaulBouchier/EncoderTest. The object's init() function spawns the task that runs this object . The task reads encoder pulses and tracks odometry and reads IMU data from the BN055. MowbotMediator is its interface to the other ESP32 tasks.
PiLink: Contains the PiLink object. Code is in https://github.com/PaulBouchier/PiLinkTest. The object's init() function spawns the task that runs this object. The task sends and receives messages from the RPi over the serial link. MowbotMediator is its interface to the other ESP32 tasks.
RL500CommsTask: Contains the RL500CommsTask object. Code is in Paul's dropbox: Dropbox/GitRepos/RL500CommTaskTest.git. It is private at this time because it exposes the BIT interface to the RL500, which is the subject of an NDA.
MowbotRealtime Startup
The system follows the Arduino model for startup: the setup() function is called once, then the loop() function is called continuously.
MowbotRealtime/src/main.cpp contains the setup() entrypoint for the software system. The module instantiates the MowbotOdometry, PiLink, and RL500CommsTask classes. The module also instantiates messages used by each module to communicate. The Arduino setup() entry point calls each object's init() function which spawns the task that does that objects's work. The loop() function does no work.
The module provides a library in MowbotRealtime/lib/MowbotRealtime/src which mediates calls from the three tasks and passes them on to the proper object for servicing.
RL500CommsTask
This task contains messages that are passed between it and the mower. There are two general kinds of message: TxMsg going to the mower, and RxMsg coming from the mower. It also contains a request queue upon which other tasks can place various kinds of RL500TaskRqst messages. RL500CommsTask pulls requests off the request queue and actions them by interacting with the mower. Requests can be things like motor speed request, BIT-mode request to put the mower into BIT mode, light-mode request to set the light on or off, and so on. A block diagram of the objects used by the task is shown below.
MowbotOdometry task
To be written
RPi4 and Rpi Zero 2W Configuration
This section describes how to install the latest Raspberry Pi OS onto an SSD on a Raspberry Pi and to configure it for developing ROS software.
The overall approach taken is to run Raspberry Pi OS on the RPi, because it is the latest and best suited to RPi hardware, but ROS programs are run inside a docker container, because ROS isn't supported on Raspberry Pi OS. The ROS docker container uses the host's networking stack, and mounts /dev for hardware access.
User bouchier is the main user account on both laptop and the RPi and inside the ROS docker container, and has ability to commit to github from either laptop or rpi4, and to ssh from laptop to rpi4 without needing to enter a password.
ROS source code is saved in the recommended places on RPi OS and is edited (generally) on the RPi OS filesystem then built and tested and run in the docker container. Build products are stored on the RPi OS filesystem, so as to persist across container instances.
Containers are (generally) removed after each use, and re-instantiated from the image each time they're started. See the ROS docker page for more details.
The ROS docker containers are configured with the ROS GUI apps, which can be run either on the rpi or on the laptop. Generally, running on the laptop will be better.
rpi-imager Configuration
In this step we connect the boot media (typically SD-card, but could be SSD) to the laptop, run rpi-imager to install a firmware update image or a Raspberry Pi OS image, then reconnect the boot media to the rpi and boot the rpi from it.
Load the latest rpi-imager on to your laptop. At least 1.8.4 is needed.
Install the firmware updater and update the rpi board firmware
Install Raspberry Pi OS 64-bit. As of this writing, rpi-imager didn't offer Rpi OS bookworm for the rpi zero 2 W. The latest 64-bit OS for the hardware is preferred. I installed on rpi zero 2W legacy (not Full, not Lite) to the boot media. (May require going into "Other images"). Configure initial user account, password, and networking parameters, and enable ssh before writing the boot media by using the "edit boot options" function. For these instructions, the rpi4 was loaded with the Bookworm version and rpi-z2w with the Bullseye version
Connect a monitor and keyboard/mouse, connect the boot media to the rpi and boot
Verify remaining space is sufficient.
RPi4 SSD Boot Notes
Updated RPi firmware to latest
Installed latest stable RPi OS (Bookworm) with extras to SSD using rpi-imager running on my linux laptop, with SSD connected to laptop
Booted RPi from SSD
I found it important to run the SSD off a powered USB3 hub - it would get disk errors and disconnect if run directly off the RPi USB3 port
I found doing a proper power-cycle to be important. If I only power-cycled the RPi, or switched the disk off/on, it could hang and refuse to boot until I power-cycled the electronics module.
Disk I/O Benchmark results
Insalled and ran the storage benchmark test with the following command:
sudo curl https://raw.githubusercontent.com/TheRemote/PiBenchmarks/master/Storage.sh | sudo bashwhich gave the following RPI4-with-SSD performance results, which are about in the middle of the range of reported results:
Category Test Result HDParm Disk Read 322.23 MB/s HDParm Cached Disk Read 308.07 MB/s DD Disk Write 60.8 MB/s FIO 4k random read 10773 IOPS (43093 KB/s) FIO 4k random write 7864 IOPS (31459 KB/s) IOZone 4k read 23416 KB/s IOZone 4k write 17973 KB/s IOZone 4k random read 18942 KB/s IOZone 4k random write 21717 KB/sScore: 5183
The RPi zero 2W with SD card gave the following performance results:
Category Test Result HDParm Disk Read 22.07 MB/sec HDParm Cached Disk Read 22.10 MB/sec DD Disk Write 12.4 MB/s FIO 4k random read 2073 IOPS (8294 KB/s) FIO 4k random write 872 IOPS (3488 KB/s) IOZone 4k read 7978 KB/s IOZone 4k write 2964 KB/s IOZone 4k random read 6458 KB/s IOZone 4k random write 4068 KB/sScore: 1071
RPi4 Firmware Config
This section describes settings in the boot config files, and associated pins. The only change required is to modify config.txt and cmdline.txt See the table below for the mapping of UARTs to pins, devices, and use. All 5 UARTs are enabled.
Precondition: Booted the RPi with an external monitor and Keyboard/Mouse
Open a terminal in the GUI and edit /boot/config.txt using vi or nano. Add the following lines:
Add the following lines to file /boot/config.txt to enable serial console on UART 2, 3, 4 and 5 (/dev/ttyAMA2-5):
Reboot and check that /dev/ttyAMA2-5 exist. Reference: see discussion of how to enable serial ports here.
Edit /boot/cmdline.txt and replace "console=serial0,115200) with "console=ttyAM4,115200". and remove the boot options "quiet" and "plymouth.ignore-serial-consoles". This causes the OS to output boot messages to the serial console
RPi Zero 2W Config
This section describes settings in the boot config files. The only change required is to modify config.txt and cmdline.txt.
Precondition: Booted the RPi with an external monitor and Keyboard/Mouse
Open a terminal in the GUI or use the command line and edit /boot/config.txt using vi or nano. Add the following lines:
This causes the OS to present a login on the serial console, and to print boot messages to the serial console.
Edit /boot/cmdline.txt and remove the boot options "quiet" and "plymouth.ignore-serial-consoles". This causes the OS to output boot messages to the serial console
Verify serial console and networking (RPi4 and RPi Zero 2W)
Connect a USB serial cable to the RPi Serial console connection, and on the laptop, run miniterm /dev/ttyUSB0 115200 to connect from PC to rpi via USB serial. Reboot from the monitor/keyboard and verify you see boot messages come out on the miniterm terminal. Verify you can log in. The USB-serial connection is your back-door into the system in case you're in the field and can't access the rpi through ususal methods.
The miniterm command uses .bash.aliases: alias miniterm='python -m serial.tools.miniterm --eol LF'. But cursor movement commands don't work: backspace, vi is crap.
Use the monitor/keyboard to connect to Wifi. Check you know the IP the rpi was given, and ssh to it from your laptop to verify the ability to connecto over the network.
Use the keyboard/monitor to shut down the board, or use the poweroff command. Disconnect keyboard/monitor, and reapply power. Verify you can ssh to the board after it boots.
Raspberry Pi OS Configuration
These are the steps to configure Raspberry Pi OS on Mowbot's RPi once it has been installed and is bootable.
change /etc/hostname as appropriate. Edit /etc/hosts to make rpi4 a name for 127.0.1.1
Add the hostname of the rpi and it's IP to the laptop's /etc/hosts file
Ensure ping www.google.com works
Update and upgrade list of packages. sudo apt update; sudo apt upgrade
From laptop, install user bouchier's ssh public & private keys to allow rpi to commit to github: scp .ssh/id_rsa* bouchier@<hostname>/home/bouchier/.ssh
On laptop, create .ssh/config file that causes ssh rpi4 to connect to host rpi4 as user bouchier. .ssh/config should contain the following:
Optional (seems important for rpi zero 2W): Increase swap size using these instructions: https://pimylifeup.com/raspberry-pi-swap-file/
Mowbot Ubiquity Config
Plug in the ubiquity microstation or a wired ethernet cable
Apply the netplan: sudo netplan apply
Check link status: ip addr show dev eth0
Package Installation
This section describes installation of packages needed to make ROS on RPi work as desired. Note: some of these steps are no longer necessary if using the 1.8 version of rpi-imager; it does a lot more to pre-configure the system.
VNC
VNC was chosen for graphical use because generally the robot's RPi would run headless, but remote desktop capability is sometimes valuable.
Observations: the current version of RPi OS doesn't support the RealVNC server which ships with it, owing to it using Wayland and RealVNC using X11. Tigervnc is the recommended alternative
install tigervnc-standalone-server
edit /etc/tigervnc/vncserver-config-mandatory to uncomment $localhost="no" so as to allow remote connections
Run tigervncpasswd and set a password
Install xterm
copy xstartup into .vnc???
manually start tigervncserver on rpi
Test vnc: on laptop: xtigervncviewer -SecurityTypes VncAuth,TLSVnc <hostname>:1
Kill the vnc session on the rpi with tigervncserver -kill :1
Firefox (Optional)
Install firefox: sudo apt install firefox
miniterm
Configure python for miniterm, (serial port access from python, etc). sudo apt install python-is-python3; sudo apt install python3-pip; Add the following to .bash_aliases: alias miniterm='python -m serial.tools.miniterm --eol LF'
git config file (~/.gitconfig)(
Configure git to use my favorite aliases & tools. Note that git difftool would have to be run in a VNC window, since it uses meld, which is a graphical diff app. Add the following to ~/.gitconfig. Note: the indented lines need to be preceeded by tab, not spaces
[user] email = paul.bouchier@gmail.com name = Paul Bouchier[alias]s = statusco = checkout
[diff]tool = meld[difftool]prompt = false[difftool "meld"]cmd = meld "$LOCAL" "$REMOTE"
[merge]tool = meld[mergetool "meld"]cmd = meld "$LOCAL" "$MERGED" "$REMOTE" --output "$MERGED"
Make ROS source directories
mkdir -p catkin_ws/srcmkdir -p ros2_ws/srcMowbot GPS Packages
u-center (dev laptop only)
Install u-center on laptop running Windoze. u-center is a Windoze (x86) tool for checkout and analysis of ublox receivers.
Download latest version (v22.05) of u-center (not u-center2) from the ublox site. Unzip and run under windows:
UTM conversion
These steps install packages which convert the GPS lat-lon fix to UTM, for easier use with odometry, rviz etc. The GeographicLib which contains conversion routines is built as part of the ROS docker container. The ROS-UTM-LLA package which subscribes to the /gps/fix topic and uses the GeographicLib library to convert the fix to UTM and publishes the UTM fix needs to be cloned. Note: the UTM zone parameter in ROS-UTM-LLA is not used in this application, and can be left as-is.
ROS-UTM-LLA package: https://github.com/PaulBouchier/ROS-UTM-LLA
git clone git@github.com:PaulBouchier/ROS-UTM-LLA.gitrviz_satellite (dev laptop only)
The rviz_satellite package provides an rviz plugin that enables viewing robot position in the context of satellite imagery. You need to create your own Mapbox account and get a mapbox api key (www.mapbox.com) and insert your key into the AerialMapDisplay URI. Note: my URI key has been obfuscated in the git repo to limit unauthorized use of my account.
Reference: https://github.com/nobleo/rviz_satellite
Clone rviz_satellite into the dev laptop ROS src directory
git clone https://github.com/nobleo/rviz_satellite.gitublox-gps
rtcm_msgs
Docker Installation and Configuration
Install docker on rpi from these instructions: https://docs.docker.com/engine/install/debian. Use the "Install using the apt repository" section of the instructions. Be sure to verify the installation by running the docker hello-world image per instructions
Continue to run the docker post-install instructions at https://docs.docker.com/engine/install/linux-postinstall/ to enable managing docker from your non-root account. Verify you can run the docker hello-world container without sudo.
Add the following to .bashrc on the Rpi:
active_docker () { if [ $# -eq 1 ]; then echo ${1} > ~/.active_docker fi export ACTIVE_DOCKER=`cat ~/.active_docker` echo $ACTIVE_DOCKER}
# Docker aliasesexport PATH_TO_ROS_DOCKERS=${HOME}'/ROS_dockers'
alias docker_build='cd ${PATH_TO_ROS_DOCKERS}/${ACTIVE_DOCKER} && docker build -t ${ACTIVE_DOCKER} .'alias dr='cd ${PATH_TO_ROS_DOCKERS}/${ACTIVE_DOCKER} && ./run_it.sh $@'alias dsl='docker start -ai `docker ps -lq`'alias de='docker exec -it `docker ps -lq` bash'
# ROS aliasesalias swri_console='rosrun swri_console swri_console'
Clone my ros_docker repo from git@github.com:PaulBouchier/ROS_dockers.git
Build ros1_rpi and ros2_rpi dockers after setting the ACTIVE_DOCKER env variable by using the active_docker shell script
Launch a ros1 or ros2 container using the dr alias and build the workspace in the container using standard ROS procedures from the ROS1 or ROS2 tutorials
Mowbot SW Installation & Test
This section describes how to install Mowbot's ROS SW and related packages onto the RPi.
Install pySerialTransfer: pip install pySerialTransfer
Clone Mowbot repo, install needed dependencies, and build it:
cd src; git clone git@github.com:PaulBouchier/Mowbot.git; cd ..; rosdep install --from-paths src --ignore-src -y; catkin_make. This should complete without errors.
Verify /dev/ttyAMA1 exists - it is used to talk to the ESP32
Run the Mowbot start launch file: roslaunch mowbot_bringup start.launch
Test Results and Observations
RPI4 Performance
RPi running COBS test decoder decoding 14 byte PacketSerial packet took 20us to decode the packet
Building Mowbot SW inside a container took 3 min 31 sec.
RPi Zero Performance
Running tigervncserver with chromium launched in it, 256MB of memory was used by user processes, the swap daemon was running, and performance was noticably sluggish
On rpi zero 2w the OS (Full version) used 9.2GB. The OS (lite version) used 1.4G, but was up to 8.8GB after installing dockers for ros1 & ros2. The not-full, not-lite version used 4.4GB for just the OS install. Installing the ros2 docker increased usage to 8.3GB and adding the ros1 docker brought it to 11GB used.
I increased swap to 1GB
Building the ros1 and ros2 dockers each took a bit over half an hour. Free memory was frequently below 100 MB and 400 MB of swap was occasionally used.
Building Mowbot SW inside a container took 101 min 40 sec, load average 4 - 7! Much swapping as indicated by kswapd consuming significant CPU % in top
It ran my Robocolumbus code driving the sim (which was runnng on the laptop) and the Robocolumbus code took 30% of a CPU.
Building Mowbot SW with catkin_make tended to hang even with 1GB swap. Tried -j1 option. It took 88 minutes for a partial build
Power
BMS phone app doesn't display discharge current, only charge current
BMS was unable to charge the old 4S + new 3S battery to 100% - peaked at 98% with 30V 1A charge power applied
BMS bluetooth is off when battery is disconnected.(maybe after a timeout). It wakes back up when a load is placed on the battery
Notes
ZED-F9P
After 1 minute of no corrections it drops out of RTK Fixed mode. If corrections are re-instated, even a minute later, it very quickly re-enters RTK mode
If ZED-F9P is powered on and allowed to run without corrections for a minute, it never achieves RTK lock
ZED-F9P drops out of RTK Fixed mode immediately the antenna is placed on top of the electronics box. Moving it to 0.5 - 1m away allows it to regain RTK Fixed in about a minute, and keep it. Thesis: EMI from the electronics box is upsetting the sensitive amplifiers in the powered antenna.