Multi Media Service
Hardware Equipment:
The PTZ Camera of Daystar Robot Dog can provide both visible light and infrared video streams, as shown below:

Software Interface:
The PTZ Camera video streams can be accessed through standard RTSP API network interfaces.
- RGB Camera Stream URL:
rtsp://admin:yoseen2018@192.168.144.202:554/h264/ch1/sub/av_stream - Infrared Camera Stream URL:
rtsp://admin:yoseen2018@192.168.144.202:554/h264/ch2/sub/av_stream
Important Notes:
- The development device needs to connect to the robot dog's network (WiFi Name:
IS_** WiFiPassword:DaystarBot) to access video streams. - The Camera Stream URLs should be adjusted according to IP of the robot dog:
- After connecting to the robot dog's network, check whether the robot dog's IP is
192.168.100.*or192.168.144.*- If the segment is
100, use192.168.100.202in the stream URL - If the segment is
144, use192.168.144.202in the stream URL
- If the segment is
- After connecting to the robot dog's network, check whether the robot dog's IP is
Video Stream Verification and Testing:
You can use VLC media player to connect and display the video streams.

RGB Camera:

Infrared Camera:

| Function | C++ | ROS | Python | C# |
|---|---|---|---|---|
| Get gimbal attitude information | ✔ | ✔ | ✔ | ✔ |
| Control gimbal to target angle | ✔ | ✔ | ✔ | ✔ |
| Control continuous gimbal motion | ✔ | ✔ | ✔ | ✔ |
| Assist focus | ✔ | ✔ | ✔ | ✔ |
| Switch focus mode | ✔ | ✔ | ✔ | ✔ |
| Light control | ✔ | ✔ | ✔ | ✔ |
Gimbal Control Interface
Get Gimbal Pose Information
This interface is used to publish the current pose of the gimbal.
ROS2 Interface
| Topic Name | Topic Type | Role |
|---|---|---|
cam/PTZ_CAM/set_ptzf_position | cam_msgs::msg::PtzfPosition | Subscriber |
Message Structure
ptzf_position: of type PtzfPosition, includes the following fields:
| Parameter Name | Type | Description |
|---|---|---|
pan | float32 | Pan rotation |
tilt | float32 | Tilt rotation |
zoom | float32 | Zoom level |
focus | uint16 | Focus value |
Testing Method
ros2 topic echo /cam/PTZ_CAM/set_ptzf_positionPython Interface
void subscribe_ptzf_position(ptzf_position_callback)
Function Description
Subscribe to real-time gimbal status information.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
ptzf_position_callback | function | Required | Callback function for receiving real-time gimbal status information. |
ptzf_position Structure
| Field Name | Type | Description |
|---|---|---|
pan | float | Pan rotation. |
tilt | float | Tilt rotation. |
zoom | float | Zoom level. |
focus | uint16 | Focus value. |
Return Value
| Type | Description |
|---|---|
void | No return value. |
Usage Example
success = await client.subscribe_ptzf_position(ptzf_position_callback)
if success:
logging.info("Successfully subscribed to gimbal position information")
else:
logging.error("Failed to subscribe to gimbal position information")
def ptzf_position_callback(position_data):
"""Gimbal position data callback function"""
if "ptzf_position" in position_data:
ptzf = position_data["ptzf_position"]
logging.info(f"Gimbal position update - Pan: {ptzf.get('pan', 0):.3f}, "
f"Tilt: {ptzf.get('tilt', 0):.3f}, "
f"Zoom: {ptzf.get('zoom', 0):.3f}, "
f"Focus: {ptzf.get('focus', 0)}")void unsubscribe_ptzf_position()
Function Description
Unsubscribe from gimbal position information.
Parameter Description
None.
Return Value
| Type | Description |
|---|---|
void | No return value. |
C# Interface
void SubscribePtzPosition(Action<PtzPositionStamped> callback)
Function Description
Subscribe to the real-time position information of the gimbal, including pan, tilt, zoom, and focus parameters.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
callback | Action<PtzPositionStamped> | Required | Callback function for receiving position data. |
Return Value
| Type | Description |
|---|---|
void | No return value. |
void UnsubscribePtzPosition()
Function Description
Unsubscribe from the gimbal position information.
Parameter Description
None.
Return Value
| Type | Description |
|---|---|
void | No return value. |
Usage Example
// Subscribe to ptz position information
_robotMutiMediaClient?.SubscribePtzPosition(OnPtzPositionReceived);
// Callback function to process position data
private void OnPtzPositionReceived(PtzPositionStamped positionData)
{
Debug.Log($"ptz Position - Pan: {positionData.position.pan}, " +
$"Tilt: {positionData.position.tilt}, " +
$"Zoom: {positionData.position.zoom}, " +
$"Focus: {positionData.position.focus}");
}
// Unsubscribe from ptz position information
_robotMutiMediaClient?.UnsubscribePtzPosition();C++ Interface
bool subscribe_ptzf_position()
Function Description
Subscribe to gimbal position messages.
Parameter Description
None.
Return Value
| Type | Description |
|---|---|
bool | true if successful, false otherwise. |
bool unsubscribe_ptzf_position()
Function Description
Unsubscribe from gimbal position messages.
Parameter Description
None.
Return Value
| Type | Description |
|---|---|
bool | true if successful, false otherwise. |
Usage Example
Lenovo::Daystar::SDK sdk;
auto &ptz = sdk.getPTZ();
if (ptz.connect()) {
// Subscribe to position messages
ptz.subscribe_ptzf_position();
// Perform some operations...
std::this_thread::sleep_for(std::chrono::seconds(10));
// Unsubscribe
if (ptz.unsubscribe_ptzf_position()) {
std::cout << "Gimbal position subscription cancelled" << std::endl;
}
}Control Gimbal Motion Angle
This interface is used to move the gimbal to a specified angle.
ROS2 Interface
| Service Name | Service Type | Role |
|---|---|---|
/cam/PTZ_CAM/set_ptzf_position | cam_msgs::srv::SetPtzfPosition | Client |
Message Structure
cam_msgs::srv::SetPtzfPosition::Request includes the following fields:
| Parameter Name | Type | Description |
|---|---|---|
| relative | bool | Indicates whether relative movement is enabled |
| ptzf_position | PtzfPosition | Includes four fields: pan, tilt, zoom, focus |
ptzf_position fields:
| Field Name | Type | Description |
|---|---|---|
| pan | float32 | Pan rotation (-180~180) |
| tilt | float32 | Tilt rotation (-90~90) |
| zoom | float32 | Zoom level (1–25) |
| focus | uint16 | Focus value (4000–40000) |
Note
The focus field is only effective in manual focus mode.
Testing Method
- Call the interface to move the gimbal 90° left, 30° up, and zoom to 10x:
ros2 service call /cam/PTZ_CAM/set_ptzf_position cam_msgs/srv/SetPtzfPosition "relative: false
ptzf_position:
pan: 90.0
tilt: 30.0
zoom: 10.0
focus: 0"Python Interface
set_ptzf_position(position: PtzfPosition, relative)
Function Description
Control the gimbal to move to a specified angle.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
position | PtzfPosition | Required | Angle command. |
relative | bool | Required | Indicates whether relative movement is enabled. |
PtzfPosition Structure
| Field Name | Type | Description |
|---|---|---|
pan | float | Pan rotation (-180~180). |
tilt | float | Tilt rotation (-90~90). |
zoom | float | Zoom level (1~25). |
focus | float | Focus value (4000~40000). |
Return Value
| Type | Description |
|---|---|
bool | Whether the operation was successful. |
Usage Example
async with WebSocketRobotClient(host=args.host, port=args.port) as client:
await asyncio.sleep(1)
position = PtzfPosition(
pan=args.pan,
tilt=args.tilt,
zoom=args.zoom,
focus=args.focus
)
success = await client.set_ptzf_position(position, relative=args.relative)C# Interface
void SetPtzPosition(float pan, float tilt, float zoom, ushort focus, bool relative = false)
Function Description
Control the gimbal to move to a specified angle.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
pan | float | Required | Pan angle (-180~180). |
tilt | float | Required | Tilt angle (-90~90). |
zoom | float | Required | Zoom level (1~25). |
focus | ushort | Required | Focus value. |
relative | bool | false | Whether it is a relative position (true = relative, false = absolute). |
Return Value
| Type | Description |
|---|---|
void | No return value. |
Usage Example
// Absolute position control
robotMutiMediaClient.SetPtzPosition(45.0f, -30.0f, 2.0f, 0, false);
// Relative position control (adjust based on the current position)
robotMutiMediaClient.SetPtzPosition(10.0f, 0, 0, 0, true);C++ Interface
void call_ptz_position(float pan, float tilt, float zoom, uint16_t focus, bool relative = false)
Function Description
Control the gimbal to move to the specified position.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
pan | float | Required | Pan angle (-180~180). |
tilt | float | Required | Tilt angle (-90~90). |
zoom | float | Required | Zoom level (1~25). |
focus | uint16_t | Required | Focus value (4000~40000). |
relative | bool | false | Whether it is a relative position (true = relative, false = absolute). |
Return Value
| Type | Description |
|---|---|
void | No return value. |
Usage Example
Lenovo::Daystar::SDK sdk;
auto &ptz = sdk.getPTZ();
if (ptz.connect()) {
// Absolute position control: move gimbal to pan 30 degrees, tilt 15 degrees
ptz.call_ptz_position(30.0f, 15.0f, 1.5f, 100, false);
// Relative position control: pan right 10 degrees based on the current position
ptz.call_ptz_position(10.0f, 0.0f, 1.0f, 100, true);
}Control Continuous Gimbal Motion
This interface is used to continuously move the gimbal.
It involves four parameters:
| Parameter Name | Type | Description |
|---|---|---|
| pan | float32 | Horizontal angular velocity. Positive = counterclockwise, negative = clockwise, 0 = no movement (-12~12) |
| tilt | float32 | Vertical angular velocity. Positive = upward, negative = downward, 0 = no movement (-12~12) |
| zoom | float32 | Zoom velocity. Positive = zoom in, negative = zoom out, 0 = no movement (-12~12) |
| focus | uint16 | Focus velocity. Positive = push focus farther, negative = pull focus closer, 0 = no movement (-12~12) |
Note
When controlling continuous pan/tilt movement, the zoom and focus parameters must be set to 0.
ROS2 Interface
cam_msgs::srv::PtzfCmdVel::Request includes the following fields:
| Parameter Name | Type |
|---|---|
| pan | float32 |
| tilt | float32 |
| zoom | float32 |
| focus | uint16 |
Testing Method
- Call the interface to make the gimbal start rotating left:
ros2 topic pub /cam/PTZ_CAM/ptzf_cmd_vel cam_msgs/srv/PtzfCmdVel "
pan: 8.0
tilt: 0.0
zoom: 0.0
focus: 0"Python Interface
bool publish_ptzf_cmd_vel(cmd_vel: PtzfCmdVel)
Function Description
Continuously control gimbal motion.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
cmd_vel | PtzfCmdVel | Required | Velocity command object. |
PtzfCmdVel Definition
| Field Name | Type | Default | Description |
|---|---|---|---|
pan | float | 0.0 | Horizontal angular velocity (-12~12). |
tilt | float | 0.0 | Vertical angular velocity (-12~12). |
zoom | float | 0.0 | Zoom velocity (-12~12). |
focus | float | 0.0 | Focus velocity (-12~12). |
Return Value
| Type | Description |
|---|---|
bool | Whether the operation was successful. |
Usage Example
async with WebSocketRobotClient(host=args.host, port=args.port, client_name="complex_control") as client:
await asyncio.sleep(1)
await client.advertise_ptzf_cmd_vel()
await asyncio.sleep(0.5)
cmd_vel = PtzfCmdVel(
pan=args.pan,
tilt=args.tilt,
zoom=args.zoom,
focus=args.focus
)
print(f"Composite motion control: Pan={args.pan}, Tilt={args.tilt}, Zoom={args.zoom}, Focus={args.focus}")
success = await client.publish_ptzf_cmd_vel(cmd_vel)C# Interface
void MovePtzContinues(float panSpeed, float tiltSpeed, float zoomSpeed, float focusSpeed = 0)
Function Description
Continuously control gimbal motion.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
panSpeed | float | Required | Horizontal angular velocity (-12~12). |
tiltSpeed | float | Required | Vertical angular velocity (-12~12). |
zoomSpeed | float | Required | Zoom velocity (-12~12). |
focusSpeed | float | 0 | Focus velocity (-12~12). |
Return Value
| Type | Description |
|---|---|
void | No return value. |
Usage Example
// Continuous move left
robotMutiMediaClient.MovePtzContinues(8.0f, 0, 0, 0);
// Continuous move right
robotMutiMediaClient.MovePtzContinues(-8.0f, 0, 0, 0);
// Continuous move up
robotMutiMediaClient.MovePtzContinues(0, 8.0f, 0, 0);
// Continuous move down
robotMutiMediaClient.MovePtzContinues(0, -8.0f, 0, 0);
// Zoom in
robotMutiMediaClient.MovePtzContinues(0, 0, 1.0f, 0);
// Zoom out
robotMutiMediaClient.MovePtzContinues(0, 0, -1.0f, 0);
// Stop movement
robotMutiMediaClient.MovePtzContinues(0, 0, 0, 0);C++ Interface
void publish_ptzf_cmd_vel(float pan, float tilt, float zoom, float focus)
Function Description
Publish gimbal velocity control command.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
pan | float | Required | Horizontal angular velocity. Positive = counterclockwise, negative = clockwise, 0 = no movement (-12~12). |
tilt | float | Required | Vertical angular velocity. Positive = upward, negative = downward, 0 = no movement (-12~12). |
zoom | float | Required | Zoom velocity. Positive = zoom in, negative = zoom out, 0 = no movement (-12~12). |
focus | float | Required | Focus velocity. Positive = push focus farther, negative = pull focus closer, 0 = no movement (-12~12). |
Return Value
| Type | Description |
|---|---|
void | No return value. |
Usage Example
Lenovo::Daystar::SDK sdk;
auto &ptz = sdk.getPTZ();
if (ptz.connect()) {
// Rotate to the right at medium speed
for (int i = 0; i < 40; i++)
{
ptz.publish_ptzf_cmd_vel(0.8f, 0.0f, 0.0f, 0.0f);
// std::cout << "Sent velocity control command " << (i + 1) << "/40" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
std::this_thread::sleep_for(std::chrono::seconds(2));
// Stop all movement
ptz.stop_all_movement();
}Auxiliary Focus
ROS2 Interface
This interface is used to move the gimbal to a specified angle.
| Service Name | Service Type | Role |
|---|---|---|
/cam/PTZ_CAM/auto_focus | cam_msgs::srv::AutoFocus | Client |
Message Structure
cam_msgs::srv::AutoFocus::Request includes the following fields:
| Parameter Name | Type | Description |
|---|---|---|
| focus_mode | uint8 | 1: Global auto focus2: Regional auto focus |
| pixel_bbox | Bbox | Includes four fields: x_min, y_min, x_max, y_max |
pixel_bbox fields:
| Field Name | Type | Description |
|---|---|---|
| x_min | int32 | x-coordinate of the top-left corner of the rectangle |
| y_min | int32 | y-coordinate of the top-left corner of the rectangle |
| x_max | int32 | x-coordinate of the bottom-right corner of the rectangle |
| y_max | int32 | y-coordinate of the bottom-right corner of the rectangle |
Note
pixel_bbox is only valid in regional auto focus mode.
Testing Method
- Call the interface to perform regional auto focus:
ros2 service call /cam/PTZ_CAM/auto_focus cam_msgs/srv/AutoFocus "focus_mode: 2
pixel_bbox:
x_min: 500
y_min: 300
x_max: 1600
y_max: 900"Python Interface
bool auto_focus(focus_mode, pixel_bbox=None)
Function Description
Implement gimbal focus function.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
focus_mode | int | Required | Focus mode: 1=Global auto focus, 2=Regional auto focus. |
pixel_bbox | dict | None | Focus area settings (only valid in regional auto focus mode). |
Return Value
| Type | Description |
|---|---|
bool | Whether the operation was successful. |
Usage Example
async with WebSocketRobotClient(host=args.host, port=args.port) as client:
await asyncio.sleep(1)
if args.mode == 1:
success = await client.auto_focus(focus_mode=1)
elif args.mode == 2:
if hasattr(args, 'bbox') and args.bbox:
try:
coords = [int(x.strip()) for x in args.bbox.split(',')]
bbox = {
"x_min": coords[0],
"y_min": coords[1],
"x_max": coords[2],
"y_max": coords[3]
}
success = await client.auto_focus(focus_mode=2, pixel_bbox=bbox)C# Interface
bool AutoFocus(int focusMode = 1, PixelBoundingBox? pixelBbox = null, int timeoutMs = 8000)
Function Description
Enable auto focus.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
focusMode | int | 1 | Focus mode: 1=Global auto focus, 2=Regional auto focus. |
pixelBbox | PixelBoundingBox? | null | Focus area settings (only valid in regional auto focus mode). |
timeoutMs | int | 8000 | Timeout in milliseconds. |
Return Value
| Type | Description |
|---|---|
bool | Whether the operation was successful. |
Usage Example
// Semi-automatic focus
bool success = _robotMutiMediaClient?.AutoFocus(1) ?? false;
// Regional focus (using default center region)
bool success = _robotMutiMediaClient?.AutoFocus(2) ?? false;
// Regional focus (custom region)
PixelBoundingBox customRegion = new PixelBoundingBox
{
x_min = 100, y_min = 100,
x_max = 300, y_max = 300
};
bool success = _robotMutiMediaClient?.AutoFocus(2, customRegion) ?? false;C++ Interface
bool auto_focus(int focus_mode = 1)
Function Description
Enable auto focus.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
focus_mode | int | 1 | Focus mode (1 = auto focus). |
Return Value
| Type | Description |
|---|---|
bool | true if successful, false otherwise. |
Usage Example
Lenovo::Daystar::SDK sdk("192.168.100.103:50051");
auto &ptz = sdk.getPTZ();
if (ptz.connect()) {
if (ptz.auto_focus(1)) {
std::cout << "Auto focus enabled successfully" << std::endl;
} else {
std::cerr << "Failed to enable auto focus" << std::endl;
}
}Switch Focus Mode
ROS2 Interface
This interface is used to move the gimbal to a specified angle.
| Service Name | Service Type | Role |
|---|---|---|
/cam/PTZ_CAM/set_focus_mode | cam_msgs::srv::SetFocusMode | Client |
Message Structure
cam_msgs::srv::SetFocusMode::Request includes the following field:
| Parameter Name | Type | Description |
|---|---|---|
| focus_mode | uint8 | 1: Semi-automatic focus2: Manual focus |
Testing Method
- Call the interface to switch focus mode:
ros2 service call /cam/PTZ_CAM/set_focus_mode cam_msgs/srv/SetFocusMode "focus_mode: 2"Python Interface
bool set_focus_mode(focus_mode: int)
Function Description
Set the gimbal focus mode.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
focus_mode | int | Required | Focus mode: 1=Semi-automatic focus, 2=Manual focus. |
Return Value
| Type | Description |
|---|---|
bool | Whether the operation was successful. |
Usage Example
async with WebSocketRobotClient(host=args.host, port=args.port) as client:
await asyncio.sleep(1)
mode_names = {1: "Semi-automatic", 2: "Manual"}
mode_name = mode_names.get(args.mode, f"Unknown ({args.mode})")
print(f"Set focus mode to: {mode_name}")
success = await client.set_focus_mode(args.mode)C# Interface
bool SetFocusMode(int focusMode, int timeoutMs = 8000)
Function Description
Set the gimbal focus mode.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
focusMode | int | Required | Focus mode: 1=Semi-automatic focus, 2=Manual focus. |
timeoutMs | int | 8000 | Timeout in milliseconds. |
Return Value
| Type | Description |
|---|---|
bool | Whether the operation was successful. |
Usage Example
// Set to semi-automatic focus mode
bool success = _robotMutiMediaClient?.SetFocusMode(1) ?? false;
// Set to manual focus mode
bool success = _robotMutiMediaClient?.SetFocusMode(2) ?? false;C++ Interface
bool set_focus_mode(int focus_mode)
Function Description
Set focus mode.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
focus_mode | int | Required | Focus mode: 1=Semi-automatic focus, 2=Manual focus. |
Return Value
| Type | Description |
|---|---|
bool | true if successful, false otherwise. |
Usage Example
Lenovo::Daystar::SDK sdk;
auto &ptz = sdk.getPTZ();
if (ptz.connect()) {
if (ptz.set_focus_mode(2)) {
std::cout << "Focus mode set successfully" << std::endl;
} else {
std::cerr << "Failed to set focus mode" << std::endl;
}
}Light Control
ROS2 Interface
This interface is used to control the gimbal light.
| Service Name | Service Type | Role |
|---|---|---|
/cam/PTZ_CAM/light_cmd | cam_msgs::srv::SetBool | Client |
Message Structure
cam_msgs::srv::SetBool::Request includes the following field:
| Value | Description |
|---|---|
1 | Turn on the light |
0 | Turn off the light |
Testing Method
- Call the interface to switch the light state:
ros2 service call /cam/PTZ_CAM/light_cmd cam_msgs/srv/SetBool "focus_mode: 2"Python Interface
bool light_cmd(enable: bool)
Function Description
Control the gimbal light.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
enable | bool | Required | true to turn on the light,false to turn off. |
Return Value
| Type | Description |
|---|---|
bool | Whether the operation was successful. |
Usage Example
async with WebSocketRobotClient(host=args.host, port=args.port, client_name="light_control") as client:
await asyncio.sleep(1)
action_str = "Turn on" if args.enable else "Turn off"
print(f"{action_str} gimbal light...")
success = await client.light_cmd(args.enable)C# Interface
void SetPtzLight(bool enable)
Function Description
Control the gimbal light.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
enable | bool | Required | true to turn on the light, false to turn off. |
Return Value
| Type | Description |
|---|---|
void | No return value. |
Usage Example
// Turn on PTZ light
robotMutiMediaClient.SetPtzLight(true);
// Turn off PTZ light
robotMutiMediaClient.SetPtzLight(false);C++ Interface
bool light_cmd(bool enable)
Function Description
Control the fill light.
Parameter Description
| Parameter Name | Type | Required/Default | Description |
|---|---|---|---|
enable | bool | Required | true to turn on the fill light, false to turn off. |
Return Value
| Type | Description |
|---|---|
bool | true if successful, false otherwise. |
Usage Example
Lenovo::Daystar::SDK sdk("192.168.100.103:50051");
auto &ptz = sdk.getPTZ();
if (ptz.connect()) {
// Turn on the fill light
if (ptz.light_cmd(true)) {
std::cout << "Fill light turned on" << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(5));
// Turn off the fill light
if (ptz.light_cmd(false)) {
std::cout << "Fill light turned off" << std::endl;
}
}