31 #include <esminiLib.hpp>
38 #define ESMINI_CONTROLLER_TYPE_EXTERNAL 1
40 namespace cloe_esmini {
52 void step(
double dt_sec,
double trg_throttle,
double trg_front_wheel_angle) {
55 SE_SimpleVehicleControlAnalog(model_, dt_sec, trg_throttle, trg_front_wheel_angle);
58 const SE_SimpleVehicleState& get_ego_state() {
59 SE_SimpleVehicleGetState(model_, &ego_state_);
63 [[nodiscard]]
double get_throttle_from_acceleration(
double trg_accel)
const {
64 return std::max(-1.0, std::min(1.0, trg_accel / max_acceleration_abs_));
68 void init_model(uint64_t ego_id) {
70 SE_ScenarioObjectState sc_ego_state;
71 SE_GetObjectState(ego_id, &sc_ego_state);
72 if (sc_ego_state.ctrl_type != ESMINI_CONTROLLER_TYPE_EXTERNAL) {
74 "ESMiniSimpleEgoModel: esminiController must be set to ExternalController in .xosc "
78 if (sc_ego_state.length <= 0.0) {
79 throw cloe::ModelError(
"ESMiniSimpleEgoModel: Unphysical ego length received.");
81 model_ = SE_SimpleVehicleCreate(sc_ego_state.x, sc_ego_state.y, sc_ego_state.h,
82 sc_ego_state.length, sc_ego_state.speed);
84 SE_SimpleVehicleSetMaxAcceleration(model_, max_acceleration_abs_);
85 SE_SimpleVehicleSetMaxDeceleration(model_, max_acceleration_abs_);
86 SE_SimpleVehicleSetEngineBrakeFactor(model_, engine_brake_factor_);
87 SE_SimpleVehicleSteeringRate(model_, steering_rate_);
88 SE_SimpleVehicleSteeringReturnFactor(model_, steering_return_factor_);
90 SE_SimpleVehicleSetMaxSpeed(model_, max_speed_kph_);
91 SE_SimpleVehicleSteeringScale(model_, steering_scale_);
96 const double max_acceleration_abs_{19};
98 const double steering_rate_{8};
100 const double engine_brake_factor_{0.001};
102 const double steering_return_factor_{4.0};
104 const double max_speed_kph_{300.0};
106 const double steering_scale_{0.02};
108 void* model_{
nullptr};
110 SE_SimpleVehicleState ego_state_{0, 0, 0, 0, 0, 0, 0, 0};
121 {DriverModelType::Simple,
"simple"},
122 {DriverModelType::GhostLookAheadTime,
"ghost_time"},
123 {DriverModelType::GhostLookAheadDist,
"ghost_distance"},
127 class ESMiniDriverModel {
129 ESMiniDriverModel(uint64_t ego_id, DriverModelType type) : ego_id_(ego_id), model_type_(type) {}
130 virtual ~ESMiniDriverModel() =
default;
132 void step(
double ego_vel,
double& throttle,
double& steering_angle) {
134 steering_angle = 0.0;
135 SE_RoadInfo road_info;
137 esmini_logger()->info(
"ESMiniDriverModel at {}s", SE_GetSimulationTime());
139 if (SE_ObjectHasGhost(ego_id_) == 1) {
140 SE_ScenarioObjectState ego_state, ghost_state;
141 SE_GetObjectState(ego_id_, &ego_state);
142 SE_GetObjectGhostState(ego_id_, &ghost_state);
143 double ghost_dir_angle = atan2(ghost_state.y - ego_state.y, ghost_state.x - ego_state.x);
144 double delta_ego_dir = remainder(ghost_dir_angle - ego_state.h, 2 * M_PI);
145 if (std::abs(delta_ego_dir) > M_PI_2) {
147 "ESMiniDriverModel: Ego vehicle has passed driver model ghost object. Fix scenario.");
151 "ESMiniDriverModel: Ghost vehicle missing. Refer to test-driver.xosc for an example how "
152 "to set property \"useGhost\".");
155 if (model_type_ == DriverModelType::GhostLookAheadDist) {
156 SE_GetRoadInfoAlongGhostTrail(ego_id_, 5 + 0.75f * ego_vel, &road_info, &target_vel);
157 }
else if (model_type_ == DriverModelType::GhostLookAheadTime) {
158 SE_GetRoadInfoGhostTrailTime(ego_id_, SE_GetSimulationTime() + 0.25f, &road_info,
163 uint16_t lookahead_strategy = 0;
164 SE_GetRoadInfoAtDistance(ego_id_, 5 + 0.75F * ego_vel, &road_info, lookahead_strategy,
true);
165 if (road_info.speed_limit <= 0.0) {
166 throw cloe::ModelError(
"ESMiniDriverModel::Simple: OpenDrive speed limit missing.");
169 double curve_weight = 30.0;
170 target_vel = road_info.speed_limit / (1.0 + curve_weight * std::fabs(road_info.angle));
172 throttle = throttle_weight_ * (target_vel - ego_vel);
173 throttle = std::max(-1.0, std::min(1.0, throttle));
174 steering_angle = road_info.angle;
183 const double throttle_weight_{0.1};
193 ESMiniEgoControl(uint64_t
id) : LatLongActuator(
"esmini/lat_long_actuator"), ego_id_(
id) {
194 vehicle_model_ = std::make_shared<ESMiniSimpleEgoModel>(ego_id_);
196 std::make_shared<ESMiniDriverModel>(ego_id_, DriverModelType::GhostLookAheadDist);
216 double trg_throttle = 0;
217 double trg_steering_angle = 0;
218 get_target_actuation(trg_throttle, trg_steering_angle);
220 vehicle_model_->step(std::chrono::duration<double>(s.
step_width()).count(), trg_throttle,
223 auto ego_state = vehicle_model_->get_ego_state();
225 SE_ReportObjectPosXYH(0, 0.0F, ego_state.x, ego_state.y, ego_state.h);
226 SE_ReportObjectSpeed(0, ego_state.speed);
229 esmini_logger()->info(
"ESMiniEgoControl: vehicle {} new controller state: {}",
id(),
230 level_.to_human_cstr());
238 old_level_.set_none();
239 LatLongActuator::reset();
243 void get_target_actuation(
double& trg_throttle,
double& trg_angle)
const {
244 if (!target_acceleration_ || !target_steering_angle_) {
246 auto ego_state = vehicle_model_->get_ego_state();
247 driver_model_->step(ego_state.speed, trg_throttle, trg_angle);
250 if (target_acceleration_) {
251 trg_throttle = vehicle_model_->get_throttle_from_acceleration(*target_acceleration_);
253 if (target_steering_angle_) {
254 trg_angle = *target_steering_angle_;
261 std::shared_ptr<ESMiniSimpleEgoModel> vehicle_model_{
nullptr};
262 std::shared_ptr<ESMiniDriverModel> driver_model_{
nullptr};
Definition: latlong_actuator.hpp:37
virtual Duration step_width() const =0
Definition: actuation_level.hpp:48
Definition: esmini_ego_control.hpp:191
bool has_level_change()
Definition: esmini_ego_control.hpp:204
void reset() override
Definition: esmini_ego_control.hpp:237
void save_level_state()
Definition: esmini_ego_control.hpp:210
cloe::Duration process(const cloe::Sync &sync) override
Definition: esmini_ego_control.hpp:235
void step(const cloe::Sync &s)
Definition: esmini_ego_control.hpp:215
Definition: esmini_ego_control.hpp:47
std::chrono::nanoseconds Duration
Definition: cloe_fwd.hpp:36
#define ENUM_SERIALIZATION(xType, xMap)
Definition: enum.hpp:51
DriverModelType
Definition: esmini_ego_control.hpp:113
@ Simple
Look ahead to a point on the current lane and steer towards it.
@ GhostLookAheadTime
Use ghost vehicle state in some time ahead to obtain target acceleration and steering.
@ GhostLookAheadDist
Use ghost vehicle state in some distance ahead to obtain target acceleration and steering.