Copter Object Avoidance

ArduPilot Copter supports object avoidance using a Lightware SF40C or with any sensor capable of providing distances using the MAVLink DISTANCE_SENSOR message. This page describe how the object avoidance feature works and how “proximity sensors” should provide data into ArduPilot.

Avoidance in Loiter

The video above shows a test of an EnRoute EX700 copter fitted with a Lightware SF40C 360degree lidar. The vehicle stops 2m from the fence regardless of the speed of the vehicle towards the fence. This is possible because ArduPilot knows the speed of the vehicle (using the GPS and accelerometers), the distance to the barrier and the maximum acceleration/deceleration of the vehicle.

The AP_Proximity library collects the raw distance measurements from the sensor. These raw distance measurements are consolidated so that only the closest distance and angle within 8 sectors is stored and used.

Each sector is 45 degrees wide with sector 0 pointing forward of the vehicle, sector 1 is forward-right, etc. From these distances and angles a fence (an array of 2D Vectors) is built up around the vehicle. The fence points fall on the lines between sectors at a conservative distance.


The default is to divide the area around the vehicle into 8 sectors but each proximity sensor driver can override this and use a different number of sectors.


The AC_Avoidance library consumes the above fence and uses it to adjust (mostly shortens) desired velocity vectors sent to it by the Loiter controller (search for “avoid->adjust_velocity”). Loiter’s desired velocity vectors come from the pilot’s inputs.


Object avoidance also works for Guided mode’s velocity controller

Avoidance in AltHold

The AP_Proximity and AC_Avoidance libraries are also used for object avoidance in AltHold. Because AltHold does not rely upon the GPS, the vehicle’s velocity towards the barriers is not known and a much simpler version of object avoidance is used in which the distance to the barrier is converted into a lean angle.

The image below shows the method by which the distances to various objects are combined together to result in a final roll/pitch lean angle. Each sensed object’s distance and angle from the vehicle is turned into a roll/pitch angle. The largest positive and negative roll and pitch angles are found and combined together resulting in a final roll/pitch angle.


This final roll/pitch angle is combined with the pilot’s input meaning the vehicle tends to fly away from objects but the pilot always maintains the ability to override the object avoidance. This is quite different from Loiter mode in which the pilot cannot force the vehicle to fly into an object.


The vehicle will also stop before hitting barriers above it there is an upward facing range finder. Currently this range finder’s distance must be sent to ardupilot using the DISTANCE_SENSOR message with the orientation field set to 24 (upwards).

Reporting to the Ground Station

The Mission Planner (and hopefully other ground stations in the future) support displaying the distance to nearby objects.


This is accomplished by the vehicle sending DISTANCE_SENSOR messages to the ground station at regular intervals. The method that does this can be seen in the vehicle code’s GCS_Mavlink.cpp file (search for “send_proximity”). Note that this means that it is possible that DISTANCE_SENSOR messages can be used both to send distances into the vehicle code, and then similar DISTANCE_SENSOR messages might be sent out from the vehicle to the ground station. These are separate messages though and are likely transferred at a different rate.

Providing Distance Sensor messages to ArduPilot

For developers of new “proximity” sensors (i.e. sensors that can somehow provide the distance to nearby objects) the easiest method to get your distance measurements into ardupilot is to send DISTANCE_SENSOR message for each direction the sensor is capable of. The system id of the message should match the system id of the vehicle (default is “1” but can be changed using the SYSID_THISMAV parameter). The component id can be anything but MAV_COMP_ID_PATHPLANNER (195) or MAV_COMP_ID_PERIPHERAL (158) are probably good choices.

These messages should be sent at between 10hz and 50hz (the faster the better). The fields should be filled in as shown below:

  • time_boost_ms : 0 (ignored)
  • min_distance : the minimum distance that the sensor can measure in centimeters (i.e. 100 = 1m). This number should generally not change and should be the same regardless of the orientation field.
  • max_distance : the maximum distance that the sensor can measure in centimeters (i.e. 1500 = 15m). This number should generally not change and should be the same regardless of the orientation field.
  • current_distance : the shortest distance in cm to the object
  • type : 0 (ignored)
  • id : 0 (ignored)
  • orientation : 0 to 7 (0=forward, each increment is 45degrees more in clockwise direction), 24 (upwards) or 25 (downwards). search for MAV_SENSOR_ORIENTATION on the mavlink/common page.
  • covariance : 0 (ignored)

When DISTANCE_SENSOR messages are not received for all 8 sectors, empty sectors are filled in with the distance from an adjacent sector (if available). This conveniently leads to a “cup” shaped fence which is more likely to protect the vehicle from hitting the object. It is likely this will be changed in future releases especially if the “stop” behaviour (instead of “slide” behaviour) is configured.


These two videos shows a ZED 3D camera connected to an NVidia TX1 running OpenKai and providing forward facing distance measurements to ArduPilot using the method described above.

Future Steps

  • add support for cheaper proximity sensors (issue here)
  • provide an option for simply stopping instead of sliding past obstacles in Loiter mode (issue here)
  • add avoidance to other modes including RTL, AUTO (issue here)
  • improve integration with ROS (issue here)
  • implement a simple occupancy grid for cases where we cannot (or do not want to) implement ROS on the vehicle (issue here)
  • add RNGFND_ORIENT parameter to allow an upward facing range finder to be connected in the same way a downward facing range finder is connected (issue here)

If you would like to get involved with the development of this area, please consider posting in the issues listed above or chatting with the developers on Gitter/ArduPilot.