Perception Module

Interfaces for the QUANTA X1 Pro SDK's head and wrist cameras, LiDAR, IMU, ToF, ultrasonic sensors, and chassis depth point cloud.

The perception module provides single-read and streaming-read interfaces for robot cameras and environmental sensors. When processing streaming data, actively manage resource cleanup, display frequency, and disk write speed.

Capability overview
  • Head camera system interface: Supports acquiring head RGB images, depth images, and H.265-encoded images from left and right eye cameras, providing two data acquisition methods: single-frame images and real-time image streams.

  • Left and right arm camera system interface: Supports acquiring RGB images from left and right arm cameras and H.265-encoded images from the corresponding arm cameras, providing two data acquisition methods: single-frame images and real-time image streams.

  • LiDAR interface: Supports obtaining laser scan data and real-time laser scan data streams, suitable for scenarios such as environmental perception, mapping, and localization.

  • IMU interface: Supports acquiring chassis inertial measurement data, real-time IMU data streams, and sensor operating status.

  • Distance sensor interface: Supports obtaining single-point infrared ranging and ultrasonic ranging data from the chassis, with two acquisition modes: single read and real-time data streams.

  • Chassis front depth camera interface: Supports acquiring point cloud data generated by the chassis front depth camera and real-time point cloud data streams.

Head camera system interface
get_rgb_image interface reference

Acquires a single-frame head RGB image and returns CompressedImage.

Note: This interface applies to configurations that provide a head RGB camera. If the device uses a stereo-camera configuration without a head RGB camera, the interface returns UNAVAILABLE. Use the left-eye or right-eye camera interface according to the actual configuration.

FieldDetails
Functionget_rgb_image()
Signaturedef get_rgb_image(timeout) -> sensor_msgs_.CompressedImage
DescriptionGet a single RGB image
ParameterNone
Return ValueCompressedImage
NotesNone

Example:

Save the following code as head_rgb_image.py:

from typing import Annotated

import cv2
import numpy as np
import typer
from x2robot import connect


def main(
    server: Annotated[
        str,
        typer.Option(
            help="SDK Server address, for example: 192.168.10.1:50051"
        ),
    ] = "localhost:50051",
):
    robot = connect(f"x2://{server}")
    image = robot.head_camera.get_rgb_image()

    if not image or not image.data:
        raise RuntimeError("Failed to obtain head RGB image data")

    image_array = np.frombuffer(
        bytes(image.data),
        dtype=np.uint8,
    )
    frame = cv2.imdecode(
        image_array,
        cv2.IMREAD_COLOR,
    )

    if frame is None:
        raise RuntimeError(
            f"Failed to decode head RGB image, "
            f"format={image.format!r}"
        )

    window_name = "Head RGB"
    try:
        cv2.imshow(window_name, frame)
        print("Press any key to close the image window.")
        cv2.waitKey(0)
    finally:
        cv2.destroyAllWindows()


if __name__ == "__main__":
    typer.run(main)

Run the program:

python3 head_rgb_image.py \
  --server 192.168.10.1:50051
get_depth_image interface reference
FieldDetails
Functionget_depth_image()
Signaturedef get_depth_image(timeout) -> sensor_msgs_.CompressedImage
DescriptionGet a single depth image
ParameterNone
Return ValueCompressedImage
NotesNone

Example:

image = robot.head_camera.get_depth_image()
get_rgb_video_stream interface reference
FieldDetails
Functionget_rgb_video_stream()
Signaturedef get_rgb_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage]
DescriptionGet an RGB image stream
ParameterNone
Return ValueIterator[CompressedImage]
NotesNone

Example:

images = robot.head_camera.get_rgb_video_stream()
for image in images:
    # Process response
    pass
get_depth_video_stream interface reference
FieldDetails
Functionget_depth_video_stream()
Signaturedef get_depth_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage]
DescriptionGet a depth-image stream
ParameterNone
Return ValueIterator[CompressedImage]
NotesNone

Example:

images = robot.head_camera.get_depth_video_stream()
for image in images:
    # Process response
    pass
get_left_eye_image / get_right_eye_image interface reference
FieldDetails
Functionget_left_eye_image()get_right_eye_image()
Signaturedef get_left_eye_image(timeout) -> sensor_msgs_.CompressedImagedef get_right_eye_image(timeout) -> sensor_msgs_.CompressedImage
DescriptionGet an H.265-encoded image from the left-eye or right-eye camera. This interface is supported only on robot types with a stereo-camera configuration.
ParameterNone
Return ValueCompressedImage
NotesNone

Example:

