MengeCrowdSim / Menge

The source code for the Menge crowd simulation framework
Apache License 2.0
138 stars 64 forks source link

Initial agents and obstacle placement #119

Open AdriannaGmz opened 5 years ago

AdriannaGmz commented 5 years ago

Hello, I'm having troubles creating a new simulation where I can place the obstacles and agents in specific positions. Specifically, as starting point, I'm modifying the tradeshow.xml simulation. Hence, to modify the placements of the agents and obstacles, I only modify the tradeshowS.xml in the agents and obstacles section. I have one problem with each of them:

`

        <Vertex p_x="7.5" p_y="7.5" />
        <Vertex p_x="10" p_y="0" />
        <Vertex p_x="7.5" p_y="-7.5" />
        <Vertex p_x="0" p_y="-10" />
        <Vertex p_x="-7.5" p_y="-7.5" />
        <Vertex p_x="-10" p_y="0" />
        <Vertex p_x="-7.5" p_y="7.5" />
        <Vertex p_x="0" p_y="10" />
    </Obstacle>

`

Thanks for the attention

curds01 commented 5 years ago

Editing the obstacles in tradeshow is going to blow up for you. The primary reason for that is because it uses a navigation mesh for finding paths and determining preferred velocity. The navigation mesh is not computed automatically from the obstacles -- it's explicitly encoded in the .nav file. That file format is rather arcane. So, arbitrarily changing the obstacle definitions is most likely going to cause problems.

By placing an agent at (15, -15) you've put them inside an obstacle and off the navigation mesh. That's what's causing your crash -- the program is complaining that it can't find a path for an agent that is off the mesh. The fact that it's a seg fault is a bug and I'll need to fix that.

So, on the whole, this is not going to be a very good workflow -- editing the tradeshow.

AdriannaGmz commented 5 years ago

Thank you very much for your answer!

According to what I read from #117 , Do I first need to create the navmesh? I want to use a scenario, which is already developed in Unreal Engine 4. From what I'm checking, I should be able to pull the navigation mesh defined in UE4. Could you tell me if this workflow seems right?:

please correct me if I'm wrong, any guidance will be very much appreciated,

curds01 commented 5 years ago

You have sketched out a nice workflow. Sadly, it doesn't exist. :(

The primary reason for this is the navigation mesh representation used by Menge is completely proprietary. (In other words, I made it up as I went along.) It was a format that relatively directly maps to the in-memory representation of the navigation mesh. No other program in the world would know how to read it (or write it, really).

The way I create a navigation mesh is to create a literal mesh in a modeling package of the walkable area. I export that mesh as an obj file and run it through one of my helpful utilities to convert it to a .nav file. It has long been my intention to make that better (including automatic nav mesh generation from obstacle definition, etc.) But right now, it's really clunky.

The good news is, if you have a navigation mesh file, you don't have to enumerate obstacles. The fact that tradeshow has both obstacles and a navigation mesh is an anachronism; it used to use a roadmap for navigation (so it required obstacles). But the beauty of the navigation mesh approach is that it inherently defines obstacles as well. I should probably update the tradeshow demo to be more consistent.

Even with a navigation mesh, there is a reason to want to have explicit obstacles of the same environment. My roadmapBuilder.py script knows how to read and visualize explicitly declared obstacles (but not navigation mesh obstacles) So, given an obstacle definition, you can place agents in the gui and export those positions to use in the scene specification file. That's really convenient for placing agents around the scene without having to guess what appropriate locations are.

So, that's the state of the art.

One alternative is to go back to a roadmap navigation (instead of navigation mesh). You can use the roadmapBuilder.py script to author a roadmap for a scene (given the obstacle definitions). It's easier to author a roadmap than a navigation mesh.

AdriannaGmz commented 5 years ago

Once again, thank you very much for your detailed explanation, I appreciate your honesty. ok, so, now I have three related questions:

  1. What is the benefit of using a navMesh? It seems like a hassle compared to only declare obstacles and agents, so I'd suppose there could be an extra benefit besides the "intrinsic" obstacles (?)

  2. What modeling program do you use to create the *.obj files that are the input to the your python script so you get the nav file?

  3. I'm still trying to understand why the agents walk-in the obstacles once as I described at the very beginning of this post. This time, in the tradeshow's Behaviour xml, I removed the navmesh and left only the goal as the velocity component: instead of

        <State name="Walk" final="0" >
            <GoalSelector type="random" goal_set="0" per_agent="1" />
            <VelComponent type="nav_mesh" file_name="carla_roundabout.nav" heading_threshold="5"/>
            <Action type="offset_property" property="priority" dist="c" value="0.0" exit_reset="0"/>
        </State>

    I have

        <State name="Walk" final="0" >
            <GoalSelector type="random" goal_set="0" per_agent="1" />
            <VelComponent type="goal"/>
            <Action type="offset_property" property="priority" dist="c" value="0.0" exit_reset="0"/>
        </State>

