Plant Watering Robot with a Raspberry Pi

Picture of the plant watering robot on a desk.

Building a useful robot doesn’t have to require complicated code or expensive equipment. With a Raspberry Pi and some cheap, basic hardware, you can keep your plants healthy and happy from anywhere in the world!

Follow this tutorial to learn how to set up an automatic plant watering system:

  1. Complete the physical assembly and wiring.
  2. Create and connect to the robot.
  3. Configure your robot’s components.
  4. Configure the capacitive soil moisture sensor as a custom resource.
  5. Write code utilizing the Viam Python SDK to control the plant watering robot.

The tutorial uses the following hardware, but you can adjust it as needed:

Before starting this tutorial, follow the Raspberry Pi Setup Guide to prepare your Pi to run viam-server. Make sure your Pi is flashed with a Viam-compatible operating system, and that you are able to SSH into it.

Set Up your Plant Watering Robot

Before programming the Pi to make the plant watering robot functional, you need to physically set up the plant watering robot by wiring the different components together. You will set up the robot to receive signals from the capacitive soil moisture sensor and signal to the peristaltic pump when it is time to pump water from the water’s container to the plant’s container.

Full Wiring Diagram

Refer back to this diagram as you complete the steps to wire your hardware.

The full wiring diagram for all the hardware for the Plant Watering Robot.

Wire your ADC

The analog-to-digital converter (ADC) converts the capacitive soil moisture sensor’s analog readings to digital signals that can be processed by your Pi, which expects digital signals to come to it through its GPIO pins.

Start by wiring your ADC to your Raspberry Pi board.

You can find a Raspberry Pi pinout diagram at pinout.xyz. Reference the following pinout diagram for your MCP3008 analog-to-digital converter:

Pinout diagram for the ADC.

Insert the MCP3008 into your breadboard so that it bridges both sides of the divide. Then, use the rows on the side of your MCP3008’s pins and the GPIO pins on your PI to connect the pins with wires as follows:

MCP3008 ADC PinRaspberry Pi Pin
VDD3.3V
VREF3.3V
AGNDGND
DGNDGND
CLKSCLK
DOUTMISO
DINMOSI
CS/SHDNGPIO25

Wire your Capacitive Soil Moisture Sensor

Next, wire your capacitive soil moisture sensor to your Pi and ADC.

Reference this diagram of the blue module part of the sensor:

Pinout diagram for the capacitive soil moisture sensor.

Start by connecting the female jumper wires at the end of the sensor prongs to the blue module where the diagram shown above is labeled “Connect with Probe.”

Then, wire the rest of the pins on the module to the Pi and ADC as follows:

PiADC
Moisture Sensor PinRaspberry Pi Pin
VCC3.3V
GNDGND
Moisture Sensor PinMCP3008 ADC Pin
A0 (Analog Signal Output)CH0

Put the soil moisture sensor inside of the container holding your plant.

Wire your Pump

Now, wire and power your Peristaltic Pump motor and motor speed controller to complete your hardware setup.

Reference this diagram of the motor speed controller:

Pinout diagram for the motor speed controller.

  1. Attach alligator wire clips to your battery to connect it to the DC power pins on your motor speed controller. Match the + notation on the battery to the + DC power pin.
  2. Attach alligator wire clips to the pump to connect the output pins on your motor speed controller to the pump.
  3. Connect the GND pin hole on the controller to GND on the Pi.
  4. Connect the PWM pin hole on the pump to Pin 12 (GPIO 18) of the Pi. Note that the controller does not come with header pins.

Program Your Plant Watering Robot

Enable SPI on your Pi

Now that you have wired your ADC and moisture sensor, make sure that the Serial Peripheral Interface (SPI) is enabled on your Pi. Enabling this protocol is necessary to allow the Pi to communicate with the moisture sensor peripheral.

SSH into your Pi and run the following command:

sudo raspi-config

Once the raspi-config interface is open, navigate to Interface Options:

Raspi-config Tool interface with Interface Options selected.

Then, select SPI:

Raspi-config Tool interface with SPI selected.

Now, select Yes to enable SPI:

Raspi-config Tool interface with Yes selected for SPI enablement.

Finally, select Finish. Restart your Pi using sudo reboot to make these changes take effect.

Test your Soil Moisture readings on your Pi

Next, install the Adafruit ADC library Adafruit_CircuitPython_MCP3xxx on your Pi.

Before installation, make sure any packages on your Pi are up to date:

sudo apt update
sudo apt upgrade

Make sure you have pip installed for Python 3:

