Skip to main content
🤝

이 가이드는 인류와 AI가 함께 만드는 지식입니다.

이 콘텐츠는 Human + AI Partnership 철학 아래 모든 사람이 로봇·AI를 배울 수 있도록 무료로 제공됩니다. 당신의 질문과 기여가 다음 학생의 미래를 바꿉니다.

ROS 2 Agricultural Robotics Guide 2026

Agriculture is one of the fastest-growing robotics markets. This guide covers the ROS 2 stack for field robots: centimeter-accurate RTK-GPS navigation, vision-based crop-row following, precision spraying, and autonomous harvesting.

1. The Ag-Robot Stack

Field robots combine GNSS, vision, and implement control:

sudo apt-get install -y   ros-humble-nav2-bringup   ros-humble-robot-localization   ros-humble-nmea-navsat-driver   ros-humble-mavros            # for ArduPilot rovers

# Layers (bottom -> top):
#   1. RTK-GPS + IMU fusion  (robot_localization EKF)
#   2. Crop-row perception    (vision line detection)
#   3. Coverage path planner   (boustrophedon / headland turns)
#   4. Implement control       (sprayer / seeder / cutter)

2. RTK-GPS: Centimeter Accuracy

Standard GPS drifts meters; RTK corrects to ~2cm — essential for crop rows:

# ublox ZED-F9P RTK rover with NTRIP corrections
ros2 launch ublox_gps ublox_gps_node.launch.py   device:=/dev/ttyACM0   frame_id:=gps_link

# Feed NTRIP base-station corrections for RTK fix
ros2 run ntrip_client ntrip_ros   --ros-args   -p host:=rtk.example.com -p port:=2101   -p mountpoint:=NEAR -p username:=user

# Verify a FIXED solution (not FLOAT):
ros2 topic echo /ublox_gps_node/fix --field status.status
#   2 = GBAS/RTK fixed   <- required for row-level precision

3. GPS + IMU Fusion

Fuse RTK-GPS with wheel odometry and IMU using robot_localization:

# ekf_ag.yaml — navsat_transform + EKF
navsat_transform_node:
  ros__parameters:
    frequency: 30.0
    magnetic_declination_radians: 0.0
    yaw_offset: 0.0
    zero_altitude: true
    broadcast_utm_transform: true
    publish_filtered_gps: true

ekf_filter_node:
  ros__parameters:
    frequency: 30.0
    two_d_mode: true
    odom0: /wheel/odometry
    odom0_config: [false,false,false, false,false,false,
                   true,true,false, false,false,true, false,false,false]
    imu0: /imu/data
    imu0_config: [false,false,false, true,true,true,
                  false,false,false, true,true,true, true,true,true]

4. Vision-Based Crop-Row Following

Between GPS waypoints, follow the actual crop rows with vision — plants never grow exactly on the GPS line:

import cv2, numpy as np

def detect_crop_row(frame):
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    # Excess-green segmentation for vegetation
    green = cv2.inRange(hsv, (35, 40, 40), (85, 255, 255))

    # Column-wise vegetation histogram -> row centers
    hist = np.sum(green[green.shape[0]//2:], axis=0)
    row_center = int(np.argmax(np.convolve(hist, np.ones(40)/40, 'same')))

    error = (row_center - frame.shape[1] / 2) / (frame.shape[1] / 2)
    return error   # -1..1 steering error to stay centered on the row

5. Coverage Path Planning

Fields need full coverage, not point-to-point. Generate a boustrophedon (back-and-forth) pattern:

def boustrophedon(field_polygon, swath_width, heading):
    """Back-and-forth coverage aligned to the field heading."""
    lanes = slice_polygon_into_lanes(field_polygon, swath_width, heading)
    path, flip = [], False
    for lane in lanes:
        pts = lane if not flip else lane[::-1]
        path.extend(pts)
        flip = not flip            # alternate direction each lane
    return add_headland_turns(path)  # smooth U-turns at field ends

# Feed the coverage path to Nav2 as an ordered waypoint follower.

6. Precision Spraying

Actuate nozzles only over detected weeds/plants — cuts chemical use dramatically:

class PrecisionSprayer(Node):
    def __init__(self):
        super().__init__('precision_sprayer')
        self.create_subscription(Detection2DArray, '/weed_detections',
                                 self.spray, 10)
        self.nozzle_pub = self.create_publisher(UInt8, '/nozzle_bank', 10)

    def spray(self, msg):
        # Map each detection's x-position to one of N boom nozzles
        active = 0
        for det in msg.detections:
            nozzle = int(det.bbox.center.position.x / self.px_per_nozzle)
            active |= (1 << nozzle)        # bitmask of nozzles to fire
        self.nozzle_pub.publish(UInt8(data=active))
        # Only spray where weeds are -> 60-90% less herbicide

7. Autonomous Harvesting

Harvesting couples fruit detection, ripeness classification, and arm picking:

# Harvest decision pipeline
for fruit in detect_fruits(rgbd_frame):
    if classify_ripeness(fruit) < RIPE_THRESHOLD:
        continue                          # leave unripe fruit
    point3d = pixel_to_3d(fruit.u, fruit.v, depth, camera_info)
    if point3d is None:
        continue
    grasp = plan_grasp(point3d, approach='side')
    if moveit.plan_and_execute(grasp):
        actuate_cutter()                  # snip stem
        place_in_bin()

8. Safety in the Field

9. Connectivity & Fleet

10. Real Platforms

Key Takeaways

Precision agriculture runs on RTK-GPS for centimeter accuracy, fused with IMU/odometry in an EKF, corrected by vision-based crop-row following. Cover fields with boustrophedon planning, spray only where weeds are detected to slash chemical use, and couple fruit detection with arm control for harvesting. Design for field safety, poor connectivity, and multi-season data — that is what turns an ag-robot into real farm ROI.