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
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,41 @@ bool OSCEnvironment::IsRoadConditionSet() const
return roadcondition_.has_value();
}

bool OSCEnvironment::IsWetnessSet() const
{
return IsRoadConditionSet() && roadcondition_->wetness.has_value();
}

WetnessType OSCEnvironment::GetWetness() const
{
return roadcondition_->wetness.value();
}

double OSCEnvironment::GetWaterFilmHeight() const
{
if (!IsWetnessSet())
{
return OSCWetnessDryWaterFilm; // default to dry road
}

switch (GetWetness())
{
case WetnessType::DRY:
return OSCWetnessDryWaterFilm;
case WetnessType::MOIST:
return OSCWetnessMoistWaterFilm;
case WetnessType::WETWITHPUDDLES:
return OSCWetnessWetWithPuddlesWaterFilm;
case WetnessType::LOWFLOODED:
return OSCWetnessLowFloodedWaterFilm;
case WetnessType::HIGHFLOODED:
return OSCWetnessHighFloodedWaterFilm;
default:
LOG_WARN("Unknown wetness type, setting water film height to dry road");
return OSCWetnessDryWaterFilm;
}
}

void OSCEnvironment::UpdateEnvironment(const OSCEnvironment& new_environment)
{
if (new_environment.IsAtmosphericPressureSet())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ namespace scenarioengine
double const OSCSunIntensityMax = 100000.0; // lux
double const OSCSunIntensityMin = 0.0; // lux

// Water film height representing each OpenSCENARIO wetness level, reported as OSI lane road condition surface_water_film
double const OSCWetnessDryWaterFilm = 0.0; // mm
double const OSCWetnessMoistWaterFilm = 0.1; // mm
double const OSCWetnessWetWithPuddlesWaterFilm = 1.0; // mm
double const OSCWetnessLowFloodedWaterFilm = 10.0; // mm
double const OSCWetnessHighFloodedWaterFilm = 50.0; // mm

/*
Class PrecipitationType
Represents the different types of precipitations
Expand Down Expand Up @@ -61,7 +68,7 @@ namespace scenarioengine
enum class WetnessType
{
DRY,
MOSIT,
MOIST,
WETWITHPUDDLES,
LOWFLOODED,
HIGHFLOODED
Expand Down Expand Up @@ -142,7 +149,7 @@ namespace scenarioengine
Represents the state of the wind

frictionscalefactor double the friction scale factor
wetness wetness the wetness of the road (optional) NOT IMPLEMENTED YET
wetness wetness the wetness of the road (optional)
properties Properties additional properties of the RoadCondition (optional) NOT IMPLEMENTED YET

*/
Expand Down Expand Up @@ -213,6 +220,9 @@ namespace scenarioengine
void SetRoadCondition(const double friction);
RoadCondition GetRoadCondition() const;
bool IsRoadConditionSet() const;
bool IsWetnessSet() const;
WetnessType GetWetness() const;
double GetWaterFilmHeight() const; // mm, derived from the wetness level

void UpdateEnvironment(const OSCEnvironment& new_environment);
bool IsEnvironment() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2782,10 +2782,13 @@ int OSIReporter::UpdateOSIRoadLane()
source_reference->add_identifier(t_road_s);
source_reference->add_identifier(t_lane_id);

// Water film height defaults to dry road, updated from the OpenSCENARIO RoadCondition wetness
// in UpdateEnvironmentRoadCondition()
osi_lane->mutable_classification()->mutable_road_condition()->set_surface_water_film(OSCWetnessDryWaterFilm);

// STILL TO DO:
double temp = 0;
osi_lane->mutable_classification()->mutable_road_condition()->set_surface_temperature(temp);
osi_lane->mutable_classification()->mutable_road_condition()->set_surface_water_film(temp);
osi_lane->mutable_classification()->mutable_road_condition()->set_surface_freezing_point(temp);
osi_lane->mutable_classification()->mutable_road_condition()->set_surface_ice(temp);
osi_lane->mutable_classification()->mutable_road_condition()->set_surface_roughness(temp);
Expand Down Expand Up @@ -3690,7 +3693,29 @@ void OSIReporter::UpdateEnvironment(const OSCEnvironment &environment)
{
UpdateEnvironmentTimeOfDay(environment);
}
if (environment.IsRoadConditionSet())
{
UpdateEnvironmentRoadCondition(environment);
}
}
}