image = robot.head_camera.get_left_eye_image()
get_left_eye_video_stream / get_right_eye_video_stream interface reference
FieldDetails
Functionget_left_eye_video_stream()get_right_eye_video_stream()
Signaturedef get_left_eye_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage]def get_right_eye_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage]
DescriptionGet an H.265-encoded image stream from the left-eye or right-eye camera. This interface is supported only on robot types with a stereo-camera configuration.
ParameterNone
Return ValueIterator[CompressedImage]
NotesNone

Example:

images = robot.head_camera.get_left_eye_video_stream()
for image in images:
    # Process response
    pass
Left arm camera system
get_raw_image interface reference
FieldDetails
Functionget_raw_image()
SignatureNone
DescriptionMonocular-camera configuration: Get a single RGB image from the wrist camera. Stereo-camera configuration: Get an H.265-encoded image from the wrist camera.
ParameterNone
Return ValueCompressedImage
Notes

Example:

image = robot.left_arm_camera.get_raw_image()
get_video_stream interface reference

Acquires the real-time video stream of the left arm wrist camera and returns a CompressedImage iterator.

FieldDetails
Functionget_video_stream()
SignatureNone
DescriptionMonocular-camera configuration: Get an RGB image stream from the wrist camera. Stereo-camera configuration: Get an H.265-encoded image stream.
ParameterNone
Return ValueIterator[CompressedImage]
Notes

Example:

images = robot.left_arm_camera.get_video_stream()

for image in images:
    print(
        f"format={image.format}, "
        f"bytes={len(image.data)}"
    )

The video stream continuously returns data and can be stopped using Ctrl+C.

get_elbow_image interface reference
FieldDetails
Functionget_elbow_image()
Signaturedef get_elbow_image(timeout) -> sensor_msgs_.CompressedImage
DescriptionGet an H.265-encoded image from the wrist camera. This interface is supported only on robot types with a stereo-camera configuration.
ParameterNone
Return ValueCompressedImage
NotesNone

Example:

image = robot.left_arm_camera.get_elbow_image()
get_elbow_video_stream interface reference
FieldDetails
Functionget_elbow_video_stream()
Signaturedef get_elbow_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage]
DescriptionGet an H.265-encoded image from the wrist camera. This interface is supported only on robot types with a stereo-camera configuration.
ParameterNone
Return ValueCompressedImage
Notes

Example:

images = robot.left_arm_camera.get_elbow_video_stream()
for image in images:
    # Process response
    pass
Right arm camera system
get_raw_image interface reference
FieldDetails
Functionget_raw_image()
SignatureNone
DescriptionMonocular-camera configuration: Get a single RGB image from the wrist camera. Stereo-camera configuration: Get an H.265-encoded image from the wrist camera.
ParameterNone
Return ValueCompressedImage
Notes

Example:

image = robot.right_arm_camera.get_raw_image()
get_video_stream interface reference

Acquires the real-time video stream of the right arm wrist camera and returns a CompressedImage iterator.

FieldDetails
Functionget_video_stream()
SignatureNone
DescriptionMonocular-camera configuration: Get an RGB image stream from the wrist camera. Stereo-camera configuration: Get an H.265-encoded image stream from the wrist camera.
ParameterNone
Return ValueIterator[CompressedImage]
Notes

Example:

images = robot.right_arm_camera.get_video_stream()

for image in images:
    print(
        f"format={image.format}, "
        f"bytes={len(image.data)}"
    )

The video stream continuously returns data and can be stopped using Ctrl+C.

get_elbow_image interface reference
FieldDetails
Functionget_elbow_image()
Signaturedef get_elbow_image(timeout) -> sensor_msgs_.CompressedImage
DescriptionGet an H.265-encoded image from the wrist camera. This interface is supported only on robot types with a stereo-camera configuration.
ParameterNone
Return ValueCompressedImage
NotesNone

Example:

image = robot.right_arm_camera.get_elbow_image()
get_elbow_video_stream interface reference
FieldDetails
Functionget_elbow_video_stream()
Signaturedef get_elbow_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage]
DescriptionGet an H.265-encoded image stream from the wrist camera. This interface is supported only on robot types with a stereo-camera configuration.
ParameterNone
Return ValueCompressedImage
NotesNone

Example:

images = robot.right_arm_camera.get_elbow_video_stream()
for image in images:
    # Process response
    pass
LiDAR sensor
get_laser_scan interface reference
FieldDetails
Functionget_laser_scan()
Signaturedef get_laser_scan(timeout) -> sensor_msgs_.LaserScan
DescriptionGet LiDAR scan data
ParameterNone
Return ValueLaserScan
NotesNone