and still, when the agent faces the object, it enters to it and then gets trapped inside it. Here is a quick video

Hope not to bother that much.. and thanks!

curds01 commented 5 years ago

What is the benefit of using a navMesh?

Navigation meshes and roadmaps both represent "free space". The represent where agents can walk to get from point A to point B. Where they differ is how robust the representation is. Roadmaps are point samples connected by line segments. The only thing the roadmap knows is that the points and connecting line segments are collision free, but have no idea how much freespace surrounds it. Navigation meshes encapsulate the entire free space in a mesh of convex polygons. Because the polygons are convex, it can know that an agent can go from any point in a polygon to another point in the same polygon -- the whole space is available for planning. So, Navigation meshes give the planner more knowledge about what space is actually available to work in.

What modeling program do you use?

I've historically used Maya. This is primarily because I've been a Maya use for 20 years (since the first day it came out). However, I'll probably move over to Blender (open source vs licensed).

why the agents walk-in the obstacles

The definition of obstacles are piecewise, "one-sided" line segments. Each line segment defines "inside" and "outside". Agents can always pass through an obstacle from inside to outside (but not the other way around). The primary reason for this is that Menge (and crowd simulation in general) doesn't guarantee collision free behavior, so it must account for when inevitable, non-physical penetrations occur. When an agent gets pressed into an obstacle, this behavior lets it seamlessly move out of the obstacle again.

Given two vertices, p0 and p1, the obstacle formed by the pair (p0, p1) has a direction (p1 - p0) (pointing from p0 to p1). The right side of this vector is outside and the left side is inside. So, if you define the vertices of a polygon in counter-clockwise order, agents will stay on the outside. If you define them in a clockwise order, they'll stay inside.

If you want to experiment this, you can create a simple polygon around the origin, have an agent walk from top to bottom (or left to right), and then reverse the ordering of the vertices. You'll see two different behaviors.

In the case of the tradeshow, the obstacles you define have to agree with the navigation mesh. If they don't agree, weird things can happen. (Incidentally, the link to the video didn't work, so I can't see the weird behavior you're seeing.)

AdriannaGmz commented 5 years ago

Wow, thanks again for your quick answer! although, just a quickie this time

*What is the benefit of using a navMesh?* Navigation meshes and roadmaps both represent "free space"..

How do I create a roadmap in Menge? are they created by just defining agents and obstacle positions as in simpler examples such as circle or cross ?

I'm still trying to understand why the agents walk-in the obstacles once ..

I have it corrected now, as it was the declaration order of the vertices what made it work wrong. by declaring the vertices clockwisely, it made the obstacle work as Intended.

instead of        <State name="Walk" final="0" > ...   I have ...

I want to understand the implications of modifying the velocity component (Behaviour xml -->State-->VelComponent) in the way I exposed, by removing the navmesh and left alone with goal. Is this change what makes me go from using a navmesh to create internally a roadmap?

Thanks!

curds01 commented 5 years ago

How do I create a roadmap in Menge?