void OSIReporter::UpdateEnvironmentRoadCondition(const OSCEnvironment &environment)
{
// water film height is derived from the wetness of the road condition, dry road if no wetness given
const double water_film = environment.GetWaterFilmHeight();
if (surface_water_film_.has_value() && water_film == surface_water_film_.value())
{
return; // no change, avoid looping over all lanes
}

// OpenSCENARIO defines the wetness globally, while OSI defines the road condition per lane.
// Hence apply the same water film height to all lanes.
for (int i = 0; i < obj_osi_internal.static_gt->lane_size(); i++)
{
obj_osi_internal.static_gt->mutable_lane(i)->mutable_classification()->mutable_road_condition()->set_surface_water_film(water_film);
}
surface_water_film_ = water_film;
}

void OSIReporter::UpdateEnvironmentWeather(const OSCEnvironment &environment)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ class OSIReporter
*/
void UpdateEnvironmentPrecipitation(const double precipitation_intensity);

/**
Fills the road condition of the lanes
*/
void UpdateEnvironmentRoadCondition(const OSCEnvironment& environment);

std::vector<TrafficCommandStateChange> traffic_command_state_changes_;

void RegisterTrafficCommandStateChange(OSCPrivateAction* action, StoryBoardElement::State state, StoryBoardElement::Transition transition)
Expand Down Expand Up @@ -298,6 +303,7 @@ class OSIReporter
OSIStaticReportMode static_update_mode_ = OSIStaticReportMode::DEFAULT;
std::vector<std::pair<int, double>> osi_crop_ = {}; // id, radius
std::optional<int64_t> environment_timestamp_offset_; // Offset to apply to environment timestamp, in seconds
std::optional<double> surface_water_film_; // water film height currently applied to the OSI lanes, in mm
std::vector<uint8_t> has_lightstate_action_ = {};
google::protobuf::io::GzipOutputStream::Options options_;
struct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5562,6 +5562,29 @@ static void SelectCloudState(scenarioengine::CloudState &state, const std::strin
}
}

static bool SelectWetness(scenarioengine::WetnessType &wetness, const std::string &wetnessStr)
{
// Helper function for parseOSCEnvironment
using scenarioengine::WetnessType;
std::map<std::string, WetnessType> wetnessMap{
{"dry", WetnessType::DRY},
{"moist", WetnessType::MOIST},
{"wetWithPuddles", WetnessType::WETWITHPUDDLES},
{"lowFlooded", WetnessType::LOWFLOODED},
{"highFlooded", WetnessType::HIGHFLOODED},
};

auto it = wetnessMap.find(wetnessStr);
if (it == wetnessMap.end())
{
LOG_WARN("Not valid wetness name:{}, ignoring it", wetnessStr);
return false;
}

wetness = it->second;
return true;
}

void ScenarioReader::parseOSCEnvironment(const pugi::xml_node &xml_node, OSCEnvironment &env)
{
for (pugi::xml_node envChild : xml_node.children())
Expand Down Expand Up @@ -5754,7 +5777,18 @@ void ScenarioReader::parseOSCEnvironment(const pugi::xml_node &xml_node, OSCEnvi
LOG_WARN("Ignorning {} in Envirnoment, mandatory attribute frictionScaleFactor missing", envChildName);
continue;
}
env.SetRoadCondition(std::stod(friction));

std::optional<scenarioengine::WetnessType> wetness;
if (const auto &val = parameters.ReadAttribute(envChild, "wetness"); !val.empty())
{
scenarioengine::WetnessType wetnessType;
if (SelectWetness(wetnessType, val))
{
wetness = wetnessType;
}
}

env.SetRoadCondition(RoadCondition{std::stod(friction), wetness, std::nullopt});
}
else
{
Expand Down
39 changes: 39 additions & 0 deletions EnvironmentSimulator/Unittest/ScenarioEngineDll_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3959,6 +3959,45 @@ TEST(EnvironmentTest, OSIFrictionScaleFactor)
SE_Close();
}

// Check that the OpenSCENARIO RoadCondition wetness is reported as water film height of all OSI lanes
TEST(EnvironmentTest, OSISurfaceWaterFilm)
{
std::string scenario_file = "../../../EnvironmentSimulator/Unittest/xosc/environment_test.xosc";
const osi3::GroundTruth* osi_gt;

ASSERT_EQ(SE_Init(scenario_file.c_str(), 0, 0, 0, 0), 0);

// report the static ground truth, including the lanes, at every frame
SE_SetOSIStaticReportMode(SE_OSIStaticReportMode::API);

osi_gt = reinterpret_cast<const osi3::GroundTruth*>(SE_GetOSIGroundTruthRaw());

auto expect_water_film_of_all_lanes = [&](double water_film)
{
ASSERT_GT(osi_gt->lane_size(), 0);
for (const auto& lane : osi_gt->lane())
{
EXPECT_TRUE(lane.classification().has_road_condition());
EXPECT_NEAR(lane.classification().road_condition().surface_water_film(), water_film, 1E-3);
}
};

// no wetness set yet, dry road
expect_water_film_of_all_lanes(0.0);

// the environment actions are reported in the OSI data one frame after being triggered
SE_StepDT(1.0); // environment action with wetness "wetWithPuddles" triggered
SE_StepDT(1.0); // environment action with wetness "highFlooded" triggered

expect_water_film_of_all_lanes(1.0);

SE_StepDT(0.1);

expect_water_film_of_all_lanes(50.0);

SE_Close();
}

