19#include "google/protobuf/util/json_util.h"
33using apollo::common::util::ContainsKey;
52using Json = nlohmann::json;
53using google::protobuf::util::JsonStringToMessage;
54using google::protobuf::util::MessageToJsonString;
62 : sim_world_service_(map_service, routing_from_file),
63 map_service_(map_service),
64 websocket_(websocket),
66 camera_ws_(camera_ws),
67 plugin_ws_(plugin_ws),
68 perception_camera_updater_(perception_camera_updater),
69 plugin_manager_(plugin_manager),
71 RegisterMessageHandlers();
74void SimulationWorldUpdater::RegisterMessageHandlers() {
79 response[
"type"] =
"SimControlStatus";
80 response[
"enabled"] = SimControlManager::Instance()->IsEnabled();
81 websocket_->
SendData(conn, response.dump());
87 auto iter = json.find(
"elements");
88 if (iter != json.end()) {
89 MapElementIds map_element_ids;
90 if (JsonStringToMessage(iter->dump(), &map_element_ids).ok()) {
93 std::string retrieved_map_string;
94 retrieved.SerializeToString(&retrieved_map_string);
98 AERROR <<
"Failed to parse MapElementIds from json";
104 "RetrieveRelativeMapData",
108 boost::shared_lock<boost::shared_mutex> reader_lock(mutex_);
109 to_send = relative_map_string_;
118 auto navigation_info = std::make_shared<NavigationInfo>();
119 if (navigation_info->ParseFromString(data)) {
122 AERROR <<
"Failed to parse navigation info from string. String size: "
128 "RetrieveMapElementIdsByRadius",
130 auto radius = json.find(
"radius");
131 if (radius == json.end()) {
132 AERROR <<
"Cannot retrieve map elements with unknown radius.";
136 if (!radius->is_number()) {
137 AERROR <<
"Expect radius with type 'number', but was "
138 << radius->type_name();
143 response[
"type"] =
"MapElementIds";
144 response[
"mapRadius"] = *radius;
148 std::string elementIds;
149 MessageToJsonString(ids, &elementIds);
150 response[
"mapElementIds"] = Json::parse(elementIds);
152 websocket_->
SendData(conn, response.dump());
158 Json response = CheckRoutingPoint(json);
159 response[
"type"] =
"RoutingPointCheckResult";
160 websocket_->
SendData(conn, response.dump());
166 auto point = json[
"point"];
167 if (!SimControlManager::Instance()->IsEnabled()) {
168 AWARN <<
"Set start point need start sim_control.";
170 if (!ContainsKey(point,
"heading")) {
171 AWARN <<
"Set start point need set heading.";
174 SimControlManager::Instance()->ReSetPoinstion(point[
"x"], point[
"y"],
178 if (isProcessRunning(
"planning.dag")) {
179 auto action_command = std::make_shared<ActionCommand>();
180 action_command->set_command_id(++command_id_);
181 action_command->set_command(ActionCommandType::CLEAR_PLANNING);
188 "SendRoutingRequest",
190 auto lane_follow_command = std::make_shared<LaneFollowCommand>();
192 ConstructLaneFollowCommand(json, lane_follow_command.get());
196 "Lane follow command sent.");
200 "Failed to send a Lane follow command.");
205 "SendDefaultCycleRoutingRequest",
207 auto task = std::make_shared<Task>();
208 auto *cycle_routing_task = task->mutable_cycle_routing_task();
209 auto *lane_follow_command =
210 cycle_routing_task->mutable_lane_follow_command();
211 if (!ContainsKey(json,
"cycleNumber") ||
212 !json.find(
"cycleNumber")->is_number()) {
214 <<
"Failed to prepare a cycle lane follow command: Invalid cycle "
218 bool succeed = ConstructLaneFollowCommand(json, lane_follow_command);
220 cycle_routing_task->set_cycle_num(
221 static_cast<int>(json[
"cycleNumber"]));
222 task->set_task_name(
"cycle_routing_task");
225 AINFO <<
"The task is : " << task->DebugString();
228 "Default cycle lane follow command sent.");
232 "Failed to send a default cycle lane follow command.");
267 "SendParkingRoutingRequest",
269 auto valet_parking_command = std::make_shared<ValetParkingCommand>();
271 ConstructValetParkingCommand(json, valet_parking_command.get());
279 "Failed to send a Valet parking command.");
284 "RequestSimulationWorld",
288 <<
"Not sending simulation world as the data is not ready!";
292 bool enable_pnc_monitor =
false;
293 auto planning = json.find(
"planning");
295 enable_pnc_monitor = json[
"planning"];
301 boost::shared_lock<boost::shared_mutex> reader_lock(mutex_);
302 to_send = enable_pnc_monitor ? simulation_world_with_planning_data_
305 if (FLAGS_enable_update_size_check && !enable_pnc_monitor &&
306 to_send.size() > FLAGS_max_update_size) {
307 AWARN <<
"update size is too big:" << to_send.size();
317 response[
"type"] =
"RoutePath";
318 websocket_->
SendData(conn, response.dump());
322 "GetDefaultEndPoint",
325 response[
"type"] =
"DefaultEndPoint";
327 Json poi_list = Json::array();
329 for (
const auto &landmark : poi_.landmark()) {
331 place[
"name"] = landmark.name();
335 "parkingInfo", landmark.parking_info());
336 place[
"parkingInfo"] = parking_info[
"data"];
339 for (
const auto &waypoint : landmark.waypoint()) {
340 waypoint_list.push_back(GetPointJsonFromLaneWaypoint(waypoint));
342 place[
"waypoint"] = waypoint_list;
344 poi_list.push_back(place);
348 "Failed to load default "
349 "POI. Please make sure the "
353 response[
"poi"] = poi_list;
354 websocket_->
SendData(conn, response.dump());
358 "GetDefaultRoutings",
361 response[
"type"] =
"DefaultRoutings";
362 response[
"threshold"] =
363 FLAGS_loop_routing_end_to_start_distance_threshold;
365 Json default_routing_list = Json::array();
367 for (
const auto &landmark : default_routings_.landmark()) {
369 drouting[
"name"] = landmark.name();
372 for (
const auto &point : landmark.waypoint()) {
373 point_list.push_back(GetPointJsonFromLaneWaypoint(point));
375 drouting[
"point"] = point_list;
376 default_routing_list.push_back(drouting);
381 "Failed to load default "
382 "routing. Please make sure the "
386 response[
"defaultRoutings"] = default_routing_list;
387 websocket_->
SendData(conn, response.dump());
391 "GetParkAndGoRoutings",
394 response[
"type"] =
"ParkAndGoRoutings";
395 Json park_go_routing_list = Json::array();
397 for (
const auto &landmark : park_go_routings_.landmark()) {
398 Json park_go_routing;
399 park_go_routing[
"name"] = landmark.name();
402 for (
const auto &point : landmark.waypoint()) {
403 point_list.push_back(GetPointJsonFromLaneWaypoint(point));
405 park_go_routing[
"point"] = point_list;
406 park_go_routing_list.push_back(park_go_routing);
416 response[
"parkAndGoRoutings"] = park_go_routing_list;
417 websocket_->
SendData(conn, response.dump());
423 SimControlManager::Instance()->Reset();
434 auto enable = json.find(
"enable");
435 if (enable != json.end() && enable->is_boolean()) {
437 SimControlManager::Instance()->Start();
439 SimControlManager::Instance()->Stop();
445 "RequestDataCollectionProgress",
447 auto *monitors = FuelMonitorManager::Instance()->GetCurrentMonitors();
449 const auto iter = monitors->find(
"DataCollectionMonitor");
450 if (iter != monitors->end() && iter->second->IsEnabled()) {
452 response[
"type"] =
"DataCollectionProgress";
453 response[
"data"] = iter->second->GetProgressAsJson();
454 websocket_->
SendData(conn, response.dump());
460 "GetParkingRoutingDistance",
463 response[
"type"] =
"ParkingRoutingDistance";
464 response[
"threshold"] = FLAGS_parking_routing_distance_threshold;
465 websocket_->
SendData(conn, response.dump());
469 "RequestPreprocessProgress",
471 auto *monitors = FuelMonitorManager::Instance()->GetCurrentMonitors();
473 const auto iter = monitors->find(
"PreprocessMonitor");
474 if (iter != monitors->end() && iter->second->IsEnabled()) {
476 response[
"type"] =
"PreprocessProgress";
477 response[
"data"] = iter->second->GetProgressAsJson();
478 websocket_->
SendData(conn, response.dump());
484 "SaveDefaultRouting",
486 bool succeed = AddDefaultRouting(json);
490 if (!default_routing_) {
491 AERROR <<
"Failed to add a routing" << std::endl;
495 response[
"routingType"] = json[
"routingType"];
496 websocket_->
SendData(conn, response.dump());
499 "Failed to add a routing.");
506 if (!perception_camera_updater_->
IsEnabled()) {
510 perception_camera_updater_->
GetUpdate(&to_send);
517 std::vector<std::string> channels;
520 response[
"data"][
"name"] =
"GetCameraChannelListSuccess";
521 for (
unsigned int i = 0; i < channels.size(); i++) {
522 response[
"data"][
"info"][
"channel"][i] = channels[i];
524 camera_ws_->
SendData(conn, response.dump());
527 "ChangeCameraChannel",
529 if (!perception_camera_updater_->
IsEnabled()) {
532 auto channel_info = json.find(
"data");
534 if (channel_info == json.end()) {
535 AERROR <<
"Cannot retrieve channel info with unknown channel.";
536 response[
"type"] =
"ChangeCameraChannelFail";
537 camera_ws_->
SendData(conn, response.dump());
540 std::string channel =
541 channel_info->dump().substr(1, channel_info->dump().length() - 2);
544 response[
"type"] =
"ChangeCameraChannelSuccess";
545 camera_ws_->
SendData(conn, response.dump());
547 response[
"type"] =
"ChangeCameraChannelFail";
548 camera_ws_->
SendData(conn, response.dump());
554 if (!plugin_manager_->IsEnabled()) {
557 auto iter = json.find(
"data");
558 if (iter == json.end()) {
559 AERROR <<
"Failed to get plugin msg!";
562 if (!plugin_manager_->SendMsgToPlugin(iter->dump())) {
563 AERROR <<
"Failed to send msg to plugin";
568Json SimulationWorldUpdater::CheckRoutingPoint(
const Json &json) {
570 if (!ContainsKey(json,
"point")) {
571 result[
"error"] =
"Failed to check routing point: point not found.";
572 AERROR << result[
"error"];
575 auto point = json[
"point"];
576 if (!ValidateCoordinate(point) || !ContainsKey(point,
"id")) {
577 result[
"error"] =
"Failed to check routing point: invalid point.";
578 AERROR << result[
"error"];
581 if (!ContainsKey(point,
"heading")) {
583 result[
"pointId"] = point[
"id"];
584 result[
"error"] =
"Selected point cannot be a routing point.";
585 AWARN << result[
"error"];
590 result[
"pointId"] = point[
"id"];
591 result[
"error"] =
"Selected point cannot be a routing point.";
592 AWARN << result[
"error"];
598Json SimulationWorldUpdater::GetPointJsonFromLaneWaypoint(
601 point[
"x"] = waypoint.
pose().
x();
602 point[
"y"] = waypoint.
pose().
y();
603 if (waypoint.has_heading()) {
604 point[
"heading"] = waypoint.
heading();
609bool SimulationWorldUpdater::ConstructLaneWayPoint(
const Json &point,
610 LaneWaypoint *laneWayPoint,
611 std::string description) {
612 if (ContainsKey(point,
"heading")) {
614 point[
"x"], point[
"y"], point[
"heading"], laneWayPoint)) {
615 AERROR <<
"Failed to prepare a routing request with heading: "
616 << point[
"heading"] <<
" cannot locate " << description
623 AERROR <<
"Failed to prepare a routing request:"
624 <<
" cannot locate " << description <<
" on map.";
631bool SimulationWorldUpdater::ConstructLaneFollowCommand(
632 const Json &json, LaneFollowCommand *lane_follow_command) {
633 lane_follow_command->set_command_id(++command_id_);
635 auto iter = json.find(
"waypoint");
636 if (iter != json.end() && iter->is_array()) {
637 auto waypoint = lane_follow_command->mutable_way_point();
638 for (
size_t i = 0; i < iter->size(); ++i) {
639 auto &point = (*iter)[i];
640 auto *pose = waypoint->Add();
641 if (ContainsKey(point,
"heading")) {
642 pose->set_heading(point[
"heading"]);
644 pose->set_x(point[
"x"]);
645 pose->set_y(point[
"y"]);
650 if (!ContainsKey(json,
"end")) {
651 AERROR <<
"Failed to prepare a routing request: end point not found.";
655 auto end = json[
"end"];
656 if (!ValidateCoordinate(end)) {
657 AERROR <<
"Failed to prepare a routing request: invalid end point.";
660 auto end_pose = lane_follow_command->mutable_end_pose();
662 if (ContainsKey(end,
"heading")) {
663 end_pose->set_heading(end[
"heading"]);
665 end_pose->set_x(end[
"x"]);
666 end_pose->set_y(end[
"y"]);
668 AINFO <<
"Constructed LaneFollowCommand to be sent:\n"
669 << lane_follow_command->DebugString();
674bool SimulationWorldUpdater::ConstructValetParkingCommand(
675 const Json &json, ValetParkingCommand *valet_parking_command) {
676 valet_parking_command->clear_parking_spot_id();
677 valet_parking_command->set_command_id(++command_id_);
678 if (ContainsKey(json,
"parkingInfo")) {
679 auto parkingInfo = json[
"parkingInfo"];
680 valet_parking_command->set_parking_spot_id(parkingInfo[
"parkingSpaceId"]);
684 AINFO <<
"Constructed ValetParkingCommand to be sent:\n"
685 << valet_parking_command->DebugString();
689Json SimulationWorldUpdater::GetConstructRoutingRequestJson(
690 const nlohmann::json &start,
const nlohmann::json &end) {
692 result[
"start"] = start;
697bool SimulationWorldUpdater::ValidateCoordinate(
const nlohmann::json &json) {
698 if (!ContainsKey(json,
"x") || !ContainsKey(json,
"y")) {
699 AERROR <<
"Failed to find x or y coordinate.";
702 if (json.find(
"x")->is_number() && json.find(
"y")->is_number()) {
705 AERROR <<
"Both x and y coordinate should be a number.";
715void SimulationWorldUpdater::OnTimer() {
716 sim_world_service_.
Update();
719 boost::unique_lock<boost::shared_mutex> writer_lock(mutex_);
720 last_pushed_adc_timestamp_sec_ =
723 FLAGS_sim_map_radius, &simulation_world_,
724 &simulation_world_with_planning_data_);
726 &relative_map_string_);
730bool SimulationWorldUpdater::LoadPOI() {
731 if (GetProtoFromASCIIFile(EndWayPointFile(), &poi_)) {
739bool SimulationWorldUpdater::isProcessRunning(
const std::string &process_name) {
740 std::stringstream commandStream;
741 commandStream <<
"pgrep -f " << process_name;
742 std::string command = commandStream.str();
744 FILE *fp = popen(command.c_str(),
"r");
747 if (fgets(result,
sizeof(result), fp) !=
nullptr) {
748 AINFO << process_name <<
" is running";
752 AINFO << process_name <<
" is not running";
759bool SimulationWorldUpdater::LoadUserDefinedRoutings(
760 const std::string &file_name, google::protobuf::Message *message) {
765 AWARN <<
"Failed to load routings from " << file_name;
769bool SimulationWorldUpdater::AddDefaultRouting(
const Json &json) {
770 if (!ContainsKey(json,
"name")) {
771 AERROR <<
"Failed to save a routing: routing name not found.";
775 if (!ContainsKey(json,
"point")) {
776 AERROR <<
"Failed to save a routing: routing points not "
781 if (!ContainsKey(json,
"routingType")) {
782 AERROR <<
"Failed to save a routing: routing type not "
787 std::string name = json[
"name"];
788 auto iter = json.find(
"point");
789 std::string routingType = json[
"routingType"];
790 bool isDefaultRouting = (routingType ==
"defaultRouting");
791 default_routing_ = isDefaultRouting ? default_routings_.add_landmark()
792 : park_go_routings_.add_landmark();
793 default_routing_->clear_name();
794 default_routing_->clear_waypoint();
795 default_routing_->set_name(name);
796 auto *waypoint = default_routing_->mutable_waypoint();
797 if (iter != json.end() && iter->is_array()) {
798 for (
size_t i = 0; i < iter->size(); ++i) {
799 auto &point = (*iter)[i];
800 if (!ValidateCoordinate(point)) {
801 AERROR <<
"Failed to save a routing: invalid waypoint.";
804 auto *p = waypoint->Add();
805 auto *pose = p->mutable_pose();
806 pose->set_x(
static_cast<double>(point[
"x"]));
807 pose->set_y(
static_cast<double>(point[
"y"]));
808 if (ContainsKey(point,
"heading")) {
809 p->set_heading(point[
"heading"]);
813 AINFO <<
"User Defined Routing Points to be saved:\n";
814 std::string file_name =
817 isDefaultRouting ? default_routings_ : park_go_routings_,
819 AERROR <<
"Failed to set proto to ascii file " << file_name;
822 AINFO <<
"Success in setting proto to file" << file_name;
static nlohmann::json ProtoToTypedJson(const std::string &json_type, const google::protobuf::Message &proto)
Convert proto to a json string.
Used to perform oneshot or periodic timing tasks
bool CheckRoutingPoint(const double x, const double y) const
bool CheckRoutingPointWithHeading(const double x, const double y, const double heading) const
hdmap::Map RetrieveMapElements(const MapElementIds &ids) const
bool ConstructLaneWayPointWithHeading(const double x, const double y, const double heading, routing::LaneWaypoint *laneWayPoint) const
bool ConstructLaneWayPoint(const double x, const double y, routing::LaneWaypoint *laneWayPoint) const
The function fills out proper routing lane waypoint from the given (x,y) position.
bool ChangeChannel(std::string channel)
void GetUpdate(std::string *camera_update)
void GetChannelMsg(std::vector< std::string > *channels)
GetChannelMsg
void SetToClear()
Sets the flag to clear the owned simulation world object.
void Update()
The function Update() is periodically called to check for updates from the external messages.
void PublishNavigationInfo(const std::shared_ptr< apollo::relative_map::NavigationInfo > &)
void PublishTask(const std::shared_ptr< apollo::task_manager::Task > &)
void PublishLaneFollowCommand(const std::shared_ptr< apollo::external_command::LaneFollowCommand > &)
bool ReadyToPush() const
Check whether the SimulationWorld object has enough information.
const apollo::hdmap::Map & GetRelativeMap() const
const SimulationWorld & world() const
Get a read-only view of the SimulationWorld.
void GetMapElementIds(double radius, MapElementIds *ids) const
void PublishActionCommand(const std::shared_ptr< apollo::external_command::ActionCommand > &)
void PublishMonitorMessage(apollo::common::monitor::MonitorMessageItem::LogLevel log_level, const std::string &msg)
Publish message to the monitor
nlohmann::json GetRoutePathAsJson() const
void GetWireFormatString(double radius, std::string *sim_world, std::string *sim_world_with_planning_data)
Returns the binary representation of the SimulationWorld object.
void PublishValetParkingCommand(const std::shared_ptr< apollo::external_command::ValetParkingCommand > &)
void Start()
Starts to push simulation_world to frontend.
static constexpr double kSimWorldTimeIntervalMs
SimulationWorldUpdater(WebSocketHandler *websocket, WebSocketHandler *map_ws, WebSocketHandler *camera_ws, WebSocketHandler *plugin_ws, const MapService *map_service, PerceptionCameraUpdater *perception_camera_updater, PluginManager *plugin_manager, bool routing_from_file=false)
Constructor with the websocket handler.
The WebSocketHandler, built on top of CivetWebSocketHandler, is a websocket handler that handles diff...
void RegisterMessageHandler(std::string type, MessageHandler handler)
Add a new message handler for a message type.
bool SendData(Connection *conn, const std::string &data, bool skippable=false, int op_code=MG_WEBSOCKET_OPCODE_TEXT)
Sends the provided data to a specific connected client.
void RegisterConnectionReadyHandler(ConnectionReadyHandler handler)
Add a new handler for new connections.
bool SendBinaryData(Connection *conn, const std::string &data, bool skippable=false)
Planning module main class.
#define AWARN_EVERY(freq)
bool GetProtoFromASCIIFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the file specified by the file_name as ascii representation of protobufs,...
bool SetProtoToASCIIFile(const google::protobuf::Message &message, int file_descriptor)
std::string DefaultRoutingFile()
get default routing file path from flags.
std::string EndWayPointFile()
get end way point file path from flags.
std::string ParkGoRoutingFile()
get park and go routings file path from flags.
optional double timestamp_sec
optional Object auto_driving_car
optional apollo::common::PointENU pose