Chapter 17: Applications and Case Studies
Lesson 5: Agriculture and Environmental Monitoring
This lesson studies how mobile robots and unmanned aerial vehicles (UAVs) are used for precision agriculture and environmental monitoring. We connect sensing models (e.g., vegetation indices), coverage patterns, and simple linear control laws to concrete software implementations in Python, C++, Java, and MATLAB/Simulink. Emphasis is on mathematically modeling sensing and coverage, not on detailed kinematics or advanced autonomy, which are reserved for later courses.
1. Role of Robotics in Agriculture and Environmental Monitoring
Agricultural and environmental robots operate over large, structured or semi-structured environments: crop fields, orchards, forests, lakes, and coastal zones. Compared to factory robots, they face:
- Large, partially known workspaces with natural variability.
- Strong coupling to weather, soil, and vegetation dynamics.
- Strict constraints on energy, safety, and coverage completeness.
Abstractly, we can model the spatial environment as a domain \( \Omega \subset \mathbb{R}^2 \) (for ground robots) or \( \Omega \subset \mathbb{R}^3 \) (for aerial robots). At a point \( p \in \Omega \) and time \( t \), we denote by \( s(p,t) \) a scalar or vector field describing the quantity of interest (e.g., soil moisture, vegetation health, pollution level).
A field robot with pose \( q(t) \) (position and orientation, introduced conceptually in earlier chapters) acquires measurements
\[ y_k = h\big(s(q(t_k), t_k)\big) + v_k,\quad k = 0,1,2,\dots \]
where \( h(\cdot) \) is the sensor response function and \( v_k \) is measurement noise, often modeled as zero-mean:
\[ v_k \sim \mathcal{N}(0, \sigma_v^2). \]
The design challenge is to choose robot trajectories \( q(t) \) and control inputs such that:
- Coverage is sufficiently dense over \( \Omega \).
- Measurements have acceptable signal-to-noise ratio.
- The robot remains stable and safe under linear control laws studied in your control courses.
flowchart TD
M["Mission specification: crop type, field map, targets"] --> S["Sensing plan: altitude, footprint, sampling period"]
S --> C["Coverage planner: rows / strips / grid passes"]
C --> L["Low-level controller: speed, steering, altitude"]
L --> D["Data collection: reflectance, moisture, temperature"]
D --> A["Analysis: vegetation indices, maps, reports"]
A --> F["Actions: fertilize, irrigate, re-plant, alert"]
2. Vegetation Indices and Sensor Models
Many agricultural robots rely on multispectral or hyperspectral cameras that measure reflected light at several wavelengths. A classical example is the Normalized Difference Vegetation Index (NDVI), defined from near-infrared (NIR) and red (R) reflectance values at a pixel:
\[ \operatorname{NDVI} = \frac{\mathrm{NIR} - R}{\mathrm{NIR} + R}. \]
Assuming \( \mathrm{NIR} \ge 0 \) and \( R \ge 0 \), and that \( \mathrm{NIR} + R > 0 \), we can show that NDVI is bounded between \(-1\) and \(1\). Indeed,
\[ -1 \le \operatorname{NDVI} \le 1. \]
Sketch of proof: Consider \( \operatorname{NDVI} = \frac{\mathrm{NIR} - R}{\mathrm{NIR} + R} \). Then \( \lvert \mathrm{NIR} - R \rvert \le \mathrm{NIR} + R \) because both \( \mathrm{NIR}, R \ge 0 \). Dividing by \( \mathrm{NIR} + R \gt 0 \) yields \( \left\lvert \operatorname{NDVI} \right\rvert \le 1 \).
From a robotic perspective, NDVI becomes a measurement function of robot pose:
\[ y_k = \operatorname{NDVI}\big(q(t_k)\big) + v_k. \]
A simple linearized sensor model around an operating point \( q^\ast \) is
\[ y_k \approx \operatorname{NDVI}(q^\ast) + \nabla \operatorname{NDVI}(q^\ast)^\top \big(q(t_k) - q^\ast\big) + v_k. \]
This linearization is compatible with linear control and estimation, since the measurement becomes an affine function of small deviations in pose. Similar normalized indices (e.g., moisture indices, pollution ratios) can be modeled analogously.
3. Coverage Path Planning on Rectangular Fields
Consider a rectangular crop field approximated as \( \Omega = [0, L_x] \times [0, L_y] \). A ground robot with effective sensing or actuation footprint width \( w_f \) drives at constant speed \( v \). A common coverage strategy is a back-and-forth (boustrophedon) pattern with row spacing \( s \le w_f \).
The number of passes required to cover the field is
\[ N_{\text{pass}} = \left\lceil \frac{L_y}{s} \right\rceil. \]
If each pass has length approximately \( L_x \), then the total path length is
\[ \ell_{\text{tot}} \approx N_{\text{pass}} \, L_x, \]
and the approximate coverage time is
\[ T_{\text{cov}} \approx \frac{\ell_{\text{tot}}}{v} = \frac{N_{\text{pass}} \, L_x}{v}. \]
The coverage ratio compares the field area effectively visited by the footprint to the total area:
\[ C = \frac{A_{\text{visited}}}{A_\Omega},\quad A_\Omega = L_x L_y,\quad A_{\text{visited}} \approx N_{\text{pass}} \, L_x \, w_f. \]
Thus, for the simple strip pattern,
\[ C \approx \frac{N_{\text{pass}} L_x w_f}{L_x L_y} = \frac{N_{\text{pass}} w_f}{L_y} \approx \frac{\left\lceil L_y / s \right\rceil w_f}{L_y}. \]
Choosing \( s < w_f \) yields overlap (oversampling) but improves robustness, while \( s \approx w_f \) minimizes time but is sensitive to tracking errors. These trade-offs are fundamental in agricultural coverage planning.
flowchart TD
ST["Field dimensions Lx, Ly, footprint wf"] --> SROW["Select row spacing s (s <= wf)"]
SROW --> NP["Compute N_pass = ceil(Ly / s)"]
NP --> LT["Estimate path length l_tot = N_pass * Lx"]
LT --> TC["Estimate coverage time T_cov = l_tot / v"]
TC --> EVAL["Check coverage ratio C and battery limits"]
EVAL -->|OK| DEP["Deploy robot with chosen pattern"]
EVAL -->|Not OK| ADJ["Adjust s or speed v and recompute"]
4. Simple Linear Row-Following Control
Many agricultural robots must follow a crop row or virtual guidance line with small lateral and heading errors. We consider a kinematic model at constant forward speed \( v \) with sampling period \( T \). Let
- \( e_y(k) \): lateral deviation from the desired row at sample \( k \),
- \( e_\psi(k) \): heading error (difference between robot heading and row direction).
For small errors, one linearized discrete-time model is
\[ \begin{aligned} e_y(k+1) &= e_y(k) + T v\, e_\psi(k), \\ e_\psi(k+1) &= e_\psi(k) + T u(k), \end{aligned} \]
where \( u(k) \) is a control input proportional to steering angle (or steering rate). In state-space form, with \( \mathbf{x}_k = \begin{bmatrix} e_y(k) \\ e_\psi(k) \end{bmatrix} \), we have
\[ \mathbf{x}_{k+1} = \mathbf{A}\mathbf{x}_k + \mathbf{B} u(k),\quad \mathbf{A} = \begin{bmatrix} 1 & T v \\ 0 & 1 \end{bmatrix},\quad \mathbf{B} = \begin{bmatrix} 0 \\ T \end{bmatrix}. \]
A linear state feedback controller
\[ u(k) = -\mathbf{K}\mathbf{x}_k = -\begin{bmatrix} k_1 & k_2 \end{bmatrix} \begin{bmatrix} e_y(k) \\ e_\psi(k) \end{bmatrix} \]
yields the closed-loop system
\[ \mathbf{x}_{k+1} = \left(\mathbf{A} - \mathbf{B}\mathbf{K}\right)\mathbf{x}_k = \begin{bmatrix} 1 & T v \\ -T k_1 & 1 - T k_2 \end{bmatrix} \mathbf{x}_k. \]
Stability requires that both eigenvalues \( \lambda_1, \lambda_2 \) of \( \mathbf{A} - \mathbf{B}\mathbf{K} \) satisfy
\[ \lvert \lambda_i \rvert < 1,\quad i = 1,2. \]
In practice, we can place the eigenvalues at desired locations in the unit disc using discrete-time pole placement (by solving a set of linear equations for \( k_1, k_2 \)) or use an LQR design with state and input penalties. These design methods are direct applications of linear control theory to agricultural row-following.
5. Python Example — NDVI Map and Simple Coverage Waypoints
The following Python snippet illustrates how a UAV-based robot could
compute an NDVI image from NIR and red channels, threshold it to detect
stressed vegetation, and generate simple back-and-forth waypoints for
coverage over a rectangular field. We use numpy for matrix
operations and assume pixel georeferencing is known.
import numpy as np
def compute_ndvi(nir: np.ndarray, red: np.ndarray, eps: float = 1e-6) -> np.ndarray:
"""
Compute NDVI = (nir - red) / (nir + red), with small epsilon to avoid division by zero.
Inputs:
nir, red: 2D arrays of the same shape containing reflectance values.
"""
denom = nir + red + eps
ndvi = (nir - red) / denom
# Clip to physical range [-1, 1]
ndvi = np.clip(ndvi, -1.0, 1.0)
return ndvi
def stressed_mask(ndvi: np.ndarray, threshold: float) -> np.ndarray:
"""
Return boolean mask where NDVI is below a stress threshold.
"""
return ndvi < threshold
def generate_strip_waypoints(Lx: float, Ly: float, s: float) -> list:
"""
Generate a list of waypoints for a simple back-and-forth pattern over [0,Lx] x [0,Ly].
The robot flies along x, stepping in y with spacing s.
"""
N_pass = int(np.ceil(Ly / s))
waypoints = []
y = 0.0
for k in range(N_pass):
if k % 2 == 0:
# Even index: go from (0, y) to (Lx, y)
waypoints.append((0.0, y))
waypoints.append((Lx, y))
else:
# Odd index: come back from (Lx, y) to (0, y)
waypoints.append((Lx, y))
waypoints.append((0.0, y))
y = min(Ly, y + s)
return waypoints
# Example usage (assuming we have loaded NIR and RED arrays):
nir = np.random.rand(512, 512)
red = np.random.rand(512, 512)
ndvi = compute_ndvi(nir, red)
mask = stressed_mask(ndvi, threshold=0.3)
Lx, Ly = 100.0, 50.0 # meters
s = 5.0 # footprint spacing
wps = generate_strip_waypoints(Lx, Ly, s)
print("Number of waypoints:", len(wps))
# In a full robot system, 'wps' would be sent to the guidance module,
# while 'mask' would be used to trigger localized actions (e.g., spraying).
This abstraction reflects a typical agricultural workflow: sensing and map computation are conceptually separated from motion control, but both are tightly coupled through geometry and coverage requirements.
6. C++ Example — Discrete Row-Following Controller
The next example shows a minimal C++ implementation of the discrete
row-following controller from Section 4. We use Eigen for
linear algebra, which is common in robotics software.
#include <iostream>
#include <Eigen/Dense>
using State = Eigen::Vector2d; // [e_y, e_psi]
struct RowFollower {
double T; // sampling period
double v; // forward speed
Eigen::RowVector2d K; // [k1, k2]
RowFollower(double T_, double v_, double k1, double k2)
: T(T_), v(v_), K(k1, k2) {}
// One-step update of state and control
double computeControl(const State& x) const {
// u = -K x
return -K * x;
}
State propagate(const State& x, double u) const {
// x_{k+1} = A x_k + B u_k
Eigen::Matrix2d A;
A << 1.0, T * v,
0.0, 1.0;
Eigen::Vector2d B;
B << 0.0, T;
return A * x + B * u;
}
};
int main() {
double T = 0.1; // 0.1 s sample time
double v = 1.0; // 1 m/s forward speed
double k1 = 0.5; // lateral gain
double k2 = 1.0; // heading gain
RowFollower controller(T, v, k1, k2);
State x;
x << 0.5, 0.2; // initial errors: 0.5 m lateral, 0.2 rad heading
for (int k = 0; k < 50; ++k) {
double u = controller.computeControl(x);
x = controller.propagate(x, u);
std::cout << "k=" << k
<< " e_y=" << x(0)
<< " e_psi=" << x(1)
<< " u=" << u << std::endl;
}
return 0;
}
In a full robot stack, the state \( e_y, e_\psi \) would be estimated from camera or LiDAR data and the control \( u \) would be converted to steering commands via the low-level drive interface.
7. Java Example — Object-Oriented Monitoring Node
Java is often used in high-level supervision or cloud-based monitoring services. The following example sketches an object-oriented design for a simple monitoring component that receives NDVI measurements and issues alerts when stressed regions persist.
public class NDVIMonitor {
private double threshold;
private int consecutiveLimit;
private int consecutiveStressed;
public NDVIMonitor(double threshold, int consecutiveLimit) {
this.threshold = threshold;
this.consecutiveLimit = consecutiveLimit;
this.consecutiveStressed = 0;
}
public void handleMeasurement(double ndvi, double x, double y) {
// Update internal counter based on NDVI threshold
if (ndvi < threshold) {
consecutiveStressed++;
} else {
consecutiveStressed = 0;
}
if (consecutiveStressed >= consecutiveLimit) {
triggerAlert(x, y, ndvi);
// Reset after alert
consecutiveStressed = 0;
}
}
private void triggerAlert(double x, double y, double ndvi) {
System.out.println("Stress alert at (" + x + ", " + y + "), NDVI=" + ndvi);
// In a real system, send message to actuator or farm management software
}
public static void main(String[] args) {
NDVIMonitor monitor = new NDVIMonitor(0.3, 5);
// Example test data (e.g., along a robot path)
double[] ndviSamples = {0.4, 0.35, 0.28, 0.25, 0.27, 0.26, 0.45};
double x = 0.0, y = 0.0;
double dx = 1.0;
for (double ndvi : ndviSamples) {
monitor.handleMeasurement(ndvi, x, y);
x += dx;
}
}
}
This illustrates how agricultural monitoring logic can be encapsulated in reusable components, which can then be integrated with robotics middleware (e.g., via message-passing APIs) introduced in earlier chapters.
8. MATLAB/Simulink Example — Simulating Lateral Error Dynamics
MATLAB and Simulink are well suited for simulating the linear row-following system and testing feedback gains before deploying to real robots. The script below constructs the discrete-time model and uses state feedback with pole placement to stabilize the system.
% Parameters
T = 0.1; % sampling period [s]
v = 1.0; % forward speed [m/s]
% State-space matrices for [e_y; e_psi]
A = [1, T*v;
0, 1];
B = [0;
T];
% Desired closed-loop poles (inside unit disc)
p1 = 0.8;
p2 = 0.6;
p_des = [p1, p2];
% Place poles to compute state feedback K
K = place(A, B, p_des); % K is 1x2
% Closed-loop system
A_cl = A - B*K;
% Simulation of initial condition
x0 = [0.5; 0.2]; % initial lateral and heading errors
N = 50;
x_hist = zeros(2, N+1);
x_hist(:,1) = x0;
for k = 1:N
u = -K * x_hist(:,k);
x_hist(:,k+1) = A * x_hist(:,k) + B * u;
end
t = 0:T:N*T;
figure;
subplot(2,1,1);
plot(t, x_hist(1,:)); grid on;
xlabel('Time [s]');
ylabel('e_y [m]');
title('Lateral error');
subplot(2,1,2);
plot(t, x_hist(2,:)); grid on;
xlabel('Time [s]');
ylabel('e_psi [rad]');
title('Heading error');
In Simulink, the same dynamics can be implemented using a discrete-time state-space block with matrices \( \mathbf{A}, \mathbf{B} \) and a state feedback gain \( \mathbf{K} \), allowing rapid experimentation with different sampling times, speeds, and gain selections.
9. Problems and Solutions
Problem 1 (NDVI bounds): Let \( \mathrm{NIR} \ge 0 \) and \( R \ge 0 \), with \( \mathrm{NIR} + R > 0 \). Show that \( \operatorname{NDVI} = \frac{\mathrm{NIR} - R}{\mathrm{NIR} + R} \) satisfies \( -1 \le \operatorname{NDVI} \le 1 \).
Solution:
Since \( \mathrm{NIR}, R \ge 0 \), we have \( \lvert \mathrm{NIR} - R \rvert \le \mathrm{NIR} + R \). Dividing both sides by \( \mathrm{NIR} + R \gt 0 \) yields \( \left\lvert \frac{\mathrm{NIR} - R}{\mathrm{NIR} + R} \right\rvert \le 1 \). Therefore \( -1 \le \operatorname{NDVI} \le 1 \).
Problem 2 (Coverage time and footprint choice): A field has dimensions \( L_x = 200 \) m and \( L_y = 80 \) m. A ground robot drives at \( v = 1 \) m/s with footprint width \( w_f = 4 \) m. You choose row spacing \( s = 3 \) m. (a) Compute \( N_{\text{pass}} \), approximate path length \( \ell_{\text{tot}} \), and coverage time \( T_{\text{cov}} \). (b) Approximate the coverage ratio \( C \).
Solution:
(a) The number of passes is
\[ N_{\text{pass}} = \left\lceil \frac{L_y}{s} \right\rceil = \left\lceil \frac{80}{3} \right\rceil = \left\lceil 26.\overline{6} \right\rceil = 27. \]
Path length
\[ \ell_{\text{tot}} \approx N_{\text{pass}} L_x = 27 \cdot 200 = 5400\ \text{m}. \]
Coverage time
\[ T_{\text{cov}} \approx \frac{\ell_{\text{tot}}}{v} = \frac{5400}{1} = 5400\ \text{s} \approx 90\ \text{min}. \]
(b) Approximate visited area
\[ A_{\text{visited}} \approx N_{\text{pass}} L_x w_f = 27 \cdot 200 \cdot 4 = 21600\ \text{m}^2. \]
Total area \( A_\Omega = L_x L_y = 200 \cdot 80 = 16000\ \text{m}^2 \). Thus
\[ C \approx \frac{A_{\text{visited}}}{A_\Omega} = \frac{21600}{16000} = 1.35. \]
A coverage ratio > 1 indicates overlap; here, about 35% overspray/oversampling relative to ideal no-overlap.
Problem 3 (Stability of row-following controller): For the discrete model in Section 4 with \( T = 0.1 \), \( v = 1 \), choose gains \( k_1 = 0.5 \), \( k_2 = 1.0 \). Construct \( \mathbf{A} - \mathbf{B}\mathbf{K} \) and show that its eigenvalues are inside the unit disc (numerically).
Solution:
We have
\[ \mathbf{A} = \begin{bmatrix} 1 & 0.1 \\ 0 & 1 \end{bmatrix},\quad \mathbf{B} = \begin{bmatrix} 0 \\ 0.1 \end{bmatrix},\quad \mathbf{K} = \begin{bmatrix} 0.5 & 1.0 \end{bmatrix}. \]
Then
\[ \mathbf{B}\mathbf{K} = \begin{bmatrix} 0 \\ 0.1 \end{bmatrix} \begin{bmatrix} 0.5 & 1.0 \end{bmatrix} = \begin{bmatrix} 0 & 0 \\ 0.05 & 0.1 \end{bmatrix}, \quad \mathbf{A} - \mathbf{B}\mathbf{K} = \begin{bmatrix} 1 & 0.1 \\ -0.05 & 0.9 \end{bmatrix}. \]
The characteristic polynomial is \( \lambda^2 - 1.9\lambda + 0.905 = 0 \). Solving yields numerical eigenvalues \( \lambda_1 \approx 0.95 \), \( \lambda_2 \approx 0.95 \). Both satisfy \( \lvert \lambda_i \rvert < 1 \), so the closed-loop discrete-time system is stable.
Problem 4 (Sampling density along a path): A UAV acquires multispectral measurements at frequency \( f_s \) samples/s while flying at speed \( v \). Derive an expression for the distance between consecutive samples along the path, and find \( f_s \) such that the distance is at most \( d_{\max} \).
Solution:
The time between samples is \( \Delta t = 1 / f_s \), so the spatial distance is
\[ d = v \Delta t = \frac{v}{f_s}. \]
We require \( d \le d_{\max} \), hence
\[ \frac{v}{f_s} \le d_{\max} \quad \Rightarrow \quad f_s \ge \frac{v}{d_{\max}}. \]
Thus any sampling frequency \( f_s \) chosen above \( v / d_{\max} \) ensures that spatial sampling along the path does not exceed the desired spacing.
10. Summary
In this lesson we modeled key aspects of agricultural and environmental robotics using tools you already know from linear control and basic sensing. We derived simple measurement models based on vegetation indices, showed how coverage patterns over rectangular fields can be parameterized and analyzed, and built linear state-space models for row-following with state feedback. Python, C++, Java, and MATLAB/Simulink examples demonstrated how these mathematical abstractions translate into implementable software components. These ideas generalize to other field robotics domains, where coverage, sensing quality, and stability must be balanced under resource constraints.
11. References
- Choset, H. (2001). Coverage for robotics – A survey of recent results. Annals of Mathematics and Artificial Intelligence, 31(1-4), 113–126.
- Zelinsky, A., Jarvis, R., Byrne, J., & Yuta, S. (1993). Planning paths of complete coverage of an unstructured environment by a mobile robot. Proceedings of International Conference on Advanced Robotics, 533–538.
- Galceran, E., & Carreras, M. (2013). A survey on coverage path planning for robotics. Robotics and Autonomous Systems, 61(12), 1258–1276.
- Mulla, D. J. (2013). Twenty five years of remote sensing in precision agriculture: Key advances and remaining knowledge gaps. Biosystems Engineering, 114(4), 358–371.
- Corke, P. (2011). Robotics, Vision and Control. Springer.
- Furrer, F., Burri, M., Achtelik, M., & Siegwart, R. (2016). RotorS—A modular gazebo MAV simulator framework. In Robot Operating System (ROS): The Complete Reference (Volume 1), 595–625.
- Ogren, P., Fiorelli, E., & Leonard, N. E. (2004). Cooperative control of mobile sensor networks: Adaptive gradient climbing in a distributed environment. IEEE Transactions on Automatic Control, 49(8), 1292–1302.
- Rimon, E., & Koditschek, D. E. (1992). Exact robot navigation using artificial potential functions. IEEE Transactions on Robotics and Automation, 8(5), 501–518.