Skip to main content
Version: QTrobot V3

Motor

The /qtrobot/motor/... services and topics list motors, control torque/homing/velocity, and stream joint state, errors, and commands. These examples assume the gateway from Connection is already running.

List motors​

ros2 service call /qtrobot/motor/list qtrobot_interfaces/srv/MotorList "{}"

Torque on/off and homing​

ros2 service call /qtrobot/motor/on/all qtrobot_interfaces/srv/MotorOnAll "{}"
ros2 service call /qtrobot/motor/move/home/all qtrobot_interfaces/srv/MotorMoveHomeAll "{}"

ros2 service call /qtrobot/motor/on qtrobot_interfaces/srv/MotorOn "{motor: 'HeadYaw'}"
ros2 service call /qtrobot/motor/off qtrobot_interfaces/srv/MotorOff "{motor: 'HeadYaw'}"
ros2 service call /qtrobot/motor/move/home qtrobot_interfaces/srv/MotorMoveHome "{motor: 'HeadYaw'}"

Set velocity​

ros2 service call /qtrobot/motor/velocity/set qtrobot_interfaces/srv/MotorVelocitySet \
"{motor: 'HeadYaw', velocity: 50}"

Subscribing to joint state​

Before writing a node, it's often useful to peek at a topic's live data and exact type from the command line:

ros2 topic echo /qtrobot/motor/joints/state/stream
ros2 interface show qtrobot_interfaces/msg/MotorJointsStateFrame
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from qtrobot_interfaces.msg import MotorJointsStateFrame


class JointStateListener(Node):
def __init__(self):
super().__init__('joint_state_listener')
self.subscription = self.create_subscription(
MotorJointsStateFrame,
'/qtrobot/motor/joints/state/stream',
self.on_joint_state,
10,
)

def on_joint_state(self, msg: MotorJointsStateFrame):
for joint in msg.joints:
self.get_logger().info(
f'{joint.name}: position={joint.position:.1f} deg, '
f'velocity={joint.velocity:.1f} deg/s, temperature={joint.temperature:.1f} C'
)


def main():
rclpy.init()
node = JointStateListener()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()


if __name__ == '__main__':
main()

MotorJointsStateFrame carries a joints array of MotorJointState entries (name, position, velocity, effort, voltage, temperature), published at 10 Hz.

Subscribing to joint errors​

ros2 topic echo /qtrobot/motor/joints/error/stream

MotorJointsErrorFrame follows the same shape as joint state, but only publishes on change, carrying per-joint error flags (overload, voltage, temperature, sensor).

Sending joint commands​

Instead of motor/velocity/set, you can drive joints continuously by publishing MotorJointsCommandFrame messages to the command stream:

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from qtrobot_interfaces.msg import MotorJointsCommandFrame, MotorJointCommand


class JointCommander(Node):
def __init__(self):
super().__init__('joint_commander')
self.pub = self.create_publisher(MotorJointsCommandFrame, '/qtrobot/motor/joints/command/stream', 10)

def send(self, joint: str, position: float, velocity: float = 40.0):
cmd = MotorJointCommand(name=joint, position=position, velocity=velocity)
self.pub.publish(MotorJointsCommandFrame(joints=[cmd]))


def main():
rclpy.init()
node = JointCommander()
node.send('HeadYaw', position=15.0, velocity=40.0)
node.destroy_node()
rclpy.shutdown()


if __name__ == '__main__':
main()

MotorJointsCommandFrame carries a joints array of MotorJointCommand entries (name, position, velocity) — publish as many joints per message as you want to move together.

Next steps​

See the full motor namespace in the ROS2 API Reference, or head back to the Tutorials overview to explore Python or TypeScript/Node.js.