eclipse-sumo / sumo

Eclipse SUMO is an open source, highly portable, microscopic and continuous traffic simulation package designed to handle large networks. It allows for intermodal simulation including pedestrians and comes with a large set of tools for scenario creation.
https://eclipse.dev/sumo
Eclipse Public License 2.0
2.57k stars 1.43k forks source link

How to get the next SUMO speed/ acceleration for a vehicle when it is manually controlled? #8661

Closed philippwulff closed 2 years ago

philippwulff commented 3 years ago

Basically, I want to get the speed which SUMO would issue to a certain vehicle in a simulation in the next time step, then pass this through an algorithm to obtain a calculated speed. This calculated speed will then be applied to the vehicle and simulationStep() is called.

I looked at traci.vehicle.getSpeedWithoutTraCI(veh_id), but this just returns the speed if setSpeed(veh_id, val) during the last time step is ignored. E.g., if setSpeed(veh_id, 0) and simulationStep() are called, traci.vehicle.getSpeedWithoutTraCI(veh_id) always returns zero. So this does not really work for me.

I know that I could use getFollowSpeed and getStopSpeed and then use the minimum of the two. However this does not take care of traffic lights or right-of-way-situations.

Basically I need some method to return the speed which SUMO wants a certain vehicle to drive in the next time step. Is it possible to retrieve this value? It must be calculated within SUMO somewhere, right? If it is possible and does not exist at the moment, I would try to code that feature myself.

Domsall commented 3 years ago

This sounds like the same behavior I needed in #7190. For this reason I added the command setPreviousSpeed. I do the following to get the velocity calculated from SUMO and then adapt the speed to the value from my Simulink model:

  1. simulationStep() and getSpeedWithoutTraCI() (VAR_SPEED_WITHOUT_TRACI)
  2. calculate the actually achieved speed by the Simulink model
  3. setPreviousSpeed() to set the actually achieved speed and call moveToXY() to set the vehicle to the correct position
  4. simulationStep() now uses this speed at the beginning of the step and calculates the new speed with the internal model, which after the step can be read with getSpeedWithoutTraCI()
philippwulff commented 3 years ago

Thank you for the quick reply! I will implement it and see if it works for me.

philippwulff commented 3 years ago

Unfortunately, I could not get it to work. I want the vehicle to drive with the adapted speed, meaning, when I set the vehicle's speed to value and then call simulationStep(), the vehicle's speed should be value. But when I try the pseudo-code you suggested, the vehicle always has the "SUMO-speed" after simulationStep() is called instead of the adapted speed.

These are the main calls which I make to replicate your example (and which do not work as I want them to):

while True:
    traci.simulationStep()
    sumo_speed = traci.vehicle.getSpeedWithoutTraCI(veh_id)     # -> get the SUMO-corrected speed for this time step
    model_speed = model(sumo_speed)                             # -> calculate the adjusted speed
    traci.vehicle.setPreviousSpeed(veh_id, model_speed)         # -> set the adjusted speed for the vehicle

When I run this, the vehicle always has the sumo_speed as its speed in every time step, instead of the last model_speed.

From what I understand, after calling simulationStep() SUMO will correct the PreviousSpeed (which was set before) to a value according to an internal model. However, I only want to know the value for this corrected speed and not have SUMO set the it in the simulation. Preferably, I want to know this value for the next time step, then adjust it and set the vehicle speed in the next time step to this adjusted value. Can you please explain how you do this?

You mentioned moveToXY. How is that relevant? Why do you have to call moveToXY()? Doesn't SUMO take care of calculating the new position of the vehicle after having set its speed?

philippwulff commented 3 years ago

The only way for getting the speed SUMO wants a vehicle to drive in the next time step which I came up with would be using two simulations (sim1 and sim2) and copying the simulation state in between the two after every step. Sim2 would be ahead of sim1 by one time step and SUMO would control the vehicle here to give me the SUMO-speed for it. This is a pretty bad solution and I would rather like to just extract the SUMO-speed from SUMO itself.

This would be the pseudo-code for my idea: SUMO dual sim for the next speed

As I said, I would prefer to just extract the value for the nextTraCISpeed from SUMO directly.

Domsall commented 3 years ago