Example:

scan_data = robot.radar.get_laser_scan()

print(
    f"Angle Range: "
    f"[{scan_data.angle_min:.3f}, "
    f"{scan_data.angle_max:.3f}] rad"
)
print(
    f"Angle Increment: "
    f"{scan_data.angle_increment:.6f} rad"
)
print(
    f"Time Increment: "
    f"{scan_data.time_increment:.9f} s"
)
get_laser_scan_stream interface reference
FieldDetails
Functionget_laser_scan_stream()
Signaturedef get_laser_scan_stream(timeout) -> Iterator[sensor_msgs_.LaserScan]
DescriptionGet a LiDAR scan data stream
ParameterNone
Return ValueIterator[LaserScan]
NotesNone

Example:

for scan_data in robot.radar.get_laser_scan_stream():
    print(
        f"Angle Range: "
        f"[{scan_data.angle_min:.3f}, "
        f"{scan_data.angle_max:.3f}] rad"
    )
    print(
        f"Angle Increment: "
        f"{scan_data.angle_increment:.6f} rad"
    )
    print(
        f"Time Increment: "
        f"{scan_data.time_increment:.9f} s"
    )
IMU sensor
get_chassis_imu interface reference
FieldDetails
Functionget_chassis_imu()
Signaturedef get_chassis_imu(timeout) -> sensor_msgs_.Imu
DescriptionGet chassis IMU data
ParameterNone
Return ValueImu
Notes

Example:

imu_data = robot.imu.get_chassis_imu()

print(f"Orientation Quaternion: {imu_data.orientation}")
print(f"Angular Velocity: {imu_data.angular_velocity}")
print(f"Linear Acceleration: {imu_data.linear_acceleration}")
get_chassis_imu_stream interface reference
FieldDetails
Functionget_chassis_imu_stream()
Signaturedef get_chassis_imu_stream(timeout) -> Iterator[sensor_msgs_.Imu]
DescriptionGet a chassis IMU data stream
ParameterNone
Return ValueIterator[Imu]
Notes

Example:

for imu_data in robot.imu.get_chassis_imu_stream():
    print(f"Orientation Quaternion: {imu_data.orientation}")
    print(f"Angular Velocity: {imu_data.angular_velocity}")
    print(f"Linear Acceleration: {imu_data.linear_acceleration}")
ToF single-point infrared sensor
get_chassis_tof1 / get_chassis_tof2 interface reference
FieldDetails
Functionget_chassis_tof1()get_chassis_tof2()
Signaturedef get_chassis_tof_1(timeout=None) -> sensor_msgs_.Range
DescriptionGet single-point infrared sensor data
ParameterNone
Return ValueRange
Notes

Example:

range_data = robot.tof.get_chassis_tof_1()

print(f"Distance: {range_data.range:.3f} m")
print(f"Radiation Type: {range_data.radiation_type}")
print(
    f"Field of View: {range_data.field_of_view:.3f} rad "
    f"({math.degrees(range_data.field_of_view):.1f}°)"
)
print(f"Min Range: {range_data.min_range:.2f} m")
print(f"Max Range: {range_data.max_range:.2f} m")
get_chassis_tof1_stream / get_chassis_tof2_stream interface reference
FieldDetails
Functionget_chassis_tof1_stream()get_chassis_tof2_stream()
Signaturedef get_chassis_tof_1_stream(timeout=None) -> Iterator[sensor_msgs_.Range]
DescriptionGet a single-point infrared sensor data stream
ParameterNone
Return ValueIterator[Range]
Notes

Example:

for range_data in robot.tof.get_chassis_tof_1_stream():
    print(f"Distance: {range_data.range:.3f} m")
    print(f"Radiation Type: {range_data.radiation_type}")
    print(
        f"Field of View: {range_data.field_of_view:.3f} rad "
        f"({math.degrees(range_data.field_of_view):.1f}°)"
    )
    print(f"Min Range: {range_data.min_range:.2f} m")
    print(f"Max Range: {range_data.max_range:.2f} m")
Ultrasonic sensor

The ultrasonic sensor interface is provided by robot.ultrasonic; robot.tof only provides the ToF single-point infrared sensor interface.

get_chassis_ultrasonic_1 ~ get_chassis_ultrasonic_4 interface reference
FieldDetails
Functionget_chassis_ultrasonic_1(), get_chassis_ultrasonic_2(), get_chassis_ultrasonic_3(), get_chassis_ultrasonic_4()
Signaturedef get_chassis_ultrasonic_1(timeout=None) -> Range
DescriptionGet a single distance measurement from a chassis ultrasonic sensor.
ParameterNone
Return ValueRange
NotesThere are four ultrasonic sensors. Select the corresponding sensor with the number 1 through 4 at the end of the method name.