#endif // _USE_OSI

TEST(ParameterTest, GetTypedParameterValues)
Expand Down
66 changes: 66 additions & 0 deletions EnvironmentSimulator/Unittest/ScenarioEngine_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5920,6 +5920,7 @@ TEST(EnvironmentTest, Parsing)
// Road condition
pugi::xml_node roadCondNode = envNode.append_child("RoadCondition");
roadCondNode.append_attribute("frictionScaleFactor").set_value(0.5);
roadCondNode.append_attribute("wetness").set_value("wetWithPuddles");

// Test using ScenarioReader
Entities entities;
Expand Down Expand Up @@ -5969,6 +5970,71 @@ TEST(EnvironmentTest, Parsing)

EXPECT_NEAR(oscEnv.GetRoadCondition().friction_scale_factor, roadCondNode.attribute("frictionScaleFactor").as_double(), 1e-5);

EXPECT_TRUE(oscEnv.IsWetnessSet());
EXPECT_EQ(oscEnv.GetWetness(), scenarioengine::WetnessType::WETWITHPUDDLES);
EXPECT_NEAR(oscEnv.GetWaterFilmHeight(), scenarioengine::OSCWetnessWetWithPuddlesWaterFilm, 1e-5);

delete globalAct;
}

TEST(EnvironmentTest, Wetness)
{
// Set up mock xml_node
pugi::xml_document doc;
pugi::xml_node actionNode = doc.append_child("Action");
pugi::xml_node envActionNode = actionNode.append_child("EnvironmentAction");
pugi::xml_node envNode = envActionNode.append_child("Environment");
pugi::xml_node roadCondNode = envNode.append_child("RoadCondition");
roadCondNode.append_attribute("frictionScaleFactor").set_value(1.0);
pugi::xml_attribute wetnessAttr = roadCondNode.append_attribute("wetness");

Entities entities;
Catalogs catalogs;
OSCEnvironment environment;
ScenarioReader reader(&entities, &catalogs, &environment);

// wetness level of OpenSCENARIO mapped to water film height in mm, as reported in OSI lane road condition
const std::vector<std::tuple<std::string, scenarioengine::WetnessType, double>> wetness_levels = {
{"dry", scenarioengine::WetnessType::DRY, scenarioengine::OSCWetnessDryWaterFilm},
{"moist", scenarioengine::WetnessType::MOIST, scenarioengine::OSCWetnessMoistWaterFilm},
{"wetWithPuddles", scenarioengine::WetnessType::WETWITHPUDDLES, scenarioengine::OSCWetnessWetWithPuddlesWaterFilm},
{"lowFlooded", scenarioengine::WetnessType::LOWFLOODED, scenarioengine::OSCWetnessLowFloodedWaterFilm},
{"highFlooded", scenarioengine::WetnessType::HIGHFLOODED, scenarioengine::OSCWetnessHighFloodedWaterFilm}};

for (const auto& [wetness_str, wetness_type, water_film] : wetness_levels)
{
wetnessAttr.set_value(wetness_str.c_str());

OSCGlobalAction* globalAct = reader.parseOSCGlobalAction(actionNode, nullptr);
EnvironmentAction* envAct = static_cast<EnvironmentAction*>(globalAct);
OSCEnvironment oscEnv = envAct->new_environment_;

EXPECT_TRUE(oscEnv.IsWetnessSet());
EXPECT_EQ(oscEnv.GetWetness(), wetness_type);
EXPECT_NEAR(oscEnv.GetWaterFilmHeight(), water_film, 1e-5);

delete globalAct;
}

// no wetness given, expect dry road
roadCondNode.remove_attribute(wetnessAttr);
OSCGlobalAction* globalAct = reader.parseOSCGlobalAction(actionNode, nullptr);
EnvironmentAction* envAct = static_cast<EnvironmentAction*>(globalAct);
OSCEnvironment oscEnv = envAct->new_environment_;

EXPECT_TRUE(oscEnv.IsRoadConditionSet());
EXPECT_FALSE(oscEnv.IsWetnessSet());
EXPECT_NEAR(oscEnv.GetWaterFilmHeight(), scenarioengine::OSCWetnessDryWaterFilm, 1e-5);
delete globalAct;

// invalid wetness, expect it to be ignored
roadCondNode.append_attribute("wetness").set_value("verySoaked");
globalAct = reader.parseOSCGlobalAction(actionNode, nullptr);
envAct = static_cast<EnvironmentAction*>(globalAct);
oscEnv = envAct->new_environment_;

EXPECT_TRUE(oscEnv.IsRoadConditionSet());
EXPECT_FALSE(oscEnv.IsWetnessSet());
delete globalAct;
}