pip --version

If not, run the following command:

sudo apt install python3-pip

Run the following command while connected to your Pi with SSH to install Adafruit_CircuitPython_MCP3xxx:

sudo pip3 install adafruit-circuitpython-mcp3xxx

Create a new directory for your plant watering robot’s files and navigate to this directory in your terminal session. For example, run the following commands:

mkdir plant-watering-robot
cd plant-watering-robot

After navigating to this directory, create a new Python file called adctesting.py and open up the file. For example, run the following commands:

touch adctesting.py
nano adctesting.py

Now, add the following Python code to adctesting.py to test reading values from your capacitive soil moisture sensor through your MCP3008 ADC:

import time
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn

# Create the SPI bus
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)

# Create the cs (chip select)
cs = digitalio.DigitalInOut(board.D25)

# Create the MCP3008 object
mcp = MCP.MCP3008(spi, cs)

# Create an analog input channel on Pin 0
chan = AnalogIn(mcp, MCP.P0)

print('Reading MCP3008 values, press Ctrl-C to quit...')
while True:
    print('Raw ADC Value: ', chan.value)
    time.sleep(1)

Run the code as follows:

sudo python3 adctesting.py

Now, you should see the moisture sensor values outputted by the MCP3008.

Test your sensor by putting it in air, water, and different soils to see how the values change to determine your baseline for wet and dry values.

Terminal output of capacitive soil moisture sensor values.

Configure the Components of your Robot in the Viam app

Follow this guide to install viam-server on your pi, create a new robot, and connect to it on the Viam app.

Then, navigate to your new robot’s page on the app and click on the Config tab.

First, add your Pi as a board component by creating a new component with type board and model pi:

Creation of a pi board in the Viam app config builder.

{
  "components": [
    {
      "name": "local",
      "type": "board",
      "model": "pi",
      "attributes": {},
      "depends_on": []
    }, // Motor JSON ...
  ]
}

Then, add your pump as a motor component by adding a new component with type motor and model gpio.

Set the motor’s attributes Max RPM to 1000 and PWM to 12 GPIO 18 (the number and GPIO number of the pin that you wired the pump’s PWM to).

Creation of a pump motor in the Viam app config builder.

// Board JSON ... },
{
    "name": "water-pump",
    "type": "motor",
    "model": "gpio",
    "attributes": {
    "pins": {
        "a": "",
        "b": "",
        "dir": "",
        "pwm": "12"
    },
    "board": "local",
    "max_rpm": 1000
    },
    "depends_on": []
}

Click Save config.

Now, if you navigate to your robot’s Control tab, you should be able to control the motor by setting the power and direction of rotation and clicking the RUN button:

Creation of a pump motor in the Viam app config builder.

Configure the Capacitive Soil Moisture Sensor as a Custom Resource

Resources refer to the different components and services Viam provides for robots to use. Components refer to types of hardware, and each component’s built-in models support the most common models of this hardware. For example, the sensor component has an ultrasonic model built in for the ubiquitous ultrasonic sensor.

However, there are many different types of sensors used for sensing different things across the Internet of Things. Although the capacitive soil moisture sensor is not currently one of Viam’s built-in models, you can use the Viam Python SDK to configure this sensor as a custom resource implementing the Viam sensor class, making it a model of sensor available for you to use on your robot.

Create your custom sensor resource in 3 steps:

  1. Code a MoistureSensor class implementing the GetReadings() method that belongs to all members of the Viam sensor class, and instantiate this class on a RPC server in the main() function of your code.
  2. Add this “sensor server” as a remote part of your plant-watering-robot.
  3. Add a command that runs the program you coded instantiating the “sensor server” as a process of your robot.

Code the MoistureSensor Class

If you haven’t already, install the Viam Python SDK by following the instructions here.

Navigate to the directory you created when testing your soil moisture readings, plant-watering-robot, and create a new file, sensor.py.

For example, run the following commands to create and open the file:

cd plant-watering-robot
touch sensor.py
nano sensor.py

Paste the following code into sensor.py:

import asyncio

from viam.components.sensor import Sensor
from viam.rpc.server import Server

import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn
import RPi.GPIO as GPIO

from typing import Any, Dict, List, Mapping, Optional

