Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding webots dynamic scenario tests #231

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
12 changes: 11 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import os.path
from pathlib import Path
import re
import subprocess
import sys

import pytest
Expand Down Expand Up @@ -52,6 +51,17 @@ def loader(relpath, **kwargs):
return loader


@pytest.fixture
def launchWebots():
DISPLAY = os.environ.get("DISPLAY")
if not DISPLAY:
pytest.skip("DISPLAY env variable not set.")
WEBOTS_ROOT = os.environ.get("WEBOTS_ROOT")
if not WEBOTS_ROOT:
pytest.skip("WEBOTS_ROOT env variable not set.")
return WEBOTS_ROOT


## Command-line options


Expand Down
27 changes: 27 additions & 0 deletions tests/simulators/webots/dynamic/dynamic.scenic
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""
Create a Webots cube in air and have it drop
"""

model scenic.simulators.webots.model

class Floor(Object):
width: 5
length: 5
height: 0.01
position: (0,0,0)
color: [0.785, 0.785, 0.785]

class Block(WebotsObject):
webotsAdhoc: {'physics': True}
shape: BoxShape()
width: 0.2
length: 0.2
height: 0.2
density: 100
color: [1, 0.502, 0]

floor = new Floor
ego = new Block at (0, 0, 0.5) #above floor by 0.5

terminate when ego.z < 0.1
record (ego.z) as BlockPosition
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import os

from controller import Supervisor

import scenic
from scenic.simulators.webots import WebotsSimulator

WEBOTS_RESULT_FILE_PATH = f"{os.path.dirname(__file__)}/../../../results.txt"


def send_results(data):
with open(WEBOTS_RESULT_FILE_PATH, "w") as file:
file.write(data)


supervisor = Supervisor()
simulator = WebotsSimulator(supervisor)

path = supervisor.getCustomData()
print(f"Loading Scenic scenario {path}")
scenario = scenic.scenarioFromFile(path)

scene, _ = scenario.generate()
simulation = simulator.simulate(scene, verbosity=2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a large upper bound to the time limit so if the test fails, it does so gracefully?

block_movements = simulation.result.records["BlockPosition"]
first_block_movement = block_movements[0]
last_block_movement = block_movements[-1]
blocks = [first_block_movement, last_block_movement]
supervisor.simulationQuit(status="finished")
send_results(str(blocks))
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#VRML_SIM R2023a utf8

PROTO ScenicObject [
field SFVec3f translation 0 0 0
field SFRotation rotation 0 0 1 0
field SFString name "solid"
field SFVec3f angularVelocity 0 0 0
field MFString url ""
]
{
Solid {
translation IS translation
rotation IS rotation
name IS name
angularVelocity IS angularVelocity
children [
CadShape {
url IS url
castShadows FALSE
}
]
boundingObject Shape {
geometry Mesh {
url IS url
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#VRML_SIM R2023a utf8

PROTO ScenicObjectWithPhysics [
field SFVec3f translation 0 0 0
field SFRotation rotation 0 0 1 0
field SFString name "solid"
field SFVec3f angularVelocity 0 0 0
field MFString url ""
field SFFloat density 1000 # kg / m^3
]
{
Solid {
translation IS translation
rotation IS rotation
name IS name
angularVelocity IS angularVelocity
children [
CadShape {
url IS url
castShadows FALSE
}
]
boundingObject Shape {
geometry Mesh {
url IS url
}
}
physics Physics {
# density will be set by the simulator
density IS density
mass -1
}
}
}
34 changes: 34 additions & 0 deletions tests/simulators/webots/dynamic/webots_data/worlds/world.wbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#VRML_SIM R2023a utf8

EXTERNPROTO "https://raw.githubusercontent.com/cyberbotics/webots/R2023a/projects/objects/backgrounds/protos/TexturedBackground.proto"
EXTERNPROTO "https://raw.githubusercontent.com/cyberbotics/webots/R2023a/projects/objects/floors/protos/Floor.proto"
IMPORTABLE EXTERNPROTO "../protos/ScenicObject.proto"
IMPORTABLE EXTERNPROTO "../protos/ScenicObjectWithPhysics.proto"

WorldInfo {
gravity 3
basicTimeStep 16
contactProperties [
ContactProperties {
coulombFriction [
0.8
]
}
]
}
Viewpoint {
orientation -0.19729161510865992 0.07408415124219735 0.977541588446517 2.4380019050245862
position 6.683615307234937 -5.5006366813466805 4.16419445995153
}
TexturedBackground {
}
Floor {
name "FLOOR"
size 5 5
}
Robot {
name "Supervisor"
controller "scenic_supervisor"
customData "../../../dynamic.scenic"
supervisor TRUE
}
35 changes: 35 additions & 0 deletions tests/simulators/webots/test_webots.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,42 @@
import os
import subprocess

import pytest

from tests.utils import pickle_test, sampleScene, tryPickling

WEBOTS_RESULTS_FILE_PATH = f"{os.path.dirname(__file__)}/dynamic/results.txt"
WEBOTS_WORLD_FILE_PATH = (
f"{os.path.dirname(__file__)}/dynamic/webots_data/worlds/world.wbt"
)


def receive_results():
with open(WEBOTS_RESULTS_FILE_PATH, "r") as file:
content = file.read()
return content


def cleanup_results():
command = f"rm -f {WEBOTS_RESULTS_FILE_PATH}"
subprocess.run(command, shell=True)


def test_dynamics_scenarios(launchWebots):
WEBOTS_ROOT = launchWebots
cleanup_results()
command = f"bash {WEBOTS_ROOT}/webots --no-rendering --minimize --batch {WEBOTS_WORLD_FILE_PATH}"
subprocess.run(command, shell=True)
data = receive_results()
assert data != None
start_z = float(data.split(",")[1].strip(" )]"))
end_z = float(data.split(",")[3].strip(" )]"))
assert start_z == 0.5
assert start_z > end_z
expected_value = 0.09
tolerance = 0.01
assert end_z == pytest.approx(expected_value, abs=tolerance)


def test_basic(loadLocalScenario):
scenario = loadLocalScenario("basic.scenic")
Expand Down
Loading