Expand Down
3 changes: 2 additions & 1 deletion EnvironmentSimulator/Unittest/xosc/environment_test.xosc
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
<Precipitation precipitationType="snow" precipitationIntensity="10.0"/>
<Wind direction="3.1415" speed="10"/>
</Weather>
<RoadCondition frictionScaleFactor="0.9"/>
<RoadCondition frictionScaleFactor="0.9" wetness="wetWithPuddles"/>
</Environment>
</EnvironmentAction>
</GlobalAction>
Expand All @@ -91,6 +91,7 @@
<EnvironmentAction>
<Environment name="weather2">
<Weather fractionalCloudCover="oneOktas"/>
<RoadCondition frictionScaleFactor="0.9" wetness="highFlooded"/>
</Environment>
</EnvironmentAction>
</GlobalAction>
Expand Down
24 changes: 23 additions & 1 deletion docs/user_guide/scenario-features.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,7 @@ You can define the `EnvironmentAction`, which is a `GlobalAction` directly withi
<Precipitation precipitationType="snow" precipitationIntensity="10.0"/>
<Wind direction="3.1415" speed="10"/>
</Weather>
<RoadCondition frictionScaleFactor="0.9"/>
<RoadCondition frictionScaleFactor="0.9" wetness="wetWithPuddles"/>
</Environment>
</EnvironmentAction>
</GlobalAction>
Expand All @@ -1050,6 +1050,28 @@ video::-mQUJU1rR2M[youtube,width=854,height=480,opts="autoplay,nocontrols,loop"]

Note that vehicle headlights are currently not considered in the viewer.

==== Road condition

The `RoadCondition` element's `frictionScaleFactor` scales the friction of the https://publications.pages.asam.net/standards/ASAM_OpenDRIVE/ASAM_OpenDRIVE_Specification/latest/specification/11_lanes/11_07_lane_properties.html#sec-8345bf25-d584-4a5b-8fa7-e15c920ab219[OpenDRIVE lane material], see link:scenario-features.html#_friction[Friction].

The optional https://publications.pages.asam.net/standards/ASAM_OpenSCENARIO/ASAM_OpenSCENARIO_XML/latest/generated/content/Wetness.html[`wetness`] attribute is reported as water film height in the https://opensimulationinterface.github.io/osi-antora-generator/asamosi/latest/gen/structosi3_1_1Lane_1_1Classification_1_1RoadCondition.html[OSI lane road condition] (`surface_water_film`), useful e.g. for road spray simulation in sensor models. While the OpenSCENARIO wetness is global, the OSI road condition is defined per lane. Hence the same value is applied to all lanes.

The wetness levels are mapped to the following water film heights:

[cols="1,1", stripes=even]
|===
|OpenSCENARIO `wetness`|OSI `surface_water_film` [mm]
|`dry`|0.0
|`moist`|0.1
|`wetWithPuddles`|1.0
|`lowFlooded`|10.0
|`highFlooded`|50.0
|===

If no `wetness` is given, the water film height of all lanes is reported as `0.0` mm, i.e. dry road.

Since the lanes are part of the static OSI ground truth, which by default is reported only in the first frame, a wetness change during the scenario is reflected in the OSI data only when the static ground truth is reported continuously. See option `osi_static_reporting` in link:command-reference.html#_esmini[esmini command reference] or the esminiLib function `SE_SetOSIStaticReportMode()`.

==== Visual elements affecting the viewer

Although all the environment conditions are reported in the OSI data, only some are visualized. Currently, as of v2.49.0, all but `precipitation`, `wind` and `domeImage` are visualized in some way, described below.
Expand Down
4 changes: 2 additions & 2 deletions osc_coverage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ OpenSCENARIO
Environment Yes
DomeImage (1.2) No
Weather Yes (with limited visualization)
RoadCondition Yes (frictionScaleFactor only)
RoadCondition Yes (frictionScaleFactor and wetness)
Entity Yes
AddEntityAction Yes
DeleteEntityAction Yes
Expand Down Expand Up @@ -353,7 +353,7 @@ Enumerations
VehicleCategory Yes
VehicleComponentType (1.2) No
VehicleLightType (1.2) No
Wetness (1.2) No
Wetness (1.2) Yes (reported as OSI lane surface_water_film)

Extensions:

Expand Down