Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Dhruv2012/Autonomous-Farm-Robot/llms.txt

Use this file to discover all available pages before exploring further.

Raw magnetometer readings contain significant noise that causes erratic robot behaviour. Even small heading errors compound over distance in an open field, making reliable row traversal impossible without pre-processing. AGRIBOT addresses this by applying a Moving Median filter to collect and smooth magnetometer samples — implemented in data_manipulation.py.

Moving Median Filter

The Moving Median filter accumulates raw heading samples in a list. Every 8 samples it computes the median value, publishes the result on Filteredheading, and resets the accumulator. Using the median rather than the mean makes the filter robust to short-duration spikes (e.g. from magnetic interference) because outliers do not pull the median the way they pull the mean.
def medianFilter(lis):
    ans = np.median(lis)
    return ans

def callback(msg, pub):
    global lisheading, i, heading
    magnetic_x = msg.vector.x
    magnetic_y = msg.vector.y
    RawHeading = atan2(magnetic_y, magnetic_x) * 180 / pi
    mag_data.publish(RawHeading)
    lisheading.append(RawHeading)
    if i == 7:
        heading = -1 * medianFilter(lisheading)
        lisheading = []
        pub.publish(heading)
        i = 0
    i = i + 1
Each raw heading sample is also published immediately on Rawheading via mag_data.publish(RawHeading), so the unfiltered signal is available for real-time visualization in plot.py alongside the filtered output. The sign inversion (-1 *) applied to the median result aligns the magnetometer’s sensor frame convention with the navigation frame used by the rest of the stack. Without this correction, the angular error fed to the PD controller would have the wrong sign, causing the robot to steer away from — rather than toward — the goal.
The window size of 8 samples for the Moving Median filter was tuned empirically during Gazebo simulation. Adjust it by changing the i == 7 condition in callback() if you need a faster response (smaller window) or smoother output (larger window). A window that is too large will introduce lag; one that is too small will pass through noise.

Angle Error Computation

Once a filtered heading is available, data_manipulation.py computes the corrected angle the robot must turn through to face the goal. This combines the GPS-derived bearing from gps_converter (received on angleOG) with the filtered magnetometer heading.
def angle_to_move(msg, angle_pub):
    currentPosex = msg.position.x
    currentPosey = msg.position.y
    Current_heading = heading
    angle_with_positive_X_axis = atan2(currentPosey, currentPosex) * (180 / pi)

    if angle_between_origin_to_goal < 0:
        angleToMove = (-1) * (abs(angle_between_origin_to_goal) + Current_heading) - 90
    else:
        angleToMove = abs(angle_between_origin_to_goal) - Current_heading - 90

    # Normalize to [-180, 180]
    if angleToMove > 180:
        angleToMove = angleToMove - 360
    elif angleToMove < -180:
        angleToMove = angleToMove + 360
    else:
        angleToMove = angleToMove

    angle_pub.publish(angleToMove)
The two branches of the if statement handle the sign of the GPS bearing separately so that the subtraction always produces an error in the correct rotational direction. The normalization step at the end ensures the result stays within [-180°, 180°], which prevents the PD controller from commanding a 350° rotation when a −10° correction would achieve the same result. The corrected angle is published on angle and consumed directly by the autonomousdrive node via its /angle subscriber.

Visualization with plot.py

The plot.py node subscribes to Rawheading and renders a live Matplotlib chart so developers can observe the raw heading in real time during a simulation run:
rospy.init_node('plot')
rospy.Subscriber('Rawheading', Float64, plot)
plt.ion()
plt.show()
rospy.spin()
Run it in a separate terminal alongside the main navigation stack to monitor filter performance without stopping the robot.

Build docs developers (and LLMs) love