If you want to get the speed before SUMO outputs this velocity, then you could use getFollowSpeed and getStopSpeed, but as you pointed out, that does not take care of every case. You are right, setPreviousSpeed acts the way you described it. For me it is not problematic, because you are getting the internal speed from SUMO and then setting it according to your model yourself. When you change the velocity before the next time step, the calculation behaves, as if this speed was set in the first place. I call moveTo or moveToXY, because the position gets updated with the internal speed and not with the adjusted one. When you do this before the time step, the vehicle then stands at the position it would have had, if it had driven with the adjusted speed as intended. This is a work around for the current way SUMO calculates the speeds of the different vehicles. For SUMO it does not matter, if you set these variables after the time step or "with" the time step.

@namdre I hope I am not explaining it wrong

namdre commented 3 years ago

@Domsall Yes. That's correct. The core problem that is solved by the workaround of @Domsall is, that the vehicle speed is only known within SUMO after the vehicle has interacted (via junctions) with (potentially) all other vehicles that are approaching the respective junction in the current time step. Whereas the followSpeed is based on the leader state from the previous step, the junction model works on information from the current step and thus cannot be (feasibly) anticipated at the start of the step.

behrisch commented 3 years ago

should be documented somewhere maybe from the traci page

philippwulff commented 3 years ago

@Domsall Just so that I understand how these commands are processed in SUMO:

From this

You are right, setPreviousSpeed acts the way you described it. For me it is not problematic, because you are getting the internal speed from SUMO and then setting it according to your model yourself. When you change the velocity before the next time step, the calculation behaves, as if this speed was set in the first place.

I understand, you call getSpeedWithoutTraCI() and then setPreviousSpeed() with your adjusted speed. After calling simulationStep() SUMO's calculation will assume the vehicle drove with the PreviousSpeed during the entire last time step. If one would however use setSpeed instead of setPreviousSpeed, SUMO would not use the given speed for the last time step, right?

In the end you call moveTo() so that the (manual) calculation of the vehicle position is based upon the adjusted speed and not the internal SUMO speed. However, the vehicle will still have SUMO's internal speed within the simulation during the next time step, even though its position was updated manually with the adjusted speed. This would be a major issue for my use case.

I ended up coding the co-sim-solution to obtain the internal SUMO speed for a vehicle in the next time step and while it is slow, it is working 👍🏽 .

Thanks for your help!

namdre commented 3 years ago

There is an added complication depending on the the use of moveTo / moveToXY in step 3

@Domsall can you confirm the following? :

Domsall commented 3 years ago

@philippwulff setSpeed and setPreviousSpeed:

Or what do you want to do? It is maybe a bit hard to explain it here, you can also write me an E-Mail and we can get together for a talk.

@namdre moveTo and moveToXY:

chambonp commented 2 years ago

I am trying to do what philippwulff did one year ago: use SUMO to provide the target speed for an ego vehicle , feed that target speed to an external vehicle dynamics model, and then feedback the modelled speed to SUMO to calculate the next target speed , and so on. I followed Domsall's recipe and it doesn't work for me either: the target vehicle speed gets stuck on the value the vehicle speed was it entered the network. getSpeedWithoutTraCI seems like the way to go, but when I use it getSpeedWithoutTraCI generates the same value as getSpeed. If In use setSpeed instead of set PreviousSpeed, I get a better behavior where decelerations seem reasonable but accelerations are extremely slow, or if the vehicle gets to a stop at a light it never reaccelerates.

Has any progress been made over the last year on that subject?

namdre commented 2 years ago

If the answer to both is "yes", then the problem may be in the values returned from your external model.

chambonp commented 2 years ago

if I don't feedback the modelled speed using setSpeed or setPreviousSpeed, the vehicle drives normally: in this case, it decelerates and stops at a red light, then proceeds to turn right when there is no traffic. when setting speed using setSpeed(vehID, getSpeedWithoutTraCI(vehID)), the vehicle doesn't drive the same way: it decelerates and stops at a red light, but it doesn't re-accelerate normally to turn right, it just creeps forward: it moves 1 or 2 meter over a minute or so and never moves any faster for the rest of the simulation.

chambonp commented 2 years ago