Example:

import math

range_data = (
    robot.ultrasonic
    .get_chassis_ultrasonic_1()
)

print(f"Distance: {range_data.range:.3f} m")
print(f"Radiation Type: {range_data.radiation_type}")
print(
    f"Field of View: {range_data.field_of_view:.3f} rad "
    f"({math.degrees(range_data.field_of_view):.1f}°)"
)
print(f"Min Range: {range_data.min_range:.2f} m")
print(f"Max Range: {range_data.max_range:.2f} m")

When reading other ultrasonic sensors, replace the number in the method name with 2, 3, or 4.

get_chassis_ultrasonic_1_stream ~ get_chassis_ultrasonic_4_stream interface reference
FieldDetails
Functionget_chassis_ultrasonic_1_stream(), get_chassis_ultrasonic_2_stream(), get_chassis_ultrasonic_3_stream(), get_chassis_ultrasonic_4_stream()
Signaturedef get_chassis_ultrasonic_1_stream(timeout=None) -> Iterator[Range]
DescriptionGet a real-time distance data stream from a chassis ultrasonic sensor.
ParameterNone
Return ValueIterator[Range]
NotesThe streaming interface returns data continuously. Press Ctrl+C to stop it.

Example:

import math

for range_data in (
    robot.ultrasonic
    .get_chassis_ultrasonic_1_stream()
):
    print(f"Distance: {range_data.range:.3f} m")
    print(f"Radiation Type: {range_data.radiation_type}")
    print(
        f"Field of View: {range_data.field_of_view:.3f} rad "
        f"({math.degrees(range_data.field_of_view):.1f}°)"
    )
    print(f"Min Range: {range_data.min_range:.2f} m")
    print(f"Max Range: {range_data.max_range:.2f} m")
Chassis front depth camera system

The chassis front depth camera point cloud interface is provided by robot.depth_points.

get_chassis_depth_points interface reference
FieldDetails
Functionget_chassis_depth_points()
Signaturedef get_chassis_depth_points(timeout=None) -> PointCloud2
DescriptionGet a single point-cloud frame from the front chassis depth camera.
Parametertimeout: Optional RPC timeout in seconds. None means that no explicit timeout is set for this call.
Return ValuePointCloud2
NotesIn SDK v1.1.2, header may be empty in the returned data. Do not assume that msg.header.frame_id is always available.

Example:

from x2robot import connect

robot = connect("x2://192.168.10.1:50051")

msg = robot.depth_points.get_chassis_depth_points(
    timeout=5
)

print(f"width={msg.width}, height={msg.height}")
print(
    f"point_step={msg.point_step}, "
    f"row_step={msg.row_step}"
)
print(
    "fields="
    f"{[field.name for field in msg.fields]}"
)
print(f"data_bytes={len(msg.data)}")
print(f"is_dense={msg.is_dense}")
print(f"is_bigendian={msg.is_bigendian}")

If frame_id needs to be displayed, first check whether header exists.

frame_id = (
    msg.header.frame_id
    if msg.header is not None
    else "<not provided>"
)
print(f"frame_id={frame_id}")
get_chassis_depth_points_stream interface reference
FieldDetails
Functionget_chassis_depth_points_stream()
Signaturedef get_chassis_depth_points_stream(timeout=None) -> Iterator[PointCloud2]
DescriptionGet a point-cloud data stream from the front chassis depth camera.
Parametertimeout: Optional timeout for the entire streaming RPC, in seconds. None means that no explicit timeout is set.
Return ValueIterator[PointCloud2]
NotesThe interface returns point-cloud data continuously. Press Ctrl+C to stop it. header may be empty in the returned data.

Example:

from x2robot import connect

robot = connect("x2://192.168.10.1:50051")

try:
    for msg in (
        robot.depth_points
        .get_chassis_depth_points_stream(
            timeout=None
        )
    ):
        print(
            f"width={msg.width}, "
            f"height={msg.height}, "
            f"data_bytes={len(msg.data)}"
        )
except KeyboardInterrupt:
    print("Depth point stream stopped.")

To parse the x, y, and z coordinates of each point in PointCloud2, please use the complete example in the SDK instead of only copying partial code from the parsing loop.

Run the complete point cloud example:

# Single read and parse
python3 examples/depth_points.py   --action single   --server 192.168.10.1:50051

# Stream read and parse
python3 examples/depth_points.py   --action stream   --server 192.168.10.1:50051

On this page