Skip to Content
BonicBot A2DevelopmentPython ProgrammingLesson 25 - Servo Feedback & Safety Limits

Lesson 25 - Servo Feedback & Safety Limits

Learning Objective

  • Query hardware-enforced min/max joint angle bounds using bot.get_servo_limits().
  • Retrieve real-time joint angle feedback reported by physical servos using bot.get_servo_angles().
  • Command single servos directly by joint name using bot.set_single_servo() and bot.get_single_servo().

Introduction

Physical servos have strict mechanical travel bounds (e.g. neck yaw limits between -90° and +90°). Commanding angles outside these limits can cause gear strain or electrical stalls.

This lesson covers querying hardware safety limits, reading live joint angle feedback, and setting individual servos safely.


Code

servo_feedback_and_limits.py
import time from bonicbot_bridge import BonicBot with BonicBot(host="192.168.29.52") as bot: print("1. Fetching hardware servo limits dictionary...") limits = bot.get_servo_limits() for joint_name, (min_deg, max_deg) in limits.items(): print(f" - {joint_name}: [{min_deg}°, {max_deg}°]") print("\n2. Setting single servo 'neck_yaw' to 30.0°...") bot.set_single_servo("neck_yaw", 30.0) time.sleep(2) print("\n3. Querying single servo angle feedback...") current_neck = bot.get_single_servo("neck_yaw") print(f"Current 'neck_yaw' angle: {current_neck}°") print("\n4. Reading live dictionary of all active joint angles...") all_angles = bot.get_servo_angles() print("All joint angles:", all_angles) print("\n5. Resetting all servos to neutral 0° positions...") bot.reset_servos()

Expected Output

Click to see expected output

Visual Output

Terminal Output

🤖 Connected to BonicBot at 192.168.29.52:9090 1. Fetching hardware servo limits dictionary... - left_shoulder: [-45.0°, 180.0°] - left_elbow: [0.0°, 50.0°] - right_shoulder: [-45.0°, 180.0°] - right_elbow: [0.0°, 50.0°] - left_gripper: [-45.0°, 60.0°] - right_gripper: [-45.0°, 60.0°] - neck_yaw: [-90.0°, 90.0°] 2. Setting single servo 'neck_yaw' to 30.0°... 3. Querying single servo angle feedback... Current 'neck_yaw' angle: 30.0° 4. Reading live dictionary of all active joint angles... All joint angles: {'neck_yaw': 30.0, 'left_shoulder': 0.0, 'left_elbow': 0.0, ...} 5. Resetting all servos to neutral 0° positions... 🔌 Disconnected from BonicBot

🔧 Under the Hood

How _validate_angle() protects servos in servo.py

ServoController checks requested target angles against SERVO_LIMITS before publishing:

def _validate_angle(self, joint_name, angle): if joint_name not in SERVO_LIMITS: raise ServoError(f"Unknown servo joint: {joint_name}") min_angle, max_angle = SERVO_LIMITS[joint_name] if angle < min_angle or angle > max_angle: print(f"⚠️ Angle {angle}° outside limits [{min_angle}°, {max_angle}°], rejecting") return None return angle

Out-of-bound target commands are safely rejected before reaching hardware.


Student Challenge

Challenge 1 — Python Only

Write a safety validation function validate_joint_command(joint_name, requested_angle, limits_dict) that returns True if valid or raises ValueError if out of bounds.

Click to see solution

validate_joint.py
def validate_joint_command(joint_name, requested_angle, limits_dict): if joint_name not in limits_dict: raise ValueError(f"Unknown joint '{joint_name}'") min_deg, max_deg = limits_dict[joint_name] if not (min_deg <= requested_angle <= max_deg): raise ValueError(f"Angle {requested_angle}° out of bounds [{min_deg}, {max_deg}] for {joint_name}") return True limits = {'neck_yaw': (-90.0, 90.0)} print("Validation result:", validate_joint_command('neck_yaw', 45.0, limits))

Challenge 2 — Robot

Write a script that queries get_servo_angles(), verifies that every active joint angle is currently inside its hardware limit bounds, and prints a safety diagnostic summary.

Click to see solution

servo_health_audit.py
from bonicbot_bridge import BonicBot with BonicBot(host="192.168.0.188") as bot: limits = bot.get_servo_limits() angles = bot.get_servo_angles() print("--- Servo Joint Health Audit ---") for joint, current_angle in angles.items(): if joint in limits: min_lim, max_lim = limits[joint] status = "✅ OK" if min_lim <= current_angle <= max_lim else "⚠️ OUT OF BOUNDS" print(f"{joint}: {current_angle:.1f}° [{min_lim}°, {max_lim}°] -> {status}")

Quick Reference

MethodReturn TypeDescription
bot.get_servo_limits()dictDictionary mapping joint_name: (min_deg, max_deg)
bot.get_servo_angles()dictLive dictionary mapping joint_name: current_deg
bot.set_single_servo(joint, angle)boolCommand single joint by name in degrees
bot.get_single_servo(joint)floatRetrieve current angle of single joint

Reflection Questions

Why is write-path validation (rejecting out-of-bounds commands before publishing) crucial in physical robotics APIs?

Why might live feedback from get_servo_angles() slightly differ from the commanded target angle during active motion?

Last updated on