Here is a slight correction to my previous post: the vehicle doesn't creep for ever: 300seconds after stopping at the light, it suddenly jumps back to a normal speed and seems to behave normally. I got that behavior and timing on two different ego vehicles stopping at different times and locations on that network.

namdre commented 2 years ago

Can you attach a minimal example of your setup? (traci script and all files needed to run it).

chambonp commented 2 years ago

traci.vehicle.setSpeed(idStr, traci.vehicle.getSpeedWithoutTraCI(VehID)) doesn’t work: the vehicle stops at the light and never re-accelerates. But traci.vehicle.setPreviousSpeed(idStr, traci.vehicle.getSpeedWithoutTraCI(VehID)) does work: the vehicle stops at the light and re-accelerates normally.

As soon as I add a simple model to convert the Sumo target speed into an actual vehicle speed (targetspeed= getSpeedWithoutTraCI, speed =f(targetspeed) and setPreviousSpeed(speed)), the vehicle doesn’t behave normally: when using a first order filter vehicle model, it runs thru the light at high speed , and even goes unstable with a one sample delay model.

I am monitoring getSpeed() and getSpeedWithoutTraCI() values, I have not seen them to retrieve different values yet. How can I check that getSpeedWithoutTraCI is working properly?

by the way, I am using SUMO 1.12.0

I have prepared an simple example environment to demonstrate the behavior. how can I share it privately?

philippwulff commented 2 years ago

@PaulChambonUSA, These functions worked for me just as described above. Unfortunately, I do not know what is causing your issue from the report you give and I am not too familiar with this anymore.

When adding your own controller for the vehicle speed you need to think of the usage of setPreviousSpeed and moveTo as correcting the behaviour of the SUMO-internal vehicle control with the values that you want to set for the vehicle speed and location. I say correcting, because you do this after any given time step. Basically you correct the speed and position of the vehicle according to what you want it to be. I made these notes for myself back then, maybe they are of help to you:

Screenshot 2022-06-04 at 00 25 27

