Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/scenic/simulators/template_interface/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Template Scenic Interface

This interface demonstrates an example template for lower-level implementation of each part of the
Scenic interface. In each of the file, `actions.py, simulator.py, model.scenic, behaviors.scenic`, we describe
what should be done to implement each class and function as well as providing simple example code to illustrate
what the function/class should contain in the docstrings. The Scenic docs has the official description for the
components of the interface, and we hope this template serves as a useful complement.
A good place to start is by examining the `simulator.py` file.
Empty file.
157 changes: 157 additions & 0 deletions src/scenic/simulators/template_interface/actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
"""
Introduction to Scenic Actions


This file, actions.py, is where you should define all
your Scenic Actions that are to be carried out with the
'take <Action>' syntax.

Each Action should be a class inheriting from
the Action class from scenic.core.simulators
"""

from scenic.core.simulators import * # imports the Action superclass


class ExampleAction1(Action):
"""
Each Action has two methods you need to implement,
__init__() and the applyTo(). We will see how to implement
them below
"""

def __init__(self):
"""
__init__ can have any arguments beside based on the need of your actions

For instance, you can have

def __init__(self, x, y, z)

as the funciton signature, and when taking the Action in your Scenic program,
you would write:

take ExampleAction1(x, y, z)

You should not execute or send the command
for the Action in __init__. That is the applyTo method's job.

Other than that, there is no requirement as to what to do in __init__. You can
fill in the code according to your needs
"""

pass


def applyTo(self, obj, sim):
"""
Contrary to __init__(), applyTo()'s signature is fixed
to applyTo(self, obj, sim). You should not change this.

Args:
Object obj: The Scenic object that takes the action
scenic.core.simulator.Simulation sim: the Simulation instance you implemented in simulator.py

applyTo is generally where you send the command to the simulator to execute an action

You can choose to let it return anything or None based on your needs. However,
remember that your implementation for the step() and executeAction() in simulator.py
should account for this

"""
pass



"""
Let's see an example Action
"""

class MoveAction(Action):
"""
This Action sends to command to move the agent
to an (x, y, z) coordinate
"""

def __init__(self, x=0, y=0, z=0):
self.target_coord = [x, y, z]

def applyTo(self, obj, sim):

agent_id = obj.agent_id

target_reachable = sim.YourSimulatorAPI.target_reachable(self.target_coord)

if target_reachable:
YourSimulatorAPI.move_agent(agent_id=agent_id, target_coordinate=self.target_coord)



"""
Here's an example where applyTo returns a function that executes a command
"""

class MoveAction(Action):
"""
This Action sends to command to move the agent
to an (x, y, z) coordinate
"""

def __init__(self, x=0, y=0, z=0):
self.target_coord = [x, y, z]

def applyTo(self, obj, sim):
agent_id = obj.agent_id

target_reachable = sim.YourSimulatorAPI.target_reachable(self.target_coord)

if target_reachable:
f = lambda: sim.YourSimulatorAPI.move_agent(agent_id=agent_id, target_coordinate=self.target_coord)

return f



"""
An example for a BAD Action:
You should NOT have any code in Actions that blocks code execution

This prevents Scenic from simultaneously (at least approximately simulatenaously) manage
all the agents, objects, and simulation world.
"""

class BadAction(Action):
"""
This Action sends to command to move the agent
to an (x, y, z) coordinate and waits for it to reach its goal
"""

def __init__(self, x=0, y=0, z=0):
self.target_coord = [x, y, z]

def applyTo(self, obj, sim):
"""
Here we send a command to move an agent and then wait until
the agent reaches its goal using the final while loop.

This will cause problems as Scenic is prevented from
managing and sending the action commands for other agents.
Scenic would also not be able to get information of the simulation world
during the time when the agent is moving.


This kind of blocking code can be common in robot API's, where
methods that commands the robot often conatins code that waits
until the robot has finished executing its commands.

We will see a way around this problem in behaviors.scenic
"""

