This project by Carnegie Mellon University's Kantor Lab is part of the LEAP research initiative, which focuses on deploying automation and mechanization to address labor shortages in the US nursery crop industry.
The goal of this project is to make a robot which can autonomously spray weeds with herbicide in and around pot-in-pot tree nurseries and other spaces.
Note
The team working on this project has disbanded after the 2026 summer. More details on the project state and future directions intended for those who pick up working on this project in the future can be found here.
This project uses Pixi to manage dependencies for the project. After ensuring Pixi is installed on your system, run the following to download and install dependencies for the project:
git clone https://github.com/Kantor-Lab/LEAP_sprayer.git leap_sprayer_ws
cd leap_sprayer_ws
pixi installOn Linux machines, you should also follow these instructions to support using an Intel Realsense. That basically boils down to running
sudo curl "https://raw.githubusercontent.com/realsenseai/librealsense/refs/heads/master/config/99-realsense-libusb.rules" \
-o /etc/udev/rules.d/99-realsense-libusb.rulesand for communicating with the Arduino (at least for us because we were using a knockoff brand) you'll need to uninstall or kill the Braille screen reader support so Linux doesn't recognize it as a screen reader and try to take it over
To uninstall completely
sudo apt remove --purge brlttyor to just disable it and set it to not startup again
sudo systemctl stop brltty.service brltty-udev.service
sudo systemctl mask brltty.service brltty-udev.serviceIn addition, for Linux users planning to flash the firmware of an Arduino, you'll need to follow these instructions to let PlatformIO install for you. That boils down to
curl -fsSL https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/system/99-platformio-udev.rules | sudo tee /etc/udev/rules.d/99-platformio-udev.rulesPotentially, after doing either of these, you may need to run sudo service udev restart to see the changes,
and maybe unplug and replug connected devices a few times.
To build all the nodes, run
pixi run buildThis command should also be run automatically if you run other custom pixi run commmands
because they will declare a depends-on for the build command.
Builds are cached when running this commands, so if no changes are made to the src folder,
no build will have to be run.
To launch the system (for simulation/testing), run
pixi run launchYou can optionally pass arguments to the underlying launch.py to startup different things.
For example, to use the Realsense camera instead of the debug camera, run
pixi run launch camera:=realsenseThe launch task supports the following arguments:
camera: the camera to usedetector: the detector to use for detecting weedsprojector: the algorithm to use when converting 2D bounding boxes to 3D onestracker: the algorithm to use for tracking detected bounding boxes over timedebugwill just override all tracking and directly emit debug boxesdedup(real, but rough tracking) andextrapolate(just reemitting all known boxes) can be paired withdebug_(e.g.debug_dedupis default) to run the debug emitter and pipe it through the given tracker
nozzle_dispatcher: the system that chooses which nozzle(s) to turn on to hit bounding boxesnozzle_controller: service to send nozzle commands to actual hardware (or not, for testing)debug_odom: (true/false) whether to emit a constant velocity via a transform betweenodomandsprayer_baseimage_viewer: (true/false) whether to launch the RQT image viewerfoxglove: (true/false) whether to launch the Foxglove bridge- This also starts visualization tools for some of the bounding boxes, so may be useful to enable when creating a Rosbag (see launch.py for more details on what is launched)
To start up on the real robot, run
pixi run launch-livewhich is equivalent to
pixi run launch camera:=realsense nozzle_controller:=arduino tracker:=dedupSeveral of these options will read environment variables for on-the-fly customization. You can customize them by doing something like
DEBUG_CAMERA_PORT=1 RANDOM_SEED=42 pixi run launchDEBUG_CAMERA_PORT: the port number for the debug camera node to useARDUINO_PORT: the port identifier for the live serial controller node to find the Arduino onCONSTANT_VELO: an identifier in a format like0.25,+X(0.25 m/s in the positive x direction) used by the constant velocity odometryGROUND_Z_HEIGHT: also used by constant velocity odometry to determine how much to translate thesprayer_baseframe above theodomframeRANDOM_SEED: used by the test emitter to seed its random number generator, allowing for reproducible results (it will tell you what seed it uses at startup)
If you need to do additional work in the shell, run
pixi shellThis gives you access to everything, but does not source install/setup.sh.
If you need a sourced shell (this will work regardless of what shell you use),
pass the -e sourced flag.
We use PlatformIO for building and deploying code
onto the Arduino UNO that powers our solenoids.
This is automatically managed through pixi, so pixi shell -e firmware
will give you full access to the tool in your shell.
To build firmware without going through this, run
pixi run build-firmware [controller] [upload|no_upload] [uno|nano]There are currently three controllers implemented
(corresponding to PlatformIO environments in firmware/solenoid_controller/platformio.ini)
live_pwm: communicates with real solenoid drivers and emits PWM signalslive: communicates with the real solenoid drivers (old)test_led: triggers leds from PWMs 2–4 for testing purposes
You can test the serial controller manually by connecting over USB and running
pixi run serial-connectto give you a prompt where you can input commands and send them to the Arduino.
This project currently tries to support the following platforms, based on where development occurs on it and where it is deployed.
- Jetpack 6 (Ubuntu 22.04) on Jetson Orin Nano (AArch64)
- Ubuntu 22.04 (x86-64)
- macOS (arm64) for development
Warning
macOS is only supported to the extent that pixi run build should work
and you should have access to ros tools while developing.
This is mainly so that editors can see the ros dependencies
and provide proper code completion and linting.
Intel Realsense is known to be incredibly buggy and often not work at all
on macOS, but we include versions of libraries so that message types
are available. (relevant)
Other platforms will likely not work properly, but it may be possible to get it to work.
If you try to run pixi install on a different platform,
you will receive an error with instructions on how to add your platform to the pixi.toml file
(something like pixi workspace platform add <your-unsupported-platform>).
However, for non-Linux platforms, the ros-humble-realsense2-camera package is not available,
so it had to be built from source to work on arm64 macOS here.
This
might be a good starting point for building the package from source on other platforms.
You can add local packages by giving the path in the pixi.toml channels section.
See commit f1f5494
for more details on this.
There are several useful tools available when developing this project. Many of these are borrowed from the Pixi docs on working with ROS2.
Pixi should be used to add dependencies to the project, rather than via rosdep (which is not supported by Pixi).
This way, dependencies can be automatically installed by others using the project with a simple pixi install command.
Pixi will also ensure the dependencies are available for the target platforms
(currently ARM macOS and x86-64 Linux for development, with an AArch64 Linux Jetson Nano for deployment).
You can learn more about how ROS2 dependencies are supported by RoboStack and Pixi here.
To add a new dependency, run pixi add <package_name> in the project directory.
It should now be available whenever you run commands via pixi run or in the pixi shell.
pixi run pkg-create my_package my_nodeThis will create a new node named my_node in the my_package package.
Instead of using flake8 like most ROS2 projects, for speed and reproducibility this project uses Ruff.
It is configured to closely match the style guide used by most ROS2 projects,
see ruff.toml for more details.
pixi run checkwill check your code for formatting and linting errors.
pixi run check fixwill automatically fix any fixable errors in formatting or linting.
You can also run with more options if you want to only lint or only format
pixi run check [fix|no_fix] [reformat|no_reformat]where no args is equivalent to no_fix and no_reformat
and only fix is equivalent to fix and reformat.
You will almost certainly need to point your LSP at the Python installation
that is pulled in after running pixi install.
This will probably be .pixi/envs/default/bin/python3.11.
While there is not type checking support bundled with the repo,
it does include a pyrightconfig.json,
which will allow Pyright (default for VS Code and Zed) to discover
some necessary interfaces for type checking.
A build (via pixi run build) may be required before full checking support is available.
For other editors or checkers, I recommend exploring how to mimic the contents of that configuration, as a cursory search suggests it should be possible in PyCharm or in other checkers like ty.