Gesture
The /qtrobot/gesture/... services play, record, and stop pre-built keyframe motions. These examples assume the gateway from Connection is already running.
List available gestures
ros2 service call /qtrobot/gesture/file/list qtrobot_interfaces/srv/GestureFileList "{}"
Play a gesture
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from qtrobot_interfaces.srv import GestureFilePlay, GestureCancel
class GestureClient(Node):
def __init__(self):
super().__init__('gesture_client')
self.play_client = self.create_client(GestureFilePlay, '/qtrobot/gesture/file/play')
self.cancel_client = self.create_client(GestureCancel, '/qtrobot/gesture/cancel')
self.play_client.wait_for_service(timeout_sec=5.0)
def play(self, gesture: str, speed_factor: float = 1.0):
future = self.play_client.call_async(GestureFilePlay.Request(gesture=gesture, speed_factor=speed_factor))
rclpy.spin_until_future_complete(self, future)
return future.result()
def cancel(self):
future = self.cancel_client.call_async(GestureCancel.Request())
rclpy.spin_until_future_complete(self, future)
return future.result()
def main():
rclpy.init()
node = GestureClient()
node.play('QT/send_kiss')
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Gesture names follow the <group>/<name> pattern returned by /qtrobot/gesture/file/list, such as QT/send_kiss — the same naming convention used by face/emotion. Gestures live as files on the robot; there's no service to delete them remotely.
Play raw keyframes
ros2 service call /qtrobot/gesture/play qtrobot_interfaces/srv/GesturePlay \
"{keyframes: '{\"HeadYaw\": [0, 20, 0], \"HeadPitch\": [0, -10, 0]}', rate_hz: 10.0, speed_factor: 1.0, resample: true}"
keyframes is a JSON-encoded dict mapping each motor name to a list of target positions, played back at rate_hz.
Cancel a gesture
ros2 service call /qtrobot/gesture/cancel qtrobot_interfaces/srv/GestureCancel "{}"
Record a new gesture
ros2 service call /qtrobot/gesture/record/start qtrobot_interfaces/srv/GestureRecordStart \
"{motors: '[\"HeadYaw\", \"HeadPitch\"]', timeout_ms: 10000, release_motors: true}"
# ... move the robot's head by hand ...
ros2 service call /qtrobot/gesture/record/stop qtrobot_interfaces/srv/GestureRecordStop "{}"
ros2 service call /qtrobot/gesture/record/store qtrobot_interfaces/srv/GestureRecordStore "{gesture: 'QT/my_gesture'}"
release_motors: true lets you physically move the joints by hand while recording (no torque holding them in place) — the same parameter the Python and TypeScript SDKs expose.
Gesture progress
ros2 topic echo /qtrobot/gesture/progress/stream
GestureProgressFrame reports playback progress as a 0–100% value alongside elapsed time in microseconds, the same shape used by MotorJointsStateFrame (see Motor) — subscribe to it the same way.
Next steps
Continue with the Speaker tutorial, or see the full gesture namespace in the ROS2 API Reference.