agent_id = obj.agent_id

YourSimulatorAPI.move_agent(agent_id=agent_id, target_coordinate=self.target_coord)

while not YourSimulatorAPI.agent_reached_goal(agent_id): # this code blocks Scenic's execution
continue


55 changes: 55 additions & 0 deletions src/scenic/simulators/template_interface/behaviors.scenic
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""
Introduction to Behaviors

Behaviors allow us to specify at a high level how
an agents should act. It can be made up of other behaviors
or Actions. While the Scenic documentation introduces you to
the basics of beahivors, we re going to see here some more specific
examples of using behaviors when you write your own Scenic interface.
"""


"""
Example 1: Using behaviors to get around
having Action code that blocks background
Scenic execution (mentioned in actions.py)
"""

behavior MoveToPosition(x, y, z):
"""
If you are in the robotics domain, chances are you have
code in your robot API that looks like this:

def move_to_position(self, x, y, z):
self.set_robot_goal_point(x, y, z)

while <robot has not reached goal>:
continue

As mentioned in actions.py, since the while loop above
blocks the backgournd Scenic code execution, we cannot have it
in a Scenic Action. However, we can get around it with the code
below:
"""

take SetRobotGoalPointAction(x, y, z) # This Action calls set_robot_goal_point, but does not have the while loop

while <robot has not reached goal>: # This while loop waits until the robot reaches its goal point
wait

"""
Recall that the Scenic 'wait' tells Scenic that the agent is not taking
any actions for this timestep. Seeing this, Scenic will move on to manage
other agents and objects while your robot marches its way to the goal.
So when you write your Scenic programs, rather than simply taking the
Action that tells the robot to move to a goal point, you would just
call this behavior instead.

You can also put the while loop above in its own behavior and call that
for all your robot's Actions like shown below:
"""
take SetRobotGoalPointAction(x, y, z) # This Action calls set_robot_goal_point
do WaitUntilFinishBehavior()



92 changes: 92 additions & 0 deletions src/scenic/simulators/template_interface/model.scenic
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""
Introduction to Models

In this file, you will define all the Scenic
classes that will represent your object and agent models

"""


"""
By default, all classes inherit the Scenic Object class
See the Scenic docs for more details

You can add any attribute/methods you need to a Scenic class.
"""

class Agent:
"""
Instance variables are assigned with the colon
like in Python dataclasses, whereas class variables
are assigned with '='
"""
name: "agent"
agent_controller: None
class_name = 'agent'

"""
You can add distributions to instance and class attributes
For class attributes, the value will be the same for all
instances of the class within the same scene.
"""
position: (Range(0, 1), Range(0, 10), Range(1, 2))
robot_language = Uniform('English', 'Japanese', 'Hungarian')


"""
You can add in methods just like in Python classes
"""
def distanceToClosest(self, object_class):
objects = simulation().objects
minDist = float('inf')
for obj in objects:
if not isinstance(obj, object_class):
continue
d = distance from self to obj
if 0 < d < minDist:
minDist = d
return minDist

"""
Decorators such as property, getter, and setter etc. work as well
"""
@property
def PositionNorm(self):
return self.position.norm()

"""
Inheritance works the same way as in Python
"""
class Robot(Agent):
name: "robot"
agent_controller: YourRobotAPI.robot_controller
class_name = "robot"


"""
Mixin's are also supported
"""
class RobotArm(Robot):
name: "robot_arm"
agent_controller: YourRobotAPI.robot_controller
class_name = "robot_arm"

@property
def gripper_position(self):
return YourRobotAPI.gripper_pos()


class RobotMobileBase(Robot):
name: "robot_base"
agent_controller: YourRobotAPI.robot_controller
class_name = "robot_base"

@property
def base_position(self):
return YourRobotAPI.base_pos()

class MobileManipulator(RobotArm, RobotMobileBase):
name: "mobile_manipulator"
agent_controller: YourRobotAPI.robot_controller
class_name = "mobile_manipulator"

Loading