Apollo 10.0
自动驾驶开放平台
hmi.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2017 The Apollo Authors. All Rights Reserved.
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
18
19#include <string>
20#include <vector>
21
22#include "google/protobuf/util/json_util.h"
23
24#include "modules/dreamview/proto/preprocess_table.pb.h"
25
26#include "cyber/common/file.h"
33
34namespace apollo {
35namespace dreamview {
36
39using google::protobuf::util::JsonStringToMessage;
41
42HMI::HMI(WebSocketHandler* websocket, MapService* map_service)
43 : hmi_worker_(new HMIWorker()),
44 monitor_log_buffer_(apollo::common::monitor::MonitorMessageItem::HMI),
45 websocket_(websocket),
46 map_service_(map_service) {
47 if (websocket_) {
48 RegisterMessageHandlers();
49 }
50}
51
52void HMI::Start(DvCallback callback_api) { hmi_worker_->Start(callback_api); }
53
54void HMI::Stop() { hmi_worker_->Stop(); }
55
56void HMI::RegisterMessageHandlers() {
57 // Broadcast HMIStatus to clients when status changed.
58 hmi_worker_->RegisterStatusUpdateHandler(
59 [this](const bool status_changed, HMIStatus* status) {
60 if (!status_changed) {
61 // Status doesn't change, skip broadcasting.
62 return;
63 }
64 websocket_->BroadcastData(
65 JsonUtil::ProtoToTypedJson("HMIStatus", *status).dump());
66 if (status->current_map().empty()) {
67 monitor_log_buffer_.WARN("You haven't selected a map yet!");
68 }
69 if (status->current_vehicle().empty()) {
70 monitor_log_buffer_.WARN("You haven't selected a vehicle yet!");
71 }
72 });
73
74 // Send current status and vehicle param to newly joined client.
76 [this](WebSocketHandler::Connection* conn) {
77 SendStatus(conn);
78 SendVehicleParam(conn);
79 });
80
81 websocket_->RegisterMessageHandler(
82 "HMIAction",
83 [this](const Json& json, WebSocketHandler::Connection* conn) {
84 // Run HMIWorker::Trigger(action) if json is {action: "<action>"}
85 // Run HMIWorker::Trigger(action, value) if "value" field is provided.
86 std::string action;
87 if (!JsonUtil::GetString(json, "action", &action)) {
88 AERROR << "Truncated HMIAction request.";
89 return;
90 }
91 HMIAction hmi_action;
92 if (!HMIAction_Parse(action, &hmi_action)) {
93 AERROR << "Invalid HMIAction string: " << action;
94 return;
95 }
96 std::string value;
97 if (JsonUtil::GetString(json, "value", &value)) {
98 hmi_worker_->Trigger(hmi_action, value);
99 } else {
100 hmi_worker_->Trigger(hmi_action);
101 }
102
103 // Extra works for current Dreamview.
104 if (hmi_action == HMIAction::CHANGE_MAP) {
105 // Reload simulation map after changing map.
106 ACHECK(map_service_->ReloadMap(true))
107 << "Failed to load new simulation map: " << value;
108 } else if (hmi_action == HMIAction::CHANGE_VEHICLE) {
109 // Reload lidar params for point cloud service.
110 PointCloudUpdater::LoadLidarHeight(FLAGS_lidar_height_yaml);
111 SendVehicleParam();
112 }
113 });
114
115 // HMI client asks for adding new AudioEvent.
116 websocket_->RegisterMessageHandler(
117 "SubmitAudioEvent",
118 [this](const Json& json, WebSocketHandler::Connection* conn) {
119 // json should contain event_time_ms, obstacle_id, audio_type,
120 // moving_result, audio_direction and is_siren_on.
121 uint64_t event_time_ms;
122 int obstacle_id;
123 int audio_type;
124 int moving_result;
125 int audio_direction;
126 bool is_siren_on;
127 if (JsonUtil::GetNumber(json, "event_time_ms", &event_time_ms) &&
128 JsonUtil::GetNumber(json, "obstacle_id", &obstacle_id) &&
129 JsonUtil::GetNumber(json, "audio_type", &audio_type) &&
130 JsonUtil::GetNumber(json, "moving_result", &moving_result) &&
131 JsonUtil::GetNumber(json, "audio_direction", &audio_direction) &&
132 JsonUtil::GetBoolean(json, "is_siren_on", &is_siren_on)) {
133 hmi_worker_->SubmitAudioEvent(event_time_ms, obstacle_id, audio_type,
134 moving_result, audio_direction,
135 is_siren_on);
136 monitor_log_buffer_.INFO("Audio event added.");
137 } else {
138 AERROR << "Truncated SubmitAudioEvent request.";
139 monitor_log_buffer_.WARN("Failed to submit an audio event.");
140 }
141 });
142
143 // HMI client asks for adding new DriveEvent.
144 websocket_->RegisterMessageHandler(
145 "SubmitDriveEvent",
146 [this](const Json& json, WebSocketHandler::Connection* conn) {
147 // json should contain event_time_ms and event_msg.
148 uint64_t event_time_ms;
149 std::string event_msg;
150 std::vector<std::string> event_types;
151 bool is_reportable;
152 if (JsonUtil::GetNumber(json, "event_time_ms", &event_time_ms) &&
153 JsonUtil::GetString(json, "event_msg", &event_msg) &&
154 JsonUtil::GetStringVector(json, "event_type", &event_types) &&
155 JsonUtil::GetBoolean(json, "is_reportable", &is_reportable)) {
156 hmi_worker_->SubmitDriveEvent(event_time_ms, event_msg, event_types,
157 is_reportable);
158 monitor_log_buffer_.INFO("Drive event added.");
159 } else {
160 AERROR << "Truncated SubmitDriveEvent request.";
161 monitor_log_buffer_.WARN("Failed to submit a drive event.");
162 }
163 });
164
165 websocket_->RegisterMessageHandler(
166 "HMIStatus",
167 [this](const Json& json, WebSocketHandler::Connection* conn) {
168 SendStatus(conn);
169 });
170
171 websocket_->RegisterMessageHandler(
172 "SensorCalibrationPreprocess",
173 [this](const Json& json, WebSocketHandler::Connection* conn) {
174 // json should contain type and data.
175 std::string current_mode = hmi_worker_->GetStatus().current_mode();
176 std::string task_type;
177 if (current_mode == FLAGS_lidar_calibration_mode) {
178 task_type = "lidar_to_gnss";
179 } else if (current_mode == FLAGS_camera_calibration_mode) {
180 task_type = "camera_to_lidar";
181 } else {
182 AERROR << "Unsupported mode:" << current_mode;
183 return;
184 }
185
186 const auto iter = json.find("data");
187 if (iter == json.end()) {
188 AERROR << "The json has no such key: data";
189 return;
190 }
191 PreprocessTable preprocess_table;
192 if (!JsonStringToMessage(json["data"].dump(), &preprocess_table).ok()) {
193 AERROR
194 << "Failed to get user configuration: invalid preprocess table."
195 << json.dump();
196 }
197
198 // Gernerate user-specified configuration and run the preprocess script
199 std::string output_file =
200 absl::StrCat("modules/tools/sensor_calibration/config/",
201 task_type, "_user.config");
202 if (!SetProtoToASCIIFile(preprocess_table, output_file)) {
203 AERROR << "Failed to generate user configuration file";
204 }
205 hmi_worker_->SensorCalibrationPreprocess(task_type);
206 });
207
208 websocket_->RegisterMessageHandler(
209 "VehicleCalibrationPreprocess",
210 [this](const Json& json, WebSocketHandler::Connection* conn) {
211 hmi_worker_->VehicleCalibrationPreprocess();
212 });
213}
214
215void HMI::SendVehicleParam(WebSocketHandler::Connection* conn) {
216 if (websocket_ == nullptr) {
217 return;
218 }
219
220 const auto& vehicle_param =
222 const std::string json_str =
223 JsonUtil::ProtoToTypedJson("VehicleParam", vehicle_param).dump();
224 if (conn != nullptr) {
225 websocket_->SendData(conn, json_str);
226 } else {
227 websocket_->BroadcastData(json_str);
228 }
229}
230
231void HMI::SendStatus(WebSocketHandler::Connection* conn) {
232 const auto status_json =
233 JsonUtil::ProtoToTypedJson("HMIStatus", hmi_worker_->GetStatus());
234 websocket_->SendData(conn, status_json.dump());
235}
236
237bool HMI::UpdateScenarioSetToStatus(const std::string& scenario_set_id,
238 const std::string& scenario_set_name) {
239 return hmi_worker_->UpdateScenarioSetToStatus(scenario_set_id,
240 scenario_set_name);
241}
242
243bool HMI::UpdateDynamicModelToStatus(const std::string& dynamic_model_name) {
244 return hmi_worker_->UpdateDynamicModelToStatus(dynamic_model_name);
245}
246
247bool HMI::UpdateRecordToStatus() { return hmi_worker_->LoadRecords(); }
248
249bool HMI::UpdateVehicleToStatus() { return hmi_worker_->ReloadVehicles(); }
250
251bool HMI::UpdateCameraChannelToStatus(const std::string& channel_name) {
252 hmi_worker_->UpdateCameraSensorChannelToStatus(channel_name);
253 return true;
254}
255
256bool HMI::UpdatePointChannelToStatus(const std::string& channel_name) {
257 hmi_worker_->UpdatePointCloudChannelToStatus(channel_name);
258 return true;
259}
260} // namespace dreamview
261} // namespace apollo
static const VehicleConfig & GetConfig()
Get the current vehicle configuration.
static bool GetNumber(const nlohmann::json &json, const std::string &key, T *value)
Get a number value from the given json[key].
Definition json_util.h:59
static bool GetStringVector(const nlohmann::json &json, const std::string &key, std::vector< std::string > *value)
Get a string vector from the given json[key].
Definition json_util.cc:109
static nlohmann::json ProtoToTypedJson(const std::string &json_type, const google::protobuf::Message &proto)
Convert proto to a json string.
Definition json_util.cc:37
static bool GetBoolean(const nlohmann::json &json, const std::string &key, bool *value)
Get a boolean value from the given json[key].
Definition json_util.cc:137
static bool GetString(const nlohmann::json &json, const std::string &key, std::string *value)
Get a string value from the given json[key].
Definition json_util.cc:58
HMI(WebSocketHandler *websocket, MapService *map_service)
Definition hmi.cc:42
std::function< nlohmann::json(const std::string &function_name, const nlohmann::json &param_json)> DvCallback
Definition hmi.h:37
bool UpdateDynamicModelToStatus(const std::string &dynamic_model_name)
Definition hmi.cc:243
bool UpdatePointChannelToStatus(const std::string &channel_name)
Definition hmi.cc:256
bool UpdateRecordToStatus()
Definition hmi.cc:247
bool UpdateCameraChannelToStatus(const std::string &channel_name)
Definition hmi.cc:251
bool UpdateScenarioSetToStatus(const std::string &scenario_set_id, const std::string &scenario_set_name)
Definition hmi.cc:237
void Start(DvCallback callback_api)
Definition hmi.cc:52
bool UpdateVehicleToStatus()
Definition hmi.cc:249
bool ReloadMap(bool force_reload)
static void LoadLidarHeight(const std::string &file_path)
The WebSocketHandler, built on top of CivetWebSocketHandler, is a websocket handler that handles diff...
bool BroadcastData(const std::string &data, bool skippable=false)
Sends the provided data to all the connected clients.
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.
#define ACHECK(cond)
Definition log.h:80
#define AERROR
Definition log.h:44
nlohmann::json Json
bool SetProtoToASCIIFile(const google::protobuf::Message &message, int file_descriptor)
Definition file.cc:43
class register implement
Definition arena_queue.h:37
optional VehicleParam vehicle_param