Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSDevice_StationFinder.h
15 : /// @author Michael Behrisch
16 : /// @author Mirko Barthauer
17 : /// @date 2023-05-24
18 : ///
19 : // A device which triggers rerouting to nearby charging stations
20 : /****************************************************************************/
21 : #pragma once
22 : #include <config.h>
23 :
24 : #include <utils/common/WrappingCommand.h>
25 : #include <microsim/trigger/MSStoppingPlaceRerouter.h>
26 : #include "MSVehicleDevice.h"
27 :
28 :
29 : #define DEFAULT_SOC_INTERVAL 0.1
30 : #define DEFAULT_ENERGY_PER_DISTANCE 200 // Wh/km
31 : #define DEFAULT_AVG_WAITING_TIME 900. // s
32 : #define DEFAULT_CHARGINGSTATION_VIEW_DIST 10 // m
33 : #define DEFAULT_CONSUMPTION_ESTIMATE_HISTORY 10 // s
34 : #define DEFAULT_OPPORTUNITY_INTERVAL 1800 // s
35 :
36 : // ===========================================================================
37 : // class declarations
38 : // ===========================================================================
39 : class MSDevice_Battery;
40 : class MSStoppingPlace;
41 :
42 :
43 : // ===========================================================================
44 : // class definitions
45 : // ===========================================================================
46 : /**
47 : * @class MSDevice_StationFinder
48 : * @brief A device which triggers rerouting to nearby charging stations
49 : *
50 : * Each device checks the battery status by being
51 : * called each time step and initiaiting the search for a compatible
52 : * charging station if the battery level is too low.
53 : *
54 : * @see MSDevice
55 : */
56 : class MSDevice_StationFinder : public MSVehicleDevice, MSStoppingPlaceRerouter {
57 : public:
58 : enum ChargeType {
59 : CHARGETYPE_CHARGING,
60 : CHARGETYPE_BIDIRECTIONAL,
61 : CHARGETYPE_BATTERYEXCHANGE,
62 : CHARGETYPE_FUEL
63 : };
64 :
65 : enum ChargingStrategy {
66 : CHARGINGSTRATEGY_NONE,
67 : CHARGINGSTRATEGY_BALANCED,
68 : CHARGINGSTRATEGY_LATEST
69 : };
70 :
71 : enum RescueAction {
72 : RESCUEACTION_NONE,
73 : RESCUEACTION_REMOVE,
74 : RESCUEACTION_TOW
75 : };
76 :
77 : enum SearchState {
78 : SEARCHSTATE_NONE = 0,
79 : SEARCHSTATE_SUCCESSFUL,
80 : SEARCHSTATE_UNSUCCESSFUL,
81 : SEARCHSTATE_CHARGING,
82 : SEARCHSTATE_WAITING,
83 : SEARCHSTATE_BROKEN_DOWN
84 : };
85 :
86 : /** @brief Inserts MSDevice_StationFinder-options
87 : */
88 : static void insertOptions(OptionsCont& oc);
89 :
90 :
91 : /** @brief Build devices for the given vehicle, if needed
92 : *
93 : * The options are read and evaluated whether stationFinder-devices shall be built
94 : * for the given vehicle.
95 : *
96 : * For each seen vehicle, the global vehicle index is increased.
97 : *
98 : * The built device is stored in the given vector.
99 : *
100 : * @param[in] v The vehicle for which a device may be built
101 : * @param[in, filled] into The vector to store the built device in
102 : */
103 : static void buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into);
104 :
105 : /** @brief Constructor
106 : *
107 : * @param[in] holder The vehicle that holds this device
108 : */
109 : MSDevice_StationFinder(SUMOVehicle& holder);
110 :
111 : /// @brief Destructor.
112 : ~MSDevice_StationFinder();
113 :
114 : /// @name Methods called on vehicle movement / state change, overwriting MSDevice
115 : /// @{
116 :
117 : /** @brief Computes current emission values and adds them to their sums
118 : *
119 : * The vehicle's current emission values
120 : * are computed using the current velocity and acceleration.
121 : *
122 : * @param[in] veh The regarded vehicle
123 : * @param[in] oldPos Position before the move-micro-timestep.
124 : * @param[in] newPos Position after the move-micro-timestep.
125 : * @param[in] newSpeed The vehicle's current speed
126 : * @return false, if the vehicle is beyond the lane, true otherwise
127 : * @see MSMoveReminder
128 : * @see MSMoveReminder::notifyMove
129 : * @see PollutantsInterface
130 : */
131 : bool notifyMove(SUMOTrafficObject& veh, double oldPos, double newPos, double newSpeed) override;
132 :
133 : /** @brief Computes idling emission values and adds them to the emission sums
134 : *
135 : * Idling implied by zero velocity, acceleration and slope
136 : *
137 : * @param[in] veh The vehicle
138 : *
139 : * @see MSMoveReminder::notifyMove
140 : * @see PollutantsInterface
141 : */
142 : bool notifyIdle(SUMOTrafficObject& veh) override;
143 :
144 : /// @}
145 :
146 : /** @brief Saves the state of the device
147 : *
148 : * @param[in] out The OutputDevice to write the information into
149 : */
150 : void saveState(OutputDevice& out) const override;
151 :
152 : /** @brief Loads the state of the device from the given description
153 : *
154 : * @param[in] attrs XML attributes describing the current state
155 : */
156 : void loadState(const SUMOSAXAttributes& attrs) override;
157 :
158 : /// @brief return the name for this type of device
159 240 : const std::string deviceName() const override {
160 240 : return "stationfinder";
161 : }
162 :
163 : /// @brief return the string representation of the chosen charging strategy
164 : const std::string getChargingStrategy() const {
165 : if (myChargingStrategy == CHARGINGSTRATEGY_NONE) {
166 : return "none";
167 : } else if (myChargingStrategy == CHARGINGSTRATEGY_BALANCED) {
168 : return "balanced";
169 : } else {
170 : return "latest";
171 : }
172 : }
173 :
174 : /** @brief Called on writing tripinfo output
175 : *
176 : * @param[in] os The stream to write the information into
177 : * @exception IOError not yet implemented
178 : * @see MSDevice::tripInfoOutput
179 : */
180 : void generateOutput(OutputDevice* tripinfoOut) const override;
181 :
182 : void setBattery(MSDevice_Battery* battery) {
183 87 : myBattery = battery;
184 87 : }
185 :
186 : std::string getParameter(const std::string& key) const override;
187 :
188 : /// @brief try to set the given parameter for this device. Throw exception for unsupported key
189 : void setParameter(const std::string& key, const std::string& value) override;
190 :
191 : /** @brief Compute some custom target function components
192 : *
193 : * @param[in] veh the concerned vehicle
194 : * @param[in] brakeGap the distance before which the vehicle cannot stop
195 : * @param[in] newDestination whether the destination changed
196 : * @param[in] alternative the stopping place to evaluate
197 : * @param[in] occupancy occupancy of the stopping place
198 : * @param[in] router the router to use for evaluation if needed
199 : * @param[in,out] stoppingPlaceValues the data structure to write the evaluation values to
200 : * @param[in] newRoute the complete route to the destination passing by the stopping place
201 : * @param[in] stoppingPlaceApproach the route to the stopping place
202 : * @param[in] maxValues the maximum values of the components
203 : * @param[in] addInput external input data
204 : * @return false if the stopping place cannot be used according to the custom evaluation components
205 : */
206 : bool evaluateCustomComponents(SUMOVehicle& veh, double brakeGap, bool newDestination,
207 : MSStoppingPlace* alternative, double occupancy, double prob,
208 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router, StoppingPlaceParamMap_t& stoppingPlaceValues,
209 : ConstMSEdgeVector& newRoute,
210 : ConstMSEdgeVector& stoppingPlaceApproach,
211 : StoppingPlaceParamMap_t& maxValues,
212 : StoppingPlaceParamMap_t& addInput) override;
213 :
214 : /// @brief Whether the stopping place should be discarded due to its results from the component evaluation
215 : bool validComponentValues(StoppingPlaceParamMap_t& stoppingPlaceValues) override;
216 :
217 : /// @brief Whether the stopping place should be included in the search (can be used to add an additional filter)
218 : bool useStoppingPlace(MSStoppingPlace* stoppingPlace) override;
219 :
220 : /// @brief Provide the router to use (MSNet::getRouterTT or MSRoutingEngine)
221 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& getRouter(SUMOVehicle& veh, const Prohibitions& prohibited) override;
222 :
223 : /// @brief Return the number of occupied places of the StoppingPlace
224 : double getStoppingPlaceOccupancy(MSStoppingPlace* stoppingPlace) override;
225 :
226 : /// @brief Return the number of occupied places of the StoppingPlace from the previous time step
227 : double getLastStepStoppingPlaceOccupancy(MSStoppingPlace* stoppingPlace) override;
228 :
229 : /// @brief Return the number of places the StoppingPlace provides
230 : double getStoppingPlaceCapacity(MSStoppingPlace* stoppingPlace) override;
231 :
232 : /// @brief store the blocked stopping place in the vehicle
233 : void rememberBlockedStoppingPlace(SUMOVehicle& veh, const MSStoppingPlace* stoppingPlace, bool blocked) override;
234 :
235 : /// @brief store the stopping place score in the vehicle
236 : void rememberStoppingPlaceScore(SUMOVehicle& veh, MSStoppingPlace* place, const std::string& score) override;
237 :
238 : /// @brief forget all stopping place score for this vehicle
239 : void resetStoppingPlaceScores(SUMOVehicle& veh) override;
240 :
241 : /// @brief ask the vehicle when it has seen the stopping place
242 : SUMOTime sawBlockedStoppingPlace(SUMOVehicle& veh, MSStoppingPlace* place, bool local) override;
243 :
244 : /// @brief ask how many times already the vehicle has been rerouted to another stopping place
245 : int getNumberStoppingPlaceReroutes(SUMOVehicle& veh) override;
246 :
247 : /// @brief update the number of reroutes for the vehicle
248 : void setNumberStoppingPlaceReroutes(SUMOVehicle& veh, int value) override;
249 :
250 : protected:
251 : /** @brief Internal notification about the vehicle moves, see MSMoveReminder::notifyMoveInternal()
252 : *
253 : */
254 : void notifyMoveInternal(const SUMOTrafficObject& veh,
255 : const double frontOnLane,
256 : const double timeOnLane,
257 : const double meanSpeedFrontOnLane,
258 : const double meanSpeedVehicleOnLane,
259 : const double travelledDistanceFrontOnLane,
260 : const double travelledDistanceVehicleOnLane,
261 : const double meanLengthOnLane) override;
262 :
263 : private:
264 : /** @brief central search function for close charging stations
265 : *
266 : * @param[in] router
267 : * @param[in] expectedConsumption
268 : * @param[in,out] scores additional input for score computation and scores of the best charging station
269 : * @param[in] constrainTT whether to constrain the search radius by a maximum travel time
270 : * @param[in] skipVisited whether to skip charging stations which have not been available when passing by recently
271 : * @param[in] skipOccupied whether to skip fully occupied charging stations
272 : * @param[in] visible whether the charging station has to be within the visibility radius of the vehicle
273 : * @return The found charging station, otherwise nullptr
274 : */
275 : MSChargingStation* findChargingStation(SUMOAbstractRouter<MSEdge,
276 : SUMOVehicle>& router,
277 : double expectedConsumption,
278 : StoppingPlaceParamMap_t& scores,
279 : bool constrainTT = true, bool skipVisited = true, bool skipOccupied = false, bool visible = false);
280 :
281 :
282 : /** @brief reroute to a charging station
283 : *
284 : * @param[in] replace if the already planned next stop should be replaced (a new stop will be prepended if false)
285 : * @return true if the vehicle has been redirected to a charging station, false otherwise
286 : */
287 : bool rerouteToChargingStation(bool replace = false);
288 :
289 :
290 : /** @brief check which stop is suited for opportunistic charging and try to plan charging stops
291 : *
292 : * @return true if the vehicle has planned at least one opportunistic charging stop
293 : */
294 : bool planOpportunisticCharging();
295 :
296 :
297 : /** @brief search for a charging station and teleport the vehicle there as a rescue measure
298 : */
299 : SUMOTime teleportToChargingStation(const SUMOTime currentTime);
300 :
301 : /** @brief estimate the energy needed for the planned route / up to a target edge
302 : *
303 : * @param[in] target edge along the route up to which the consumption shall be estimated - the complete route will be used if defaulting to nullptr
304 : * @param[in] includeEmptySoC whether to add an additional buffer for the range up to the "empty" threshold
305 : * @param[in] stopDiscount duration in seconds to discount in the consumption estimation due to occurred stopping time
306 : * @return energy in Wh needed to complete the planned route
307 : */
308 : double estimateConsumption(const MSEdge* target = nullptr, const bool includeEmptySoC = true, const double stopDiscount = 0.) const;
309 :
310 : /** @brief compute the free space at a charging station
311 : *
312 : * @param[in] cs the charging station to compute the free space for
313 : * @return the free space at the charging station as a fraction of the holder vehicle
314 : */
315 : double freeSpaceAtChargingStation(MSChargingStation* cs) const;
316 :
317 : /** @brief adopt a planned charging stop outside of the device
318 : *
319 : * @return whether an already present stop was adopted to be used with the device logic
320 : */
321 : bool alreadyPlannedCharging();
322 :
323 : /** @brief create the event command for teleporting in case of brake-down
324 : */
325 : void initRescueCommand();
326 :
327 : /** @brief create the event command for changing charging rates
328 : */
329 : void initChargeLimitCommand();
330 :
331 : /** @brief update the maximum charge rate of the battery to simulate charging strategies
332 : */
333 : SUMOTime updateChargeLimit(const SUMOTime currentTime);
334 :
335 : /** @brief
336 : */
337 : void implementChargingStrategy(SUMOTime begin, SUMOTime end, const double plannedCharge, const MSChargingStation* cs);
338 :
339 : private:
340 : /// @brief myHolder cast to needed type
341 : MSVehicle& myVeh;
342 :
343 : /// @brief The corresponding battery device
344 : MSDevice_Battery* myBattery;
345 :
346 : /// @brief To which station we are currently travelling
347 : MSStoppingPlace* myChargingStation;
348 :
349 : /// @brief The command responsible for rescue actions
350 : WrappingCommand<MSDevice_StationFinder>* myRescueCommand;
351 :
352 : /// @brief The command responsible for limiting the charging rate (~ implement charging strategies)
353 : WrappingCommand<MSDevice_StationFinder>* myChargeLimitCommand;
354 :
355 : /// @brief The next charging rates to set via myChargingRateCommand
356 : std::vector<std::pair<SUMOTime, double>> myChargeLimits;
357 :
358 : /// @brief Last time the SoC was checked
359 : SUMOTime myLastChargeCheck;
360 :
361 : /// @brief Time interval after which the SoC has to be checked
362 : SUMOTime myCheckInterval;
363 :
364 : /// @brief Arrival time in the vicinity of the target charging station (to track the waiting time before accessing it)
365 : SUMOTime myArrivalAtChargingStation;
366 :
367 : /// @brief Last time charging stations have been searched
368 : SUMOTime myLastSearch;
369 :
370 : /// @brief Last time charging stations have been searched for opportunistic charging
371 : SUMOTime myLastOpportunisticSearch;
372 :
373 : /// @brief The time to wait for a rescue vehicle in case the battery is empty
374 : double myRescueTime;
375 :
376 : /// @brief The safety buffer when calculating expected consumption
377 : double myReserveFactor;
378 :
379 : /// @brief The state of charge threshold below which rescue mode is activated
380 : double myEmptySoC;
381 :
382 : /// @brief The maximum euclidean distance between the vehicle and the charging station (-1 deactivates the condition)
383 : double myMaxEuclideanDistance;
384 :
385 : /// @brief The max travel time to the next charging station
386 : SUMOTime myRadius;
387 :
388 : /// @brief Time interval to search again for a charging station if the first attempt failed
389 : SUMOTime myRepeatInterval;
390 :
391 : /// @brief Accepted waiting time at the charging station before a place becomes available
392 : SUMOTime myWaitForCharge;
393 :
394 : /// @brief Minimal expected stop duration to allow for opportunistic charging (not needed to complete the route)
395 : SUMOTime myMinOpportunisticTime;
396 :
397 : /// @brief SoC the last time the station finder algorithm was run completely
398 : double myUpdateSoC;
399 :
400 : /// @brief The maximum charging speed of the vehicle battery in W
401 : double myMaxChargePower;
402 :
403 : /// @brief The target state of charge where the vehicle stops charging
404 : double myTargetSoC;
405 :
406 : /// @brief The state of charge at which the vehicle starts looking for charging stations
407 : double mySearchSoC;
408 :
409 : /// @brief The state of charge at/below which the vehicle is interested in charging although it may still be sufficient to terminate its route
410 : double myOpportunitySoC;
411 :
412 : /// @brief The share of stopping time a charging stop should take from the next regular (non-charging) stop under certain conditions
413 : double myReplacePlannedStop;
414 :
415 : /// @brief The distance in meters to the original stop replaced by the charging stop (models charging close to the activity location) - used as well for opportunistic charging
416 : double myDistanceToOriginalStop;
417 :
418 : /// @brief The type of charging permitted by the battery (charging, bidirectional, battery exchange)
419 : ChargeType myChargeType;
420 :
421 : /// @brief The chosen charging strategy
422 : ChargingStrategy myChargingStrategy;
423 :
424 : /// @brief What to do when the state of charge gets very low
425 : RescueAction myRescueAction;
426 :
427 : /// @brief The current state of the charging search (remember for decision logic)
428 : SearchState mySearchState = SEARCHSTATE_NONE;
429 :
430 : /// @brief Whether to skip searching charging stations if the battery charge is sufficient to complete the current route
431 : bool myCheckEnergyForRoute;
432 :
433 : private:
434 : /// @brief Invalidated copy constructor.
435 : MSDevice_StationFinder(const MSDevice_StationFinder&);
436 :
437 : /// @brief Invalidated assignment operator.
438 : MSDevice_StationFinder& operator=(const MSDevice_StationFinder&);
439 : };
|