Skip to main content

ROS-like Python library for game robot control via WebSocket

Project description

agroweekpy

ROS-like Python library for game robot control via WebSocket.

Overview

agroweekpy provides a familiar rospy-style API for controlling robots in a game via WebSocket communication. It supports:

  • Motor Control: Set velocities for left and right motors
  • Odometry: Get distance traveled by motors
  • Yaw/Orientation: Get rotation angle (Y-axis)

Installation

pip install -e .

Or install dependencies directly:

pip install websockets

Quick Start

import agroweekpy
from agroweekpy.msg import MotorCommand

# Initialize node and connect to game
agroweekpy.init_node('my_rover', uri='ws://localhost:8765')

# Create motor publisher
motor_pub = agroweekpy.Publisher('/motor_cmd', MotorCommand)

# Main control loop
rate = agroweekpy.Rate(10)  # 10 Hz
while not agroweekpy.is_shutdown():
    cmd = MotorCommand(left_velocity=0.5, right_velocity=0.5)
    motor_pub.publish(cmd)
    rate.sleep()

API Reference

Node Management

# Initialize node
agroweekpy.init_node(name, uri='ws://localhost:8765', anonymous=False)

# Check shutdown state
agroweekpy.is_shutdown()  # Returns True/False

# Block until shutdown
agroweekpy.spin()

# Request shutdown
agroweekpy.signal_shutdown(reason='done')

# Register shutdown callback
agroweekpy.on_shutdown(lambda reason: print(f'Shutting down: {reason}'))

Rate Control

rate = agroweekpy.Rate(10)  # 10 Hz

while not agroweekpy.is_shutdown():
    # Do work...
    rate.sleep()  # Sleep to maintain rate

Logging

agroweekpy.logdebug('Debug message')
agroweekpy.loginfo('Info message')
agroweekpy.logwarn('Warning message')
agroweekpy.logerr('Error message')
agroweekpy.logfatal('Fatal message')

Publisher

from agroweekpy import Publisher
from agroweekpy.msg import MotorCommand

# Create publisher
pub = Publisher('/motor_cmd', MotorCommand, queue_size=10)

# Publish message
cmd = MotorCommand(left_velocity=0.5, right_velocity=0.5)
pub.publish(cmd)

MotorPublisher (Convenience Class)

from agroweekpy import MotorPublisher

motor = MotorPublisher('/motor_cmd')

motor.forward(0.5)      # Move forward
motor.backward(0.5)     # Move backward
motor.turn_left(0.3)    # Turn left in place
motor.turn_right(0.3)   # Turn right in place
motor.stop()            # Stop motors
motor.set_velocity(0.5, 0.3)  # Set left/right velocities

Subscriber

from agroweekpy import Subscriber
from agroweekpy.msg import Odometry

def callback(msg):
    print(f'Distance: {msg.total_distance}')

sub = Subscriber('/odometry', Odometry, callback)

OdometrySubscriber (Convenience Class)

from agroweekpy import OdometrySubscriber

odom = OdometrySubscriber('/odometry')

odom.get_distance()       # Total distance (average of both motors)
odom.get_left_distance()  # Left motor distance
odom.get_right_distance() # Right motor distance
odom.get_odometry()       # Full Odometry message

YawSubscriber (Convenience Class)

from agroweekpy import YawSubscriber

yaw = YawSubscriber('/yaw')

yaw.get_angle()           # Current angle in degrees
yaw.get_angle_radians()   # Current angle in radians
yaw.get_normalized_angle() # Angle in -180 to 180 range
yaw.get_angular_velocity() # Angular velocity (deg/s)
yaw.angle_to(90.0)        # Shortest angle to target

Message Types

MotorCommand

from agroweekpy.msg import MotorCommand

cmd = MotorCommand(left_velocity=0.5, right_velocity=0.5)
cmd.left_velocity   # -1.0 to 1.0
cmd.right_velocity  # -1.0 to 1.0
cmd.timestamp       # Auto-generated

# Convenience methods
cmd.forward(0.5)
cmd.backward(0.5)
cmd.turn_left(0.3)
cmd.turn_right(0.3)
cmd.stop()

Odometry

