$darkmode
vtd_vehicle.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Robert Bosch GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * SPDX-License-Identifier: Apache-2.0
17  */
22 #pragma once
23 
24 #include <algorithm> // for transform, min
25 #include <map> // for map<>
26 #include <memory> // for unique_ptr<>, shared_ptr<>
27 #include <string> // for string, to_string
28 #include <thread> // for this_thread
29 
30 #include <cloe/component/object_sensor_functional.hpp> // for ObjectSensorFilter
31 #include <cloe/core.hpp> // for Duration
32 #include <cloe/models.hpp> // for CloeComponent
33 #include <cloe/sync.hpp> // for Sync
34 #include <cloe/utility/inja.hpp> // for inja
35 #include <cloe/utility/osi_transceiver_tcp.hpp> // for OsiTransceiverTcpFactory
36 #include <cloe/utility/tcp_transceiver_config.hpp> // for TcpTransceiverConfiguration
37 #include <cloe/vehicle.hpp> // for Vehicle
38 
39 #include "actuator_component.hpp" // for VtdLatLongActuator
40 #include "omni_sensor_component.hpp" // for VtdOmniSensor
41 #include "osi_sensor_component.hpp" // for VtdOsiSensor
42 #include "rdb_transceiver_tcp.hpp" // for RdbTransceiverTcp, RdbTransceiverTcpFactory
43 #include "scp_messages.hpp" // for scp::{LabelVehicle, SensorConfiguration}
44 #include "scp_transceiver.hpp" // for ScpTransceiver
45 #include "task_control.hpp" // for TaskControl
46 #include "vtd_conf.hpp" // for VtdVehicleConfig
47 #include "vtd_logger.hpp" // for sensors_logger
48 #include "vtd_sensor_components.hpp" // VtdEgoSensor, VtdWorldSensor, ...
49 #include "vtd_sensor_data.hpp" // for VtdSensorData
50 
51 namespace vtd {
52 
57 class VtdVehicle : public cloe::Vehicle {
58  public:
59  virtual ~VtdVehicle() = default;
60  VtdVehicle() = delete;
61 
85  VtdVehicle(uint64_t id, const std::string& name, std::unique_ptr<RdbTransceiverTcp>&& rdb_client,
86  std::shared_ptr<TaskControl> task_control)
87  : Vehicle(id, fmt::format("vtd_vehicle_{}", id))
88  , vtd_name_(name)
89  , id_(id)
90  , task_control_(task_control) {
91  // clang-format off
92  sensor_port_ = rdb_client->tcp_port();
93  vehicle_label_.tethered_to_player = name;
94  vehicle_label_.text = "!";
95  auto sensor = std::make_shared<VtdOmniSensor>(std::move(rdb_client), id);
96  sensors_[DEFAULT_SENSOR_NAME] = sensor;
97  sensor->set_name(name + "_omni_sensor");
98  auto actuator = std::make_shared<VtdLatLongActuator>(task_control, id);
99  ego_control_ = actuator;
100  // Add ego sensor
101  this->new_component(new VtdEgoSensor{id, sensor, task_control},
102  cloe::CloeComponent::GROUNDTRUTH_EGO_SENSOR,
103  cloe::CloeComponent::DEFAULT_EGO_SENSOR);
104 
105  // Add object sensor
106  this->new_component(new VtdWorldSensor{sensor},
107  cloe::CloeComponent::DEFAULT_WORLD_SENSOR);
108 
109  // TODO(ben): Currently, we only send dynamic objects. This is to
110  // compensate for the controllers that are currently using stuff.
111  this->emplace_component(
112  std::make_shared<cloe::ObjectSensorFilter>(
113  this->get<cloe::ObjectSensor>(cloe::CloeComponent::DEFAULT_WORLD_SENSOR),
114  [](const cloe::Object& obj) { return obj.type == cloe::Object::Type::Dynamic; }),
115  cloe::CloeComponent::DEFAULT_WORLD_SENSOR);
116 
117  // Add groundtruth world sensor and emplace it by a static object only version
118  this->new_component(new VtdWorldSensor{task_control},
119  cloe::CloeComponent::GROUNDTRUTH_WORLD_SENSOR);
120 
121  this->emplace_component(
122  std::make_shared<cloe::ObjectSensorFilter>(
123  this->get<cloe::ObjectSensor>(cloe::CloeComponent::GROUNDTRUTH_WORLD_SENSOR),
124  [](const cloe::Object& obj) { return obj.type == cloe::Object::Type::Dynamic; }),
125  cloe::CloeComponent::GROUNDTRUTH_WORLD_SENSOR);
126 
127  // Add lane-boundary sensor
128  this->new_component(new VtdLaneBoundarySensor{sensor},
129  cloe::CloeComponent::GROUNDTRUTH_LANE_SENSOR,
130  cloe::CloeComponent::DEFAULT_LANE_SENSOR);
131 
132  // Add actuator
133  this->add_component(actuator,
134  cloe::CloeComponent::GROUNDTRUTH_LATLONG_ACTUATOR,
135  cloe::CloeComponent::DEFAULT_LATLONG_ACTUATOR);
136  // clang-format on
137  }
138 
142  const std::string& vtd_name() const { return vtd_name_; }
143 
150  LabelConfiguration lbl) {
151  // Send actuations
152  this->ego_control_->step_begin(sync);
153  if (lbl != LabelConfiguration::Off) {
154  this->update_label(tx, lbl);
155  }
156  this->ego_control_->step_end(sync);
157  }
158 
163  cloe::Duration d = s.time();
164  for (auto kv : sensors_) {
165  auto sensor = kv.second;
166  sensor->step(s);
167  d = std::min(sensor->time(), d);
168  }
169  return this->sensors_[DEFAULT_SENSOR_NAME]->time();
170  }
171 
179  void update_label(ScpTransceiver& tx, LabelConfiguration lbl) {
180  if (ego_control_->update_vehicle_label()) {
181  auto level = ego_control_->get_actuation_level();
182  switch (lbl) {
183  case LabelConfiguration::Text:
184  vehicle_label_.text = level.to_loud_cstr();
185  break;
186  case LabelConfiguration::Human:
187  vehicle_label_.text = level.to_human_cstr();
188  break;
189  case LabelConfiguration::Symbol:
190  vehicle_label_.text = level.to_symbol_cstr();
191  break;
192  case LabelConfiguration::Unicode:
193  vehicle_label_.text = level.to_unicode_cstr();
194  break;
195  default:
196  throw std::runtime_error("VtdVehicle: unknown label state");
197  }
198  this->send_label(tx);
199  }
200  }
201 
205  void send_label(ScpTransceiver& tx) const { tx.send(vehicle_label_); }
206 
210  void reset() {
211  for (auto kv : sensors_) {
212  auto sensor = kv.second;
213  sensor->reset();
214  }
215  this->ego_control_->reset();
216  vehicle_label_.text = "!";
217  }
218 
222  friend void to_json(cloe::Json& j, const VtdVehicle& v) {
223  to_json(j, dynamic_cast<const cloe::Vehicle&>(v));
224  j["vtd_name"] = v.vtd_name_;
225  j["sensors"] = v.sensors_;
226  j["actuator"] = v.ego_control_;
227  }
228 
229  void configure_components(const std::map<std::string, VtdComponentConfig>& components) {
230  for (const auto& comp : components) {
231  auto name = comp.first;
232  auto cfg = comp.second;
233  if (cfg.from.empty()) {
234  // Configure actuators.
235  if (cfg.type == "ego_state_model") {
236  auto ego_model = std::make_shared<VtdExternalEgoModel>(task_control_, id_, vtd_name_);
237  // Since no default component of this type was instantiated in the constructor, cfg.override does not apply.
238  this->add_component(ego_model, name);
239  ego_control_ = ego_model;
240  } else {
241  throw cloe::ModelError("unknown actuator component type '{}'", cfg.type);
242  }
243  } else {
244  // Configure sensors.
245  std::shared_ptr<VtdSensorData> sensor;
246  if (cfg.from != "task_control") {
247  if (!sensors_.count(cfg.from)) {
248  throw cloe::ModelError("reference to unknown sensor '{}'", cfg.from);
249  }
250  sensor = this->sensors_.at(cfg.from);
251  }
252  auto new_or_override_component = [this](cloe::Component* c, std::string name,
253  bool override) {
254  if (override) {
255  this->emplace_component(std::shared_ptr<cloe::Component>(c), name);
256  } else {
257  this->add_component(std::shared_ptr<cloe::Component>(c), name);
258  }
259  };
260  if (cfg.type == "lane_sensor") {
261  new_or_override_component(new VtdLaneBoundarySensor{sensor}, name, cfg.override);
262  } else if (cfg.type == "object_sensor") {
263  new_or_override_component(new VtdWorldSensor{sensor}, name, cfg.override);
264  } else if (cfg.type == "driver_request") {
265  new_or_override_component(new VtdDriverRequest{id_, task_control_}, name, cfg.override);
266  } else {
267  throw cloe::ModelError("unknown sensor component type '{}'", cfg.type);
268  }
269  }
270  }
271  }
272 
273  public:
274  const std::string DEFAULT_SENSOR_NAME = "cloe::vtd::sensor::default";
275  std::string vtd_name_{};
276  uint16_t sensor_port_{0};
277  uint16_t id_{0};
278  std::shared_ptr<TaskControl> task_control_{nullptr};
279  std::map<std::string, std::shared_ptr<VtdSensorData>> sensors_;
280  std::shared_ptr<VtdVehicleControl> ego_control_{nullptr};
281  scp::LabelVehicle vehicle_label_;
282 };
283 
294  public:
296  uint16_t initial_port, const std::map<std::string, VtdVehicleConfig>& vehicles)
297  : rdb_factory_(c)
298  , osi_factory_(c)
299  , sensor_host_(std::move(host))
300  , sensor_port_(initial_port)
301  , vehicles_(vehicles) {
302  // store VTD vehicle names from config to track accidental leftovers
303  remaining_vehicles_.resize(vehicles.size());
304  std::transform(vehicles.begin(), vehicles.end(), remaining_vehicles_.begin(),
305  [](auto kv) { return kv.first; });
306  }
307 
308  void set_task_control(std::shared_ptr<TaskControl> tc) { task_control_ = tc; }
309 
310  std::shared_ptr<VtdVehicle> create_or_throw(ScpTransceiver& tx, int id, const std::string& name,
311  cloe::AbortFlag& sig) {
312  assert(task_control_);
313  assert(sensor_port_ != 0);
314  remaining_vehicles_.erase(
315  std::remove(remaining_vehicles_.begin(), remaining_vehicles_.end(), name),
316  remaining_vehicles_.end());
317 
318  // Inform VTD what kind of sensors we want to be configured for our
319  // vehicle.
320  auto port = sensor_port_++;
321  this->send_sensor_configuration(tx, port, id);
322 
323  // Give the OS a chance to let VTD open a port.
324  std::this_thread::sleep_for(cloe::Milliseconds{100});
325 
326  // Connect to it, possibly retrying if necessary.
327  std::unique_ptr<RdbTransceiverTcp> rdb_client{
328  rdb_factory_.create_or_throw(sensor_host_, port, sig)};
329 
330  // Put it all together in form of a vehicle.
331  std::shared_ptr<VtdVehicle> veh =
332  std::make_shared<VtdVehicle>(id, name, std::move(rdb_client), task_control_);
333 
334  // Create and register additional configured sensors
335  if (vehicles_.count(name)) {
336  VtdVehicleConfig vcfg = vehicles_.at(name);
337  for (auto sens : vcfg.sensors) {
338  auto name = sens.first;
339  auto cfg = sens.second;
340  auto port = sensor_port_++;
341  cloe::Json j{
342  {"sensor_id", port}, {"sensor_name", name}, {"sensor_port", port}, {"player_id", id}};
343  send_sensor_configuration(tx, cfg.xml, j);
344  std::this_thread::sleep_for(cloe::Milliseconds(100));
345  switch (cfg.protocol) {
346  case ProtocolConfiguration::Rdb: {
347  sensors_logger()->debug("Opening RDB channel {} for sensor {}", port, name);
348  std::shared_ptr<VtdOmniSensor> omni(
349  new VtdOmniSensor(rdb_factory_.create_or_throw(sensor_host_, port), id));
350  veh->sensors_[name] = omni;
351  break;
352  }
353  case ProtocolConfiguration::Osi: {
354  sensors_logger()->debug("Opening TCP channel {} for OSI sensor {}", port, name);
355  std::shared_ptr<VtdOsiSensor> osi(
356  new VtdOsiSensor(osi_factory_.create_or_throw(sensor_host_, port), id));
357  osi->configure(cfg);
358  veh->sensors_[name] = osi;
359  break;
360  }
361  default: {
362  throw cloe::Error("VtdVehicle: unknown sensor protocol");
363  }
364  }
365  }
366  veh->configure_components(vcfg.components);
367  }
368 
369  return veh;
370  }
371 
372  std::vector<std::string> unregistered_vehicles() { return remaining_vehicles_; }
373 
374  private:
378  void send_sensor_configuration(ScpTransceiver& tx, uint16_t sensor_port, int player_id) const {
380  cfg.port = sensor_port;
381  cfg.player_id = player_id;
382  cfg.sensor_id = sensor_port;
383  tx.send(cfg);
384  }
385 
389  void send_sensor_configuration(ScpTransceiver& tx, const std::string& xml,
390  const cloe::Json& params) const {
391  tx.send(cloe::utility::inja_env().render(xml, params));
392  }
393 
394  private:
395  std::vector<std::string> remaining_vehicles_;
396  std::shared_ptr<TaskControl> task_control_{nullptr};
397  RdbTransceiverTcpFactory rdb_factory_{};
398  cloe::utility::OsiTransceiverTcpFactory osi_factory_{};
399  std::string sensor_host_{"localhost"};
400  uint16_t sensor_port_{0};
401  std::map<std::string, VtdVehicleConfig> vehicles_;
402 };
403 
404 } // namespace vtd
std::atomic_bool AbortFlag
Definition: abort.hpp:40
Definition: component.hpp:143
const std::string & name() const
Definition: entity.hpp:67
Definition: error.hpp:35
Definition: model.hpp:62
Definition: sync.hpp:34
virtual Duration time() const =0
Definition: vehicle.hpp:106
std::unique_ptr< T > create_or_throw(const std::string &host, uint16_t port) const
Definition: tcp_transceiver.hpp:180
Definition: rdb_transceiver_tcp.hpp:94
Definition: scp_transceiver.hpp:81
Definition: vtd_sensor_components.hpp:34
Definition: vtd_sensor_components.hpp:67
Definition: omni_sensor_component.hpp:73
Definition: osi_sensor_component.hpp:47
Definition: vtd_vehicle.hpp:293
Definition: vtd_vehicle.hpp:57
cloe::Duration vtd_step_sensors(const cloe::Sync &s)
Definition: vtd_vehicle.hpp:162
friend void to_json(cloe::Json &j, const VtdVehicle &v)
Definition: vtd_vehicle.hpp:222
void reset()
Definition: vtd_vehicle.hpp:210
void update_label(ScpTransceiver &tx, LabelConfiguration lbl)
Definition: vtd_vehicle.hpp:179
VtdVehicle(uint64_t id, const std::string &name, std::unique_ptr< RdbTransceiverTcp > &&rdb_client, std::shared_ptr< TaskControl > task_control)
Definition: vtd_vehicle.hpp:85
const std::string & vtd_name() const
Definition: vtd_vehicle.hpp:142
void vtd_step_vehicle_control(const cloe::Sync &sync, ScpTransceiver &tx, LabelConfiguration lbl)
Definition: vtd_vehicle.hpp:149
void send_label(ScpTransceiver &tx) const
Definition: vtd_vehicle.hpp:205
Definition: vtd_sensor_components.hpp:53
std::chrono::nanoseconds Duration
Definition: cloe_fwd.hpp:36
Definition: object.hpp:49
Type type
Type of object.
Definition: object.hpp:61
Definition: tcp_transceiver_config.hpp:38
Definition: vtd_conf.hpp:164
std::map< std::string, VtdComponentConfig > components
Definition: vtd_conf.hpp:173
std::map< std::string, VtdSensorConfig > sensors
Definition: vtd_conf.hpp:168
Definition: scp_messages.hpp:64