class MoistureSensor(Sensor):

    def __init__(self, name: str):
        super(MoistureSensor,self).__init__(name)
        sensor_pin = 4
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(sensor_pin, GPIO.IN)


    # Implement the Viam Sensor API's get_readings() method
    async def get_readings(self, *, extra: Optional[Mapping[str, Any]] = None, timeout: Optional[float] = None, **kwargs):
        x = 0
        input = []

        # Create the SPI bus
        spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)

        # Create the cs (chip select)
        cs = digitalio.DigitalInOut(board.D25)

        # Create the MCP3008 object
        mcp = MCP.MCP3008(spi, cs)

        # Create an analog input channel on Pin 0
        chan = AnalogIn(mcp, MCP.P0)

        while x<10:
            # read adc channel 0
            reading = chan.value
            input.append(reading)
            x+=1

        return {'moisture': input}

async def main():
   srv = Server(components=[MoistureSensor("moisture_sensor")])
   await srv.serve()

if __name__ == "__main__":
   asyncio.run(main())

You can modify this example code as necessary.

Add the MoistureSensor Remote

Now, go back to your robot’s page on the Viam app and navigate to the Config tab, then to the Remotes subtab.

Add your sensor server as a remote part called my-sensor-server:

// "components": [ board & motor ... ],
"remotes": [
    {
      "name": "my-sensor-server",
      "insecure": true,
      "address": "localhost:9090"
    }
]

Creation of a custom sensor remote in the Viam app config builder."

Add the MoistureSensor Process

Then, navigate to the Processes subtab and create a process called run-sensor-server:

{
  // "components": [ board & motor ... ] ,
  // "remotes" [ my-sensor-server ... ] ,
  "processes": [
    {
      "id": "run-sensor-server",
      "log": true,
      "name": "sudo",
      "args": [
        "-u",
        "<my_username>",
        "python",
        "sensor.py"
      ],
      "cwd": "/home/<my_username>/plant-watering-robot"
    }
  ]
}

Creation of a process to run the sensor remote server in the Viam app config builder.

Modify the "args" and "cwd" to match the path to your plant-watering-robot directory on your Pi.

Click Save config. Now, when you navigate to your robot’s Control tab, you should be able to see your sensor readings:

Readings from a soil moisture sensor in the Viam app CONTROL tab.

Add Python Control Code

Follow these instructions to start working on your Python control code:

  1. Navigate to your robot’s page in the Viam app, and click on the Code Sample tab. Follow the instructions in this tab.
  2. Click Copy Code to copy a code sample that establishes a connection with your robot when run.
  3. Paste this code sample into a new file in the plant-watering-robot directory you created on your Pi.
  4. Name the file plant-watering-robot.py, and save it.

For example, run the following commands on your Pi to create and open the file:

cd plant-watering-robot
touch plant-watering-robot.py
nano plant-watering-robot.py

Now, you can add code into plant-watering-robot.py to write the logic that defines your plant watering system.

To start, add your system logic code into the main() function of the program. Use the Viam motor and sensor API methods.

You can get your components from the robot like this:

sensor = Sensor.from_robot(robot=robot, name='moisture_sensor') # Note that this name, `moisture_sensor`, is defined in sensor.py
water_pump = Motor.from_robot(robot=robot, name='water-pump')

And you can add your system logic to run continuously like this:

while True:

      # Get the moisture sensor's readings
      readings = await sensor.get_readings()
      soil_moisture = readings.get('moisture')

      # Calculate average moisture reading from the list of readings, to account for outliers
      avg_moisture = sum(soil_moisture) / len(soil_moisture)

      # If the average moisture reading is greater than 60000, trigger pump watering
      if(avg_moisture > 60000):
          print('this plant is too thirsty! giving it more water')

          # Run the water pump for 100 rev. at 1000 rpm
          await water_pump.go_for(rpm=1000, revolutions=1000)

          # Wait 60 seconds so that the water can soak into the soil a bit before trying to water again
          print('waiting a little bit for water to soak in')
          time.sleep(60)

See the motor component’s API documentation for more information about water_pump.go_for().

Save your plant-watering-robot.py program with this logic added in, and then run it on your Pi like this:

sudo python3 plant-watering-robot.py

To tinker this example code to work best for you, determine at what analog value from the Soil Moisture readings you want to water your plant, as your thirsty plant’s average moisture reading might differ from our example value of 60000. Also, consider how often you would like to check the moisture levels of the plant, and how long the plant should be watered.

Next Steps

Now that you have created your automatic plant watering system with a capacitive soil moisture sensor, you can easily use Viam to automate other aspects of your garden. For example, you can use a light sensor or a temperature sensor! If you build something based on this please share it in our Community Discord - we’d love to see it.



Have questions, or want to meet other people working on robots? Join our Community Discord.