Python SDK
Overview
BonicBot Bridge is a Python SDK designed for educational robotics programming. It provides a high-level, intuitive API that abstracts the complexity of ROS2 robotics into simple commands suitable for STEM education and beginners.
Key Features
- Educational Focus: Simple, easy-to-understand API designed for learning
- Remote Control: Control robots from any computer on the same network
- Autonomous Navigation: Path planning and goal-based navigation
- SLAM Mapping: Create maps of environments for navigation
- Vision Processing: Camera streaming with real-time image capture
- Servo Manipulation: Control robot arms, grippers, and neck movements
- Real-time Feedback: Live updates on position, battery, and navigation status
- Safety Built-in: Automatic connection management and error handling
System Requirements
- Python Version: 3.8 or higher
- Robot Hardware: BonicBot A2 with ROS2 Humble
- Network: Robot and control computer on same network
- Dependencies: roslibpy (auto-installed with pip)
Supported Platforms
- Raspberry Pi 4 (for onboard execution)
- Ubuntu 20.04/22.04
- Windows 10/11 (remote control)
- macOS (remote control)
Installing and Setting Up the Python SDK
Install the BonicBot Bridge SDK using pip:
pip install bonicbot-bridgeRequirements
- Python 3.8 or higher
- BonicBot robot running ROS2
- rosbridge_server running on port 9090
- Robot and computer on the same network (for remote access)
Understanding the SDK Structure and Basic API Usage
The BonicBot class is the main interface for connecting to and controlling the robot using the Python SDK.
Constructor
BonicBot(host='localhost', port=9090, timeout=10)Parameters
- host (str): Robot IP address or hostname
- Use ‘localhost’ when running code on the robot
- Use the robot’s IP or hostname for remote access
- port (int): Port on which rosbridge_server is running (Default: 9090)
- timeout (int): Maximum connection wait time in seconds
Connection Examples
Local Connection (On Robot)
from bonicbot_bridge import BonicBot
bot = BonicBot()Remote Connection (Using IP)
from bonicbot_bridge import BonicBot
bot = BonicBot(host='192.168.1.100')Remote Connection (Using Hostname)
from bonicbot_bridge import BonicBot
bot = BonicBot(host='bonic.local')Best Practice (Recommended)
from bonicbot_bridge import BonicBot
with BonicBot(host='192.168.1.100') as bot:
bot.move_forward(0.3, 2)This ensures the connection is automatically closed after execution.
Checking Robot Connection
To test whether the robot is connected, you can use the is_connected() method.
Purpose: Checks whether the robot is currently connected to the Python SDK. This method should be used before sending any commands to ensure that communication with the robot is active.
Returns:
True– if the robot is connectedFalse– if the robot is not connected
Example Usage:
if bot.is_connected():
print("Robot connection OK")
else:
print("Robot not connected")Controlling Robot Movement
The movement API allows you to control the robot using either low-level velocity commands or high-level convenience functions.
Low-Level Movement (Velocity Control)
move(linear_x=0, linear_y=0, angular_z=0)
Description: Directly controls robot velocities. This is a low-level command where you specify forward/backward, sideways (if supported), and rotation speeds.
linear_x→ forward/backward speed in m/slinear_y→ sideways speed in m/s (for omnidirectional robots)angular_z→ rotation speed in degrees/s
Note: Must be continuously published to keep the robot moving.
Example:
bot.motion.move(linear_x=0.3, angular_z=30) # Move forward while turning
bot.motion.move(0, 0, 0)High-Level Movement (Convenience Functions)
These functions are convenience methods that handle timing and velocity publishing automatically.
move_forward(speed, duration=None)
Description: Moves the robot forward at the given speed. If duration is provided, the robot stops automatically after that time.
Example:
bot.move_forward(0.5, duration=2) # Move forward 2 secondsmove_backward(speed, duration=None)
Description: Moves the robot backward at the given speed. Automatically stops after duration if provided.
Example:
bot.move_backward(0.2, duration=1.5) # Move backward for 1.5 secondsturn_left(speed, duration=None)
Description: Rotates the robot counter-clockwise at the given speed. Stops after duration if provided.
Example:
bot.turn_left(0.5, duration=1) # Turn left for 1 secondturn_right(speed, duration=None)
Description: Rotates the robot clockwise at the given speed. Stops after duration if provided.
Example:
bot.turn_right(0.5, duration=1) # Turn right for 1 secondstop()
Description: Immediately stops all robot movement. Equivalent to sending zero velocities.
Example:
bot.stop() # Stop immediatelyExample: High-Level Robot Movement
This example demonstrates the use of high-level movement methods in the BonicBot SDK. It shows how to move the robot forward, backward, turn left, turn right, and stop, with automatic duration control and built-in command management for easy educational use.
from bonicbot_bridge import BonicBot
import time
# Connect to the robot
with BonicBot() as bot:
print("Starting high-level movement demo...")
# Move forward for 2 seconds
print("Moving forward...")
bot.move_forward(0.5, duration=2)
time.sleep(0.5)
# Turn left for 1 second
print("Turning left...")
bot.turn_left(0.5, duration=1)
time.sleep(0.5)
# Move backward for 1.5 seconds
print("Moving backward...")
bot.move_backward(0.3, duration=1.5)
time.sleep(0.5)
# Turn right for 1 second
print("Turning right...")
bot.turn_right(0.5, duration=1)
time.sleep(0.5)
# Stop the robot
print("Stopping robot...")
bot.stop()
print("High-level movement demo complete!")Reading Sensor Data
Sensor methods provide access to the robot’s real-time state information such as position, orientation, and battery level.
get_position()
Returns the robot’s current position and orientation.
Returns: A dictionary containing:
x– X position in metersy– Y position in meterstheta– Orientation in degrees- Returns
Noneif position data is not available
Example:
pos = bot.get_position()
if pos:
print(f"X: {pos['x']:.2f}, Y: {pos['y']:.2f}, Heading: {pos['theta']:.2f}°")get_x(), get_y(), get_heading()
Return individual components of the robot’s position.
get_x()– Current X position (meters)get_y()– Current Y position (meters)get_heading()– Current heading in degrees
Example:
x = bot.get_x()
y = bot.get_y()
heading = bot.get_heading()
print(f"X: {x}, Y: {y}, Heading: {heading}°")get_heading_degrees()
Return the robot’s heading in degrees. This method is functionally equivalent to get_heading().
Example:
heading_deg = bot.get_heading_degrees()
print(f"Heading: {heading_deg}°")get_battery()
Returns the robot’s battery level as a percentage.
Note: Not implemented yet
Returns: Integer value between 0 and 100
Example:
battery = bot.get_battery()
print(f"Battery Level: {battery}%")Example: Reading Sensor Data in a Loop
This example demonstrates how to read the robot’s current position, orientation, and battery level at regular intervals using the sensor API.
from bonicbot_bridge import BonicBot
import time
with BonicBot() as bot:
for i in range(5):
pos = bot.get_position()
battery = bot.get_battery()
if pos:
print(f"X={pos['x']:.2f}, Y={pos['y']:.2f}, Heading={pos['theta']:.2f}°")
print(f"Battery: {battery}%")
time.sleep(1)System Control Methods
Control the robot’s mapping and localization systems using these methods.
start_mapping()
Start SLAM (Simultaneous Localization and Mapping) mode to create a map of the environment.
Example:
bot.start_mapping()
# Drive the robot around to explore
bot.save_map() # Save the map after mappingstop_mapping()
Stop the SLAM mapping process.
Example:
bot.stop_mapping()save_map()
Save the map created during mapping for future navigation.
Example:
bot.save_map()Example: Mapping the Environment
This example demonstrates starting SLAM mapping, exploring the environment, stopping mapping, and saving the map for future use.
from bonicbot_bridge import BonicBot
import time
with BonicBot() as bot:
print("Starting SLAM mapping...")
# Start mapping
bot.start_mapping()
# Move the robot around manually or programmatically
bot.move_forward(0.3, duration=2)
bot.turn_left(0.5, duration=1)
bot.move_forward(0.3, duration=2)
bot.turn_right(0.5, duration=1)
# Stop mapping
bot.stop_mapping()
# Save the created map
bot.save_map()
print("Mapping complete and map saved!")Navigation Methods
Control the robot’s autonomous navigation system using these methods. To use navigation, mapping should be done or a saved map should be available. If mapping is currently running, you can start navigation and set goals directly. However, if you are using a saved map (mapping is not running), you must first set the initial position before starting navigation, and then you can set goals for the robot.
start_navigation()
Start the robot’s navigation system. Must be called before sending navigation commands.
Example:
bot.start_navigation()stop_navigation()
Stop the navigation system.
Example:
bot.stop_navigation()go_to(x, y, theta=0)
Sending a navigation to a goal. Navigate the robot autonomously to the specified coordinates.
Parameters:
x (float): Target X coordinate in metersy (float): Target Y coordinate in meterstheta (float, optional): Target orientation in degrees
Example:
bot.go_to(2.0, 1.5) # Go to (2.0, 1.5)
bot.go_to(0.0, 0.0, 90) # Go to origin facing 90°wait_for_goal(timeout=30)
Monitoring Navigation Status. Waits until the navigation goal is completed or fails.
Returns: ‘goal_reached’, ‘goal_failed’, ‘cancelled’, or ‘timeout’
Example:
result = bot.wait_for_goal()
if result == 'goal_reached':
print("Successfully reached destination!")cancel_goal()
Cancel the current navigation goal immediately.
Example:
bot.cancel_goal()set_initial_pose(x, y, theta=0)
Set the robot’s initial position and orientation on a map. Useful when using saved maps for navigation.
Example:
bot.set_initial_pose(0.0, 0.0, 0.0) # At origin
bot.set_initial_pose(2.0, 1.5, 90) # At specific location and orientationExample: Navigation with Active and Saved Maps
Demonstrates how to navigate a BonicBot both during active SLAM mapping and using a saved map. The example shows setting goals, waiting for completion, and handling initial poses when using a saved map.
from bonicbot_bridge import BonicBot
with BonicBot() as bot:
# -------------------------------
# Scenario 1: Navigation while mapping is running
# -------------------------------
print("Starting navigation with active mapping...")
bot.start_mapping() # Start SLAM mapping
bot.start_navigation() # Start navigation system
# Set a navigation goal while mapping
bot.go_to(2.0, 1.5)
result = bot.wait_for_goal(timeout=30)
if result == 'goal_reached':
print("Reached goal during active mapping!")
else:
print(f"Navigation result: {result}")
# Stop navigation and mapping
bot.stop_navigation()
bot.stop_mapping()
# -------------------------------
# Scenario 2: Navigation using a saved map
# -------------------------------
print("\nStarting navigation using a saved map...")
bot.set_initial_pose(0.0, 0.0, 0.0) # Set initial position for localization
bot.start_navigation() # Start navigation system
# Set a goal on the saved map
bot.go_to(3.0, 2.0)
result = bot.wait_for_goal(timeout=30)
if result == 'goal_reached':
print("Reached goal on saved map!")
else:
print(f"Navigation result: {result}")
# Stop navigation
bot.stop_navigation()
print("\nNavigation demo complete!")Status Methods
Status methods allow you to monitor the robot’s connection, navigation state, and progress toward goals in real time.
is_connected()
Purpose: Checks whether the robot is currently connected to the Python SDK. This is useful before sending any commands to ensure communication with the robot is active.
Returns:
Trueif the robot is connectedFalseif not connected
Example Usage:
if bot.is_connected():
print("Robot connection OK")
else:
print("Robot not connected")get_nav_status()
Purpose: Retrieves the current navigation status of the robot. This helps you know whether the robot is idle, moving toward a goal, or if there was a problem during navigation.
Returns: A string indicating the robot’s navigation state:
'idle'– No navigation goal is active'navigating'– Robot is currently moving toward a goal'goal_reached'– Robot successfully reached its goal'goal_failed'– Robot failed to reach the goal'cancelled'– Navigation was cancelled
Example Usage:
status = bot.get_nav_status()
print(f"Navigation Status: {status}")get_distance_to_goal()
Purpose: Returns the remaining distance from the robot’s current position to the active navigation goal. Useful for monitoring progress during autonomous navigation.
Returns:
- A float representing distance in meters
- Returns
Noneif there’s no active navigation goal
Example Usage:
distance = bot.get_distance_to_goal()
if distance is not None:
print(f"Distance to Goal: {distance:.1f} meters")
else:
print("No active goal")Example: Real-Time Robot Status Monitoring
Demonstrates how to monitor a BonicBot’s connection, navigation status, and distance to its goal in real time, providing feedback during autonomous movement.
from bonicbot_bridge import BonicBot
import time
with BonicBot() as bot:
# Check connection
if not bot.is_connected():
print("Robot not connected!")
else:
print("Robot connection OK")
# Start navigation (assuming a map is ready)
bot.start_navigation()
bot.go_to(2.0, 1.5) # Set a goal
# Monitor status until goal is reached or failed
while True:
status = bot.get_nav_status()
distance = bot.get_distance_to_goal()
print(f"Navigation Status: {status}")
if distance is not None:
print(f"Distance to Goal: {distance:.1f} meters")
if status in ['goal_reached', 'goal_failed', 'cancelled']:
break
time.sleep(1)
print("Navigation finished!")BonicBot Camera Methods
start_camera(callback=None)
Start camera streaming. Optionally, provide a callback function to process each frame in real-time.
Parameters:
callback (function, optional): Function called for each frame:callback(image)
Examples:
# Simple streaming
bot.start_camera()
# Streaming with callback for processing
def process_frame(image):
print(f"Frame shape: {image.shape}")
bot.start_camera(callback=process_frame)stop_camera()
Stop camera streaming.
Example:
bot.stop_camera()get_image()
Get the latest camera image as a NumPy array (BGR format). Returns None if no image is available.
Returns: numpy.ndarray or None
Example:
image = bot.get_image()
if image is not None:
print(f"Image shape: {image.shape}")save_image(filepath)
Saves the current camera image to a file or in rpi or dev system.
Parameters:
filepath (str): Path and filename to save the image
Example:
bot.save_image("robot_view.jpg")Example: Using Camera Methods
This example demonstrates how to use the BonicBot camera via the BonicBot Bridge Python SDK. It shows how to start and stop camera streaming, process frames in real-time with a callback, retrieve the latest image as a NumPy array, and save images to a file.
# Import the BonicBot Bridge SDK
from bonicbot_bridge import BonicBot
import time
# Initialize the robot
bot = BonicBot()
# ------------------------------
# Start camera streaming without a callback
# ------------------------------
bot.start_camera()
print("Streaming started without callback...")
time.sleep(3) # Stream for 3 seconds
# Stop streaming
bot.stop_camera()
print("Streaming stopped.")
# ------------------------------
# Start camera streaming with a callback for processing frames
# ------------------------------
def process_frame(image):
print(f"Processing frame with shape: {image.shape}")
bot.start_camera(callback=process_frame)
print("Streaming started with callback...")
time.sleep(5) # Stream for 5 seconds
bot.stop_camera()
print("Streaming stopped.")
# ------------------------------
# Get the latest image
# ------------------------------
image = bot.get_image()
if image is not None:
print(f"Latest image shape: {image.shape}")
# ------------------------------
# Save the latest image to file
# ------------------------------
bot.save_image("robot_view.jpg")
print("Image saved as robot_view.jpg")BonicBot Servo Control Methods
Control the robot’s servos for arms, grippers, and neck movements. You can set individual or multiple servo angles, move arms, operate grippers, rotate the neck, or reset all servos to their neutral positions.
set_servos(angles)
Set multiple servo angles at once.
Parameters:
angles (dict): Dictionary mapping joint names to angles in degrees
Example:
bot.set_servos({
'left_shoulder_pitch_joint': 45.0,
'neck_yaw_joint': -30.0
})move_left_arm(shoulder, elbow) / move_right_arm(shoulder, elbow)
Move robot arms to specified shoulder and elbow angles.
Parameters:
shoulder (float): Shoulder pitch angle (-45° to 180°)elbow (float): Elbow angle (0° to 50°)
Example:
bot.move_left_arm(90, 30) # Left arm up
bot.move_right_arm(45, 20) # Right arm halfwayset_grippers(left, right) / open_grippers() / close_grippers()
Control the robot’s gripper fingers.
Examples:
bot.open_grippers() # Open both grippers
bot.close_grippers() # Close both grippers
bot.set_grippers(30, 30) # Partially openset_neck(yaw) / look_left() / look_right() / look_center()
Control neck rotation.
Parameters:
yaw (float): Neck yaw angle (-90° to 90°)
Examples:
bot.set_neck(-45) # Look right 45°
bot.look_left() # Turn fully left
bot.look_center() # Center positionreset_servos()
Reset all servos to neutral (0°) position.
Example:
bot.reset_servos()Example: Full Servo Control
This example demonstrates the full range of BonicBot servo controls using the BonicBot Bridge Python SDK. It shows how to move arms, set multiple servo angles, operate grippers, rotate the neck, and reset all servos to neutral positions, providing a complete overview of basic robot motion and gestures.
from bonicbot_bridge import BonicBot
# Initialize the robot
bot = BonicBot()
# ------------------------------
# Move arms to specific positions
# ------------------------------
bot.move_left_arm(90, 30) # Left arm up
bot.move_right_arm(45, 20) # Right arm halfway
# ------------------------------
# Set multiple servos at once
# ------------------------------
bot.set_servos({
'left_shoulder_pitch_joint': 60,
'right_shoulder_pitch_joint': 60,
'neck_yaw_joint': 0
})
# ------------------------------
# Control grippers
# ------------------------------
bot.open_grippers() # Open both grippers
bot.set_grippers(30, 30) # Partially open grippers
bot.close_grippers() # Close both grippers
# ------------------------------
# Control neck rotation
# ------------------------------
bot.set_neck(-45) # Turn neck right
bot.look_left() # Turn fully left
bot.look_right() # Turn fully right
bot.look_center() # Reset neck to center
# ------------------------------
# Reset all servos
# ------------------------------
bot.reset_servos()