Also, you can write code within two "backwards apostrophes" ( ) such that it is easier to read, e.g.code`.

chambonp commented 2 years ago

@philippwulff, thanks for your input. I am still confused as to how it works. Based on the description of ''getSpeedWithoutTraci'', it seems that it should retrieve the speed command as if I hadn't overwritten the new desired speed using setSpeed' but I am yet to see a different value when using getSpeed and getSpeedWithoutTraci.

@namdre, how can I share my test environment with you?

namdre commented 2 years ago

The easiest way is to create a log of traci commands (https://sumo.dlr.de/docs/TraCI/Interfacing_TraCI_from_Python.html#generating_a_log_of_all_traci_commands) and then zip it up with all the simulation input files and attach it to this ticket. Alternatively send it to namdre.sumo at gmail.com

namdre commented 2 years ago

@PaulChambonUSA Here are my findings:

1) My previous suggestion of "does the vehicle drive in the same way as the uncontrolled vehicle when calling setSpeed(vehID, getSpeedWithoutTraCI(vehID)) in every step?" was faulty:

getSpeedWithoutTraCI retrieves the speed from the previous step and setSpeed sets the speed for the current step. This means, the actions being enforced this way are always lagging one simulation step behind it's unmodified behavior.

2) the tight update loop is not playing nicely with actionStepLength: when actionStepLength is active for a vehicle, it doesn't update it's desired speed in every step. Instead it computes a desired acceleration in every actionStep and expects to maintain this acceleration until the next actionStep. So when starting from a queue the first actionStep will compute a low desired speed because (just starting to accelerate). Calling setSpeed will then maintain this low speed until the speedWithoutTraCI is slightly increased once the next actionStep comes arround. Basically it divides the acceleration by stepLength/actionStepLength.

I think you could work around issue 2) by

chambonp commented 2 years ago

@namdre, my TraciAPI files do not define getLastActionTime and getActionStepLength. when I look on the repository: https://github.com/eclipse/sumo/blob/main/src/utils/traci/TraCIAPI.h, I don't see them either. where can I find them?

namdre commented 2 years ago

The code at utils/traci/TraCIAPI.h is no longer actively updated and only kept for backward compatibility. The recommended and feature-complete C++ API is libtraci. See https://sumo.dlr.de/docs/TraCI.html#interfaces_by_programming_language

If you want to do a pull request to add the two missing methods, thats also fine.

chambonp commented 2 years ago

I upgraded to libtraci.

I then reset the actionStepLength to 0.1 ( both in the vehicle distribution file and by using setActionStepLength() at each simulation step ). This way we make sure that the issue is not caused by actionStepLength. The behavior is unchanged.

I also tried to use setAccel during accelerations (and keep using setSpeed during decelerations since they seem to work) but the calculated accel is always very very small during accelerations, so the behavior is not much different.

It seems like getSpeedWithoutTraci never requests a re acceleration. Is there a way to look into what getSpeedWithoutTraci is doing to explain the lack of re-acceleration?

namdre commented 2 years ago

I found a bug! https://github.com/eclipse/sumo/issues/10947

Domsall commented 2 years ago

A few points from my side after looking into my Code again (I hope this helps):

  1. You first let the vehicle drive as if you were not controlling it: simulationStep() and use getSpeedWithoutTraCI() (VAR_SPEED_WITHOUT_TRACI) to get the actual speed.
  2. Then you do your calculations with this speed (although a first order filter model is very tricky... I did some experiments with such models back then and could not make them stable)
  3. After this, you correct the speed of the SUMO-vehicle with setPreviousSpeed(your_calculated_speed). The SUMO vehicle will then use this speed for the calculations in the next time step. Because the vehicle actually drove with a different speed in the last step, you will have to change its position, too (as if it had driven with setPreviousSpeed()). You can do this with moveToXY()/moveTo(). But you need to do the position/lane/route calulcations yourself. There should be an open issue on this moveTo-topic, too.
  4. simulationStep() now uses the speed from setPreviousSpeed() at the beginning of the step and calculates the new speed with the SUMO-model without any influence, which after the step can be read with getSpeedWithoutTraCI().

Further comments:

yougeyxt commented 8 months ago

Hi all, I am trying to do exactly what this issue wants to achieve: get the next SUMO speed or acceleration for a vehicle based on SUMO internal behavior models, then use external models to modify SUMO's output control and use movetoXY to update vehicle states.

I am using the 1.19.0 version, but getSpeedWithoutTraCI still cannot output a reasonable value. Are there any updates or suggestions?

namdre commented 8 months ago

are you using traci.executeMove allready? See #11091

yougeyxt commented 8 months ago

Thanks a lot for the quick response! I haven't, I will look into this and try it out.

yougeyxt commented 8 months ago

Hi @namdre, I tried traci.executeMove and have a few questions want to make sure. My current pipeline is:

  1. Use traci.executeMove to run "half" step of the simulation;
  2. Use getSpeedWithoutTraci to obtain the SUMO control;
  3. Based on SUMO control from step 2, my own logic will determine part of vehicles (say set A) controlled by my behavior model and the rest of vehicles (say set B) will use SUMO control;
  4. For vehicles in set A I will use traci.vehicle.moveToXY to update their states. For vehicles in set B I would like to keep SUMO's control.

My observations and questions are:

  1. I noticed that in some situations I need to add traci.vehicle.setSpeed(vehID, -1) (handle control back to SUMO) before traci.executeMove to obtain a reasonable output from step2. For example, for a vehicle stop in front of a intersection and the signal light turns from red to green, the getSpeedWithoutTraci will keep generating speed=0 if I did not add setSpeed(vehID, -1). Is that reasonable?
  2. The vehicle speed seems to have some issues. In the same example (after adding setSpeed), if I choose the control the vehicle and let it keep a standstill (using moveToXY), I find that when I fetch the vehicle speed in the next timestep it follows the SUMO controlled speed (say 1.5m/s) rather than 0, although it did not move as shown in the GUI as I want. Moreover, in the next timestep, the output from getSpeedWithoutTraci will keep increasing (for example 3m/s) as if the last step is controlled by SUMO, but I expect it to be 1.5m/s. Does that mean I need to manually patch the vehicle speed using setPreviousSpeed when using executeMove?

Thanks for the help!

yougeyxt commented 8 months ago

Hi @namdre, could you please take a look at this at your convenience? Thanks!