Aerostack2

DocsPlugins

Perception

The ArUco detector plugin of the object perception behavior, and how to set up its pipeline.

Authored by
  • @alvgaona

The object perception behavior runs a pipeline of detector plugins on the drone's camera and reports what they find. ArUco is the only plugin today.

PluginDetects
arucoArUco markers, with their pose

The behavior serves the ObjectPerceptionBehavior action, of type as2_msgs/action/DetectObjects. Detection starts when a goal arrives and keeps going until the behavior is stopped:

ros2 action send_goal /drone0/ObjectPerceptionBehavior as2_msgs/action/DetectObjects \
  "{threshold: 0.0, target_classes: []}"

Each stage publishes its detections on its output topic, and the action's feedback carries the last stage's detections. There's no Python API module for perception yet.

Running it

ros2 launch as2_behaviors_object_perception detect_behavior_launch.py \
  namespace:=drone0 \
  config_file:=config/perception.yaml

detect_behavior_auto_launch.py does the same and sends the goal by itself 5 seconds after start, with the threshold and target_classes launch arguments.

The package's own configuration is always loaded, and your file is merged over it. It sets up one stage, called detector, that runs the ArUco plugin on the camera:

config/perception.yaml
/**:
  ros__parameters:
    camera_image_topic: "sensor_measurements/camera/image_raw"
    camera_info_topic: "sensor_measurements/camera/camera_info"
    pipeline:
      stages: ["detector"]
      detector:
        plugin: "aruco"
        input_source: "image"
        publish_output: true
        output_topic: "detections_data"

The default topics match a Gazebo camera named camera in the world file. A camera topic that ends in /compressed is read as a compressed image. Every topic is resolved in the drone's namespace, even one that starts with a slash.

Behavior parameters

ParameterDefaultWhat it does
camera_image_topicsensor_measurements/camera/image_rawThe camera's image topic
camera_info_topicsensor_measurements/camera/camera_infoThe camera's calibration. Without it, poses can't be computed
use_embedded_camerafalseOpen a USB camera inside the node, set up by the camera_interface_file and calibration_file launch arguments
enable_rectificationfalseUndistort images before detecting. Fisheye cameras are supported
rectified_camera_info_topicemptyWhere to publish the calibration of the undistorted image, when rectifying
persistenttrueKeep the pipeline running after each image
run_frequency30.0How often the pipeline runs, in Hz
pipeline.stages["detector"]The names of the stages, in order

Each stage takes its own settings, under its name:

ParameterDefault for detectorWhat it does
pipeline.<stage>.pluginarucoThe plugin the stage runs
pipeline.<stage>.input_sourceimageimage for the camera, internal for another stage, or external for a topic
pipeline.<stage>.input_stageThe stage an internal stage reads. Empty means the previous one
pipeline.<stage>.input_topicThe topic an external stage reads
pipeline.<stage>.publish_outputtruePublish the stage's detections
pipeline.<stage>.output_topicdetections_dataWhere they're published, as as2_msgs/msg/ObjectPerceptionArray
pipeline.<stage>.enable_debugtruePublish the detected poses and markers for RViz
pipeline.<stage>.debug_poses_topicdebug/detection_posesWhere the poses are published, as a pose array

These defaults only apply to a stage called detector. A stage with another name starts with internal input, no output and no debug, so set every field for it.

ArUco

aruco finds ArUco markers with OpenCV and reports one detection per marker. Its class is the marker's ID, and it comes with a bounding box and its four corners as keypoints. With estimate_pose on and the camera's calibration available, it also gives the marker's pose in the camera's frame. It doesn't publish transforms.

ParameterDefaultWhat it does
aruco.tag_dict6x6_250The marker dictionary, from 4x4_50 to 7x7_1000
aruco.marker_size0.15The side of a marker, in meters. Poses scale with it
aruco.estimate_posetrueCompute each marker's pose
aruco.corner_refinementnoneRefine the corners with subpix, contour or apriltag
aruco.adaptive_thresh_win_size_min7The smallest window of the adaptive threshold, in pixels
aruco.adaptive_thresh_win_size_max7The largest window
aruco.adaptive_thresh_win_size_step10The step between windows

The settings are shared by every stage that runs the plugin. With a fisheye camera, turn on enable_rectification, or the poses come out wrong.

The goal's target_classes limits the detections to some marker IDs, given as strings such as "3". An empty list reports every marker. The goal's threshold must be between 0 and 1. Every marker is reported with full confidence, so it doesn't filter anything yet.

With enable_debug on, the plugin also publishes debug/detection_markers for RViz, a cube and the ID of each marker with a pose.

Last updated on November 3, 2026

On this page

Last updated on November 3, 2026