from agroweekpy.msg import Odometry

odom = Odometry(left_distance=10.5, right_distance=10.3)
odom.left_distance    # Left motor distance
odom.right_distance   # Right motor distance
odom.total_distance   # Average distance
odom.left_velocity    # Current left velocity
odom.right_velocity   # Current right velocity

Yaw

from agroweekpy.msg import Yaw

yaw = Yaw(angle=45.0)
yaw.angle              # Angle in degrees
yaw.radians            # Angle in radians
yaw.normalized_angle   # -180 to 180
yaw.angular_velocity   # deg/s
yaw.angle_to(90.0)     # Shortest turn to target

WebSocket Protocol

Message Format

All messages are JSON with this structure:

{
    "topic": "/motor_cmd",
    "data": {
        "left_velocity": 0.5,
        "right_velocity": 0.5,
        "timestamp": 1706450400.123
    },
    "timestamp": 1706450400.123
}

Topics

Topic Direction Message Type Description
/motor_cmd Client → Game MotorCommand Motor velocity commands
/odometry Game → Client Odometry Motor distances
/yaw Game → Client Yaw Robot orientation

Expected Game Server Messages

Odometry (sent by game):

{
    "topic": "/odometry",
    "data": {
        "left_distance": 10.5,
        "right_distance": 10.3,
        "left_velocity": 0.5,
        "right_velocity": 0.5,
        "timestamp": 1706450400.123
    }
}

Yaw (sent by game):

{
    "topic": "/yaw",
    "data": {
        "angle": 45.0,
        "angular_velocity": 5.0,
        "timestamp": 1706450400.123
    }
}

Configuration

agroweekpy.init_node(
    'my_rover',
    uri='ws://192.168.1.100:8765',  # Game server URI
    anonymous=False,                 # Add timestamp to name
    log_level=logging.INFO,          # Logging level
    reconnect=True,                  # Auto-reconnect
    reconnect_interval=1.0,          # Initial reconnect delay
    max_reconnect_interval=30.0,     # Max reconnect delay
    ping_interval=20.0,              # WebSocket ping interval
)

Examples

See the examples/ directory for complete examples:

  • basic_publisher.py - Simple motor control
  • odometry_listener.py - Reading odometry data
  • yaw_listener.py - Reading orientation data
  • rover_controller.py - Complete rover control example
  • mock_game_server.py - Mock server for testing

Comparison with rospy

rospy agroweekpy Notes
rospy.init_node() agroweekpy.init_node() Similar API
rospy.Publisher() agroweekpy.Publisher() Same pattern
rospy.Subscriber() agroweekpy.Subscriber() Same pattern
rospy.Rate() agroweekpy.Rate() Same pattern
rospy.spin() agroweekpy.spin() Same behavior
rospy.is_shutdown() agroweekpy.is_shutdown() Same behavior
rospy.loginfo() agroweekpy.loginfo() Same API

License

MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agroweekpy-1.0.0.tar.gz (20.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agroweekpy-1.0.0-py3-none-any.whl (24.8 kB view details)

Uploaded Python 3

File details

Details for the file agroweekpy-1.0.0.tar.gz.

File metadata

  • Download URL: agroweekpy-1.0.0.tar.gz
  • Upload date:
  • Size: 20.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.0

File hashes

Hashes for agroweekpy-1.0.0.tar.gz
Algorithm Hash digest
SHA256 42afb3e1491d9824f0ad4928170698e89889d92288802b2d04c5e26f2fcf91ab
MD5 6f3da9f57e384d06b79f4e93fefb9f34
BLAKE2b-256 206517aa66473f1f978f77353e50bf5b579e9ef078208fa033bbb885d5073fd3

See more details on using hashes here.

File details

Details for the file agroweekpy-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: agroweekpy-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 24.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.0

File hashes

Hashes for agroweekpy-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2ef31e3317d0602217acb53ecf9705b40f3592a9ea8332526f3ec0a421f53d4d
MD5 431f6e4055a9ca684814ed8ad1b7bf61
BLAKE2b-256 748ed340b478d36a8e7b0a607a0ef2e59fa1d9a4104383784197f6be751e3150

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page