Make your own Robot¶
The Gridsim library provides a Robot
class that manages underlying behavior and drawing of robots, making it easy for you to quickly implement your own functionality and algorithms.
In fact, the default Robot
class is an abstract class; you must implement your own Robot
subclass. There are five abstract Robot
methods that you must implement in your own class. (Inputs and outputs are not shown.)
move()
: Step-wise movement of the robot on the gridcomm_criteria()
: Distance-based criteria for whether or not another robot is within communication range of this robot.receive_msg()
: Code that is run when a robot receives a messageinit()
: Code that is run once when the robot is createdloop()
: Code that is run in every step of the simulation
It also includes an optional method you may want to implement in your subclass:
msg_received()
: Code that is run when a robot’s successfully sends a message to another robot.
In general, you will likely want to implement your own robots with an additional two layers of subclasses. This allows you to separate the physical robot platform you are representing from the algorithsm/code you are running on that platform.
First, you create a subclass that represents the physical robot system you are representing, such as a Turtlebot or Kilobot. This implements abstract methods that are properties of the physical system, such as the communication range (comm_criteria()
) and movement restrictions (move()
). This is still an abstract class.
Second, you create a subclass of your new class for implementing specific algorithms or code on your new robot platform. Here you will implement message handling (receive_msg()
and optionally msg_received()
) and onboard code (init()
and loop()
).
Custom robot example¶
Below is an example of the structure described above to create a simple robot that bounces around the arena.
First, we create , a robot with a circular communication radius of 5 grid cells that can move in the cardinal directions to any of four cells surrounding it. This robot is already provided in the library as GridRobot
; you need not re-implement this robot platform if it meets your needs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | from typing import Tuple
from .robot import Robot
# If you are building your own Robot class, you would instead use:
# from gridsim import Robot
class GridRobot(Robot):
STAY = 0
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4
DIRS = [STAY, UP, DOWN, LEFT, RIGHT]
def __init__(self, x: int, y: int, comm_range: float = 5):
"""
Create a robot that moves along the cardinal directions. Optionally, you
can specify a communication range for the robots.
Parameters
----------
x : int
Starting x position (grid cell) of the robot
y : int
Starting y position (grid cell) of the robot
comm_range : float, optional
Communication radius (in grid cells) of the robot, by default 5
"""
# Run all of the initialization for the default Robot class, including
# setting the starting position
super().__init__(x, y)
self._comm_range = comm_range
# Start with the robot stationary
self._move_cmd = GridRobot.STAY
def set_direction(self, dir: int):
"""
Helper function to set the direction the robot will move. Note that this
will persist (the robot will keep moving) until the direction is
changed.
Parameters
----------
dir : int
Direction to move, one of UP, DOWN, LEFT, RIGHT, or STAY
Raises
------
ValueError
If given direction is not one of UP, DOWN, LEFT, RIGHT, or STAY
"""
if dir in GridRobot.DIRS:
self._move_cmd = dir
else:
raise ValueError('Invalid movement direction "{}"'.format(dir))
def move(self) -> Tuple[int, int]:
"""
Determine the cell the Robot will move to, based on the direction set in
by :meth:`~gridsim.grid_robot.GridRobot.set_motors`.
Returns
-------
Tuple[int, int]
(x,y) grid cell the robot will move to, if possible/allowed
"""
x, y = self.get_pos()
if self._move_cmd == GridRobot.UP:
y -= 1
elif self._move_cmd == GridRobot.DOWN:
y += 1
elif self._move_cmd == GridRobot.RIGHT:
x += 1
elif self._move_cmd == GridRobot.LEFT:
x -= 1
# else STAY, which keeps current position
return x, y
def comm_criteria(self, dist: int) -> bool:
"""
Robots can communicate if their Euclidean distance is <= the radius
specified at initialization (by default, 5 cells)
Parameters
----------
dist : int
Euclidean distance of the other robot with which to communicate
Returns
-------
bool
Whether distance is <= the communication radius
"""
return dist <= self._comm_range
|
With our robot platform in place, we can now implement a Robot that implements whatever code we want the robot to run. In this case, it’s a simple robot that chooses a random movement every 10 ticks and changes color when it first communicates with other robots.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import random
from gridsim.grid_robot import GridRobot
import gridsim as gs
class RandomRobot(GridRobot):
# Change direction every 10 ticks
DIR_DURATION = 10
def init(self):
self.set_color(255, 0, 0)
self._msg_sent = False
# Next tick when Robot will change direction
self._next_dir_change = self.get_tick()
def receive_msg(self, msg: gs.Message, dist: float):
# This robot got a message from another robot
self._msg_sent = True
def loop(self):
# Change direction every DIR_DURATION ticks
tick = self.get_tick()
if tick >= self._next_dir_change:
new_dir = random.choice(GridRobot.DIRS)
self.set_direction(new_dir)
self._next_dir_change = tick + RandomRobot.DIR_DURATION
# Broadcast a test message to any robots nearby
msg = gs.Message(self.id, {'test': 'hello'})
self.set_tx_message(msg)
# Change color depending on whether messages have been sent or received
# Robot will be white when it has successfully sent & received a message
green = 255 * self._msg_sent
self.set_color(255, green, 0)
|
Notice that the abstraction layers mean that you have to write very little additional code to implement a new algorithm for your robot.