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.
| Field | Details |
|---|---|
| Function | get_rgb_image() |
| Signature | def get_rgb_image(timeout) -> sensor_msgs_.CompressedImage |
| Description | Get a single RGB image |
| Parameter | None |
| Return Value | CompressedImage |
| Notes | None |
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:50051get_depth_image interface reference
| Field | Details |
|---|---|
| Function | get_depth_image() |
| Signature | def get_depth_image(timeout) -> sensor_msgs_.CompressedImage |
| Description | Get a single depth image |
| Parameter | None |
| Return Value | CompressedImage |
| Notes | None |
Example:
image = robot.head_camera.get_depth_image()get_rgb_video_stream interface reference
| Field | Details |
|---|---|
| Function | get_rgb_video_stream() |
| Signature | def get_rgb_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage] |
| Description | Get an RGB image stream |
| Parameter | None |
| Return Value | Iterator[CompressedImage] |
| Notes | None |
Example:
images = robot.head_camera.get_rgb_video_stream()
for image in images:
# Process response
passget_depth_video_stream interface reference
| Field | Details |
|---|---|
| Function | get_depth_video_stream() |
| Signature | def get_depth_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage] |
| Description | Get a depth-image stream |
| Parameter | None |
| Return Value | Iterator[CompressedImage] |
| Notes | None |
Example:
images = robot.head_camera.get_depth_video_stream()
for image in images:
# Process response
passget_left_eye_image / get_right_eye_image interface reference
| Field | Details |
|---|---|
| Function | get_left_eye_image()get_right_eye_image() |
| Signature | def get_left_eye_image(timeout) -> sensor_msgs_.CompressedImagedef get_right_eye_image(timeout) -> sensor_msgs_.CompressedImage |
| Description | Get 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. |
| Parameter | None |
| Return Value | CompressedImage |
| Notes | None |
Example:
image = robot.head_camera.get_left_eye_image()get_left_eye_video_stream / get_right_eye_video_stream interface reference
| Field | Details |
|---|---|
| Function | get_left_eye_video_stream()get_right_eye_video_stream() |
| Signature | def get_left_eye_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage]def get_right_eye_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage] |
| Description | Get 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. |
| Parameter | None |
| Return Value | Iterator[CompressedImage] |
| Notes | None |
Example:
images = robot.head_camera.get_left_eye_video_stream()
for image in images:
# Process response
passLeft arm camera system
get_raw_image interface reference
| Field | Details |
|---|---|
| Function | get_raw_image() |
| Signature | None |
| Description | Monocular-camera configuration: Get a single RGB image from the wrist camera. Stereo-camera configuration: Get an H.265-encoded image from the wrist camera. |
| Parameter | None |
| Return Value | CompressedImage |
| 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.
| Field | Details |
|---|---|
| Function | get_video_stream() |
| Signature | None |
| Description | Monocular-camera configuration: Get an RGB image stream from the wrist camera. Stereo-camera configuration: Get an H.265-encoded image stream. |
| Parameter | None |
| Return Value | Iterator[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
| Field | Details |
|---|---|
| Function | get_elbow_image() |
| Signature | def get_elbow_image(timeout) -> sensor_msgs_.CompressedImage |
| Description | Get an H.265-encoded image from the wrist camera. This interface is supported only on robot types with a stereo-camera configuration. |
| Parameter | None |
| Return Value | CompressedImage |
| Notes | None |
Example:
image = robot.left_arm_camera.get_elbow_image()get_elbow_video_stream interface reference
| Field | Details |
|---|---|
| Function | get_elbow_video_stream() |
| Signature | def get_elbow_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage] |
| Description | Get an H.265-encoded image from the wrist camera. This interface is supported only on robot types with a stereo-camera configuration. |
| Parameter | None |
| Return Value | CompressedImage |
| Notes |
Example:
images = robot.left_arm_camera.get_elbow_video_stream()
for image in images:
# Process response
passRight arm camera system
get_raw_image interface reference
| Field | Details |
|---|---|
| Function | get_raw_image() |
| Signature | None |
| Description | Monocular-camera configuration: Get a single RGB image from the wrist camera. Stereo-camera configuration: Get an H.265-encoded image from the wrist camera. |
| Parameter | None |
| Return Value | CompressedImage |
| 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.
| Field | Details |
|---|---|
| Function | get_video_stream() |
| Signature | None |
| Description | Monocular-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. |
| Parameter | None |
| Return Value | Iterator[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
| Field | Details |
|---|---|
| Function | get_elbow_image() |
| Signature | def get_elbow_image(timeout) -> sensor_msgs_.CompressedImage |
| Description | Get an H.265-encoded image from the wrist camera. This interface is supported only on robot types with a stereo-camera configuration. |
| Parameter | None |
| Return Value | CompressedImage |
| Notes | None |
Example:
image = robot.right_arm_camera.get_elbow_image()get_elbow_video_stream interface reference
| Field | Details |
|---|---|
| Function | get_elbow_video_stream() |
| Signature | def get_elbow_video_stream(timeout) -> Iterator[sensor_msgs_.CompressedImage] |
| Description | Get an H.265-encoded image stream from the wrist camera. This interface is supported only on robot types with a stereo-camera configuration. |
| Parameter | None |
| Return Value | CompressedImage |
| Notes | None |
Example:
images = robot.right_arm_camera.get_elbow_video_stream()
for image in images:
# Process response
passLiDAR sensor
get_laser_scan interface reference
| Field | Details |
|---|---|
| Function | get_laser_scan() |
| Signature | def get_laser_scan(timeout) -> sensor_msgs_.LaserScan |
| Description | Get LiDAR scan data |
| Parameter | None |
| Return Value | LaserScan |
| Notes | None |
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
| Field | Details |
|---|---|
| Function | get_laser_scan_stream() |
| Signature | def get_laser_scan_stream(timeout) -> Iterator[sensor_msgs_.LaserScan] |
| Description | Get a LiDAR scan data stream |
| Parameter | None |
| Return Value | Iterator[LaserScan] |
| Notes | None |
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
| Field | Details |
|---|---|
| Function | get_chassis_imu() |
| Signature | def get_chassis_imu(timeout) -> sensor_msgs_.Imu |
| Description | Get chassis IMU data |
| Parameter | None |
| Return Value | Imu |
| 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
| Field | Details |
|---|---|
| Function | get_chassis_imu_stream() |
| Signature | def get_chassis_imu_stream(timeout) -> Iterator[sensor_msgs_.Imu] |
| Description | Get a chassis IMU data stream |
| Parameter | None |
| Return Value | Iterator[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
| Field | Details |
|---|---|
| Function | get_chassis_tof1()get_chassis_tof2() |
| Signature | def get_chassis_tof_1(timeout=None) -> sensor_msgs_.Range |
| Description | Get single-point infrared sensor data |
| Parameter | None |
| Return Value | Range |
| 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
| Field | Details |
|---|---|
| Function | get_chassis_tof1_stream()get_chassis_tof2_stream() |
| Signature | def get_chassis_tof_1_stream(timeout=None) -> Iterator[sensor_msgs_.Range] |
| Description | Get a single-point infrared sensor data stream |
| Parameter | None |
| Return Value | Iterator[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
| Field | Details |
|---|---|
| Function | get_chassis_ultrasonic_1(), get_chassis_ultrasonic_2(), get_chassis_ultrasonic_3(), get_chassis_ultrasonic_4() |
| Signature | def get_chassis_ultrasonic_1(timeout=None) -> Range |
| Description | Get a single distance measurement from a chassis ultrasonic sensor. |
| Parameter | None |
| Return Value | Range |
| Notes | There 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
| Field | Details |
|---|---|
| Function | get_chassis_ultrasonic_1_stream(), get_chassis_ultrasonic_2_stream(), get_chassis_ultrasonic_3_stream(), get_chassis_ultrasonic_4_stream() |
| Signature | def get_chassis_ultrasonic_1_stream(timeout=None) -> Iterator[Range] |
| Description | Get a real-time distance data stream from a chassis ultrasonic sensor. |
| Parameter | None |
| Return Value | Iterator[Range] |
| Notes | The 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
| Field | Details |
|---|---|
| Function | get_chassis_depth_points() |
| Signature | def get_chassis_depth_points(timeout=None) -> PointCloud2 |
| Description | Get a single point-cloud frame from the front chassis depth camera. |
| Parameter | timeout: Optional RPC timeout in seconds. None means that no explicit timeout is set for this call. |
| Return Value | PointCloud2 |
| Notes | In 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
| Field | Details |
|---|---|
| Function | get_chassis_depth_points_stream() |
| Signature | def get_chassis_depth_points_stream(timeout=None) -> Iterator[PointCloud2] |
| Description | Get a point-cloud data stream from the front chassis depth camera. |
| Parameter | timeout: Optional timeout for the entire streaming RPC, in seconds. None means that no explicit timeout is set. |
| Return Value | Iterator[PointCloud2] |
| Notes | The 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