You can use the roadmapBuilder.py utility to create a roadmap. The work flow is as follows:

  1. Create your obstacles and save them in a ____S.xml file.
  2. Load the obstacles into roadmap builder as: python roadmapBuilder.py -b path/to/____S.xml
  3. Hit 'r' to enter the "graph context" (the bottom-right corner will say "graph edit"
  4. Left click to create vertices.
  5. Middle drag from one vertex to another to create a link. (Optionally, you can middle click-and-drag in one motion to create a vertex and connect it to another vertex in one action.)
  6. Hit Ctrl-s to save your roadmap to the same directory as roadmapBuilder.py under the name graph.txt.
  7. Copy graph.txt into the same directory as your ____S.xml file. This is the file you'll reference in creating a roadmap velocity component in your behavior file.
  8. Always remember to hit the h key to get context-specific help.

I have it corrected now...

Congrats!

I want to understand the implications of modifying the velocity component

In the code snippet you included above, the change from a navmesh velocity component to a goal velocity component is as follows: The goal velocity component is stupid -- it knows where the goal is relative to current position and will always try and walk directly toward the goal. That's fine if the obstacles are trivial (see the 4square example). However, if simulation environment is complex with local concavities, walking in the direction of the goal may end up with the agent getting trapped in corners. The navmesh (roadmap as well) velocity component can use the navigation mesh to plan a path around corners to the goal. I use the goal velocity component only in very simple scenarios. Roadmaps and navigation meshes are usually necessary in complex environments.

AdriannaGmz commented 5 years ago

I'm having difficulties generating the roadmap with the roadmapBuilder.py and need some help.. Content of the objS.xml file is:

<?xml version="1.0"?>
<Experiment version="2.0">
    <Common time_step="0.1" visible_neighbors="1" />
<Obstacle closed="1" boundingbox="0">
    <Vertex p_x="-0.180494" p_y="-4.075476" />
    <Vertex p_x="-0.180495" p_y="-2.075475" />
    <Vertex p_x="1.819505" p_y="-2.075475" />
    <Vertex p_x="1.819505" p_y="-4.075475" />
</Obstacle>
</Experiment>

Which as you see is a simple square. So, in Step 2, command line says:

Arguments:
    Input dir:  .
    Output dir: .
    obstacles:  /mnt/SSD512/fromUE/objS.xml
    agents:     
    road map:   
    field:      
    scbName:    
    Goals:      
READ OBSTACLES:  /mnt/SSD512/fromUE/objS.xml
Found 1 obstacles
Overal BB: BB: min <-0.180, -4.075,  0.000>, max < 1.820, -2.075,  0.000>

Adding context PositionContext to key q
Adding context GoalContext to key g
Adding context AgentContext to key a
Adding context ObstacleContext to key o

Which I assume is alright.. Problem is that , per Step 3, I keep pressing r but I never get into graph context, in fact nothing happens when I pressed r. By pressing h, I get the suggestions to press a, g, o, q which only take me to agent, goals, obstacle, or position but never graph. therefore I can not get to edit the graph ..

could you help me please?

thanks for the attention!

curds01 commented 5 years ago

It turns out it doesn't work because I lied. :-/ Well, actually, I was in a branch that I haven't merged into master yet. Oops. Sorry about that.

So, a slight change to making the roadmap. Here are the updated instructions.

  1. Create your obstacles and save them in a ____S.xml file.
  2. Load the obstacles into roadmap builder as: python roadmapBuilder.py -b path/to/____S.xml
  3. Hit 'e' to enter the "edit mode" (the top-left corner will say "edit roadmap"
  4. Left click to create vertices.
  5. Middle drag from one vertex to another to create a link. (Optionally, you can middle click-and-drag in one motion to create a vertex and connect it to another vertex in one action.)
  6. Hit Ctrl-s to save your roadmap to the same directory as roadmapBuilder.py under the name graph.txt.
  7. Copy graph.txt into the same directory as your ____S.xml file. This is the file you'll reference in creating a roadmap velocity component in your behavior file. ~Always remember to hit the h key to get context-specific help.~ The 'h' key doesn't work in this version for editing roadmaps; however, the instructions above all work.

By the way, I'm assuming when you launched roadmapBuilder.py as shown above, you could see the obstacle you'd defined, yes?

AdriannaGmz commented 5 years ago

Hi and thanks again! It seems now I have my graph.txt defined. I just drew 4 vertices linked with 3 edges outside from my square obstacle, so pretty light.

imag

Later, declared in Behaviour.xml the walk state as follows:

        <State name="Walk" final="0" >
            <GoalSelector type="random" goal_set="0" per_agent="1" />
            <VelComponent type="road_map" file_name="graph.txt"/>
        </State>

And then, when executed, menge crashes silently with segmentation fault. Would you be able to tell me where the problem is? I have a single square obstacle declared in S.xml, the one I loaded and do see when executing roadmapBuilder.py (in response to:

By the way, I'm assuming when you launched roadmapBuilder.py as shown above, you could see the obstacle you'd defined, yes?

) and that's it. :(

On the other hand.. would you please elaborate on the meaning of these fields? (this one, taken from bottleneck example)

<State name="Walk" final="0"><GoalSelector type="explicit" goal_set="0" goal="0"/><VelComponent type="road_map" file_name="bottleneckMap.txt"/></State>

Some are self-explanatory (like type) but what about goal_set = 0 for instance? Documentation is still in progress it seems..

I'm still testing around with the navigation mesh and have similar questions with the respective fields for navmesh as well.. (taken from bottleneck), what does heading threshold or offset property are for?

<State name="Walk" final="0"><GoalSelector type="random" goal_set="0" per_agent="1"/><VelComponent type="nav_mesh" file_name="tradeshow.nav" heading_threshold="5"/><Action type="offset_property" property="priority" dist="c" value="0.0" exit_reset="0"/></State>

as always, I really appreciate your help, guidance and support

curds01 commented 5 years ago

The easiest way for me to help debug your scene specification is for you to send them to me. (It'll also be the easiest way to find out why you're getting segfault -- which is definitely a bad bug. :() If you put them in gists, I can simply run them locally and see what the problems are.

As for the documentation, sorry about that. I'm way behind on my documentation efforts. I've got a branch with improved documentation but it hasn't made it to master yet. And, for the specific questions you asked, the documentation is particularly lacking.

  1. the GoalSelector element in the State

    • Some goal selectors work with pre-defined "goal sets" (if you look at the top of the behavior xml file, you'll see a <GoalSet> tag. The goal set has a unique identifier and contains one or more goals (each with an identifier unique in that set). In the case of the explicit goal selector you referenced in your question, it says, "Explicitly assign an agent entering this state the zero goal from the zero goal set."
  2. The nav_mesh VelocityComponent heading_threshold parameter

    • This is a bit more complicated. It's a threshold that balances using the most "best" path through the navigation mesh with computation cost. As this threshold goes to zero, the path becomes the best at the cost of a lot of recomputation. As it gets larger, you save computation, but the agent doesn't make as good use of the navigation mesh's free space.
    • I need to provide additional documentation to describe it more mathematically. But this is probably not the right venue (particularly as I have to review the details myself to make sure I get them right. :))
AdriannaGmz commented 5 years ago

thanks!

Here is the link to the gist , your watchful eye will be much appreciated! _Of course, the B, S, V xmls and graph.txt are inside a folder named carla_roundabout. This folder is at the same level as carlaroundabout.xml and as for the velocity component features is about, I'll check them a little later when I have first this dummy test working :P Thank you!

curds01 commented 5 years ago

I won't be able to delve into this into later today. But I promise I'll get you some feedback on this some time today. (Today in California time, that is.)

AdriannaGmz commented 5 years ago

Oh, don't worry, the project with road_map is now working fine, I've reset the machine and redid the whole process. Now is executing although I don't quite understand why the agents move like that.. they get stuck in the square obstacle and can not see clearly the road_map function

On the other hand, I have another gists for the navmesh setup: with the same simple definition for the obstacle, I executed the objToNavMesh.py (test.obj is also included in the gists) and generated test.nav after this, I referenced to this file in the B.xml and the simulator crashed.

I'm conscious about the disclaimer in objToNavMesh.py in which it warns about a delicate treatment.. however , as you see, the obj file indicates a very simple shape (a small) square

Thanks for the attention and yeah, take your time ;)

curds01 commented 5 years ago

Some thoughts:

Things you might not be aware of:

I looked at the roadmap version:

Navmesh version

AdriannaGmz commented 5 years ago

thank you very much for your insight! now, everything with this dummy example and the roadmap is clear and working :) however... with the navmesh project i still have some concerns

Yeah, it is true that the obj file refers to two overlapping cubes but as I understood, the ObjSlice.py (that creates the obj.xml for the roadmap) "slices" with these shapes with a plane (defined by -p), so, when the overlapping cubes are "sliced" , it would throw the profile of the single square that gets in the middle of that plane. is it right? if so, I understood that something similar would be performed with the objToNavMesh.pyi.e. the obj file would be sliced and then would throw the square profile in its own navmesh format... please correct me if I'm wrong

As I still have aside questions regarding the mengeUtils , I am opening this other thread, although I would appreciate if you could clarify the above questions/statements.

curds01 commented 5 years ago

The problem is that you have envisioned a useful, intelligent, general tool. Those utilities are none of the above. :( They're a bunch of things I hacked together to make the smallest jump between point A and point B.

ObjSlice.py isn't as smart as you would hope:


 _________                                    _________
|         |                                  |         |
|     ____|____                              |         |____
|    |    |    |                             |              |
|    |    |    |   --> What you want -->     |              |
|____|____|    |                             |______        |
     |         |                                    |       |
     |_________|                                    |_______|

But that's not what you get. What you get is two rectangular series that run through each other. It would probably have the same effect, but still be a bit different.

As for the objToNavMesh.py, it's not smart at all. It has no smarts for figuring out what a nav mesh is based on a scene. It is much simpler than that. It simply translates an existing navigation mesh from one format (obj) to another (nav). That means, someone or something already went through the neighborhood and created a mesh consisting of convex, planar polygons that spans the walkable space. Furthermore, the conversion is really sensitive to the quality of the mesh and gives bad error messages if it doesn't like the quality. Painful, I know.

Does that help clarify?

tcjcxy30 commented 3 years ago

Hi: Where is the roadmapBuilder.py?

curds01 commented 3 years ago

@CxyCH they're a bunch of informal utilities located at https://github.com/curds01/MengeUtils. They're sparsely documented and only run with python 2. I'm currently on updating them to python 3 (including meaningful tests).