CARLA
Loading...
Searching...
No Matches
WalkerNavigation.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
8
14#include "carla/rpc/Command.h"
17
18#include <sstream>
19
20namespace carla {
21namespace client {
22namespace detail {
23
24 WalkerNavigation::WalkerNavigation(std::weak_ptr<Simulator> simulator, bool server_side)
25 : _simulator(simulator),
26 _next_check_index(0),
27 _server_side(server_side) {
28 _nav.SetSimulator(simulator);
29 if (_server_side) {
30 // The server hosts the navigation (World-Partitioned navmesh): no .bin
31 // navmesh is downloaded and the client-side Detour crowd stays empty.
32 return;
33 }
34 // Here call the server to retrieve the navmesh data.
35 auto files = _simulator.lock()->GetRequiredFiles("Nav");
36 if (!files.empty()) {
37 _nav.Load(_simulator.lock()->GetCacheFile(files[0], true));
38 }
39 }
40
41 void WalkerNavigation::Tick(std::shared_ptr<Episode> episode) {
42 if (_server_side) {
43 // Walkers are driven by the server's crowd; pushing client-side
44 // WalkerControl states here would fight the server controller.
45 return;
46 }
47 auto walkers = _walkers.Load();
48 if (walkers->empty()) {
49 return;
50 }
51
52 // get current state
53 std::shared_ptr<const EpisodeState> state = episode->GetState();
54
55 // purge all possible dead walkers
56 CheckIfWalkerExist(*walkers, *state);
57
58 // add/update/delete all vehicles in crowd
59 UpdateVehiclesInCrowd(episode, false);
60
61 // update crowd in navigation module
62 _nav.UpdateCrowd(*state);
63
65 using Cmd = rpc::Command;
66 std::vector<Cmd> commands;
67 commands.reserve(walkers->size());
68 for (auto handle : *walkers) {
69 // get the transform of the walker
70 if (_nav.GetWalkerTransform(handle.walker, trans)) {
71 float speed = _nav.GetWalkerSpeed(handle.walker);
72 commands.emplace_back(Cmd::ApplyWalkerState{ handle.walker, trans, speed });
73 }
74 }
75 _simulator.lock()->ApplyBatchSync(std::move(commands), false);
76
77 // check if any agent has been killed
78 bool alive;
79 for (auto handle : *walkers) {
80 // get the agent state
81 if (_nav.IsWalkerAlive(handle.walker, alive)) {
82 if (!alive) {
83 _simulator.lock()->SetActorCollisions(handle.walker, true);
84 _simulator.lock()->SetActorDead(handle.walker);
85 // remove from the crowd
86 _nav.RemoveAgent(handle.walker);
87 // destroy the controller
88 _simulator.lock()->DestroyActor(handle.controller);
89 // unregister from list
90 UnregisterWalker(handle.walker, handle.controller);
91 }
92 }
93 }
94 }
95
96 void WalkerNavigation::CheckIfWalkerExist(std::vector<WalkerHandle> walkers, const EpisodeState &state) {
97
98 // check with total
99 if (_next_check_index >= walkers.size())
101
102 // check the existence
103 if (!state.ContainsActorSnapshot(walkers[_next_check_index].walker)) {
104 // remove from the crowd
105 _nav.RemoveAgent(walkers[_next_check_index].walker);
106 // destroy the controller
107 _simulator.lock()->DestroyActor(walkers[_next_check_index].controller);
108 // unregister from list
109 UnregisterWalker(walkers[_next_check_index].walker, walkers[_next_check_index].controller);
110 }
111
113
114 }
115
116 // add/update/delete all vehicles in crowd
117 void WalkerNavigation::UpdateVehiclesInCrowd(std::shared_ptr<Episode> episode, bool show_debug) {
118 std::vector<carla::nav::VehicleCollisionInfo> vehicles;
119
120 // get current state
121 std::shared_ptr<const EpisodeState> state = episode->GetState();
122
123 // get all vehicles from episode
124 for (auto &&actor : episode->GetActors()) {
125 // only vehicles
126 if (actor.description.id.rfind("vehicle.", 0) == 0) {
127 // get the snapshot
128 ActorSnapshot snapshot = state->GetActorSnapshot(actor.id);
129 // add to the vector
130 vehicles.emplace_back(carla::nav::VehicleCollisionInfo{actor.id, snapshot.transform, actor.bounding_box});
131 }
132 }
133
134 // update the vehicles found
135 _nav.UpdateVehicles(vehicles);
136
137 // optional debug info
138 if (show_debug) {
139 if (_nav.GetCrowd() == nullptr) return;
140
141 // draw bounding boxes for debug
142 for (int i = 0; i < _nav.GetCrowd()->getAgentCount(); ++i) {
143 // get the agent
144 const dtCrowdAgent *agent = _nav.GetCrowd()->getAgent(i);
145 if (agent && agent->params.useObb) {
146 // draw for debug
147 carla::geom::Location p1, p2, p3, p4;
148 p1.x = agent->params.obb[0];
149 p1.z = agent->params.obb[1];
150 p1.y = agent->params.obb[2];
151 p2.x = agent->params.obb[3];
152 p2.z = agent->params.obb[4];
153 p2.y = agent->params.obb[5];
154 p3.x = agent->params.obb[6];
155 p3.z = agent->params.obb[7];
156 p3.y = agent->params.obb[8];
157 p4.x = agent->params.obb[9];
158 p4.z = agent->params.obb[10];
159 p4.y = agent->params.obb[11];
161 line1.life_time = 0.01f;
162 line1.persistent_lines = false;
163 // line 1
164 line1.primitive = carla::rpc::DebugShape::Line {p1, p2, 0.2f};
165 line1.color = { 0, 255, 0 };
166 _simulator.lock()->DrawDebugShape(line1);
167 // line 2
168 line1.primitive = carla::rpc::DebugShape::Line {p2, p3, 0.2f};
169 line1.color = { 255, 0, 0 };
170 _simulator.lock()->DrawDebugShape(line1);
171 // line 3
172 line1.primitive = carla::rpc::DebugShape::Line {p3, p4, 0.2f};
173 line1.color = { 0, 0, 255 };
174 _simulator.lock()->DrawDebugShape(line1);
175 // line 4
176 line1.primitive = carla::rpc::DebugShape::Line {p4, p1, 0.2f};
177 line1.color = { 255, 255, 0 };
178 _simulator.lock()->DrawDebugShape(line1);
179 }
180 }
181
182 // draw some text for debug
183 for (int i = 0; i < _nav.GetCrowd()->getAgentCount(); ++i) {
184 // get the agent
185 const dtCrowdAgent *agent = _nav.GetCrowd()->getAgent(i);
186 if (agent) {
187 // draw for debug
188 carla::geom::Location p1(agent->npos[0], agent->npos[2], agent->npos[1] + 1);
189 if (agent->params.userData) {
190 std::ostringstream out;
191 out << *(reinterpret_cast<const float *>(agent->params.userData));
193 text.life_time = 0.01f;
194 text.persistent_lines = false;
195 text.primitive = carla::rpc::DebugShape::String {p1, out.str(), false};
196 text.color = { 0, 255, 0 };
197 _simulator.lock()->DrawDebugShape(text);
198 }
199 }
200 }
201 }
202 }
203
204} // namespace detail
205} // namespace client
206} // namespace carla
Represents the state of all the actors of an episode at a given frame.
bool ContainsActorSnapshot(ActorId actor_id) const
void UpdateVehiclesInCrowd(std::shared_ptr< Episode > episode, bool show_debug=false)
add/update/delete all vehicles in crowd
void Tick(std::shared_ptr< Episode > episode)
void CheckIfWalkerExist(std::vector< WalkerHandle > walkers, const EpisodeState &state)
check a few walkers and if they don't exist then remove from the crowd
WalkerNavigation(std::weak_ptr< Simulator > simulator, bool server_side=false)
void UnregisterWalker(ActorId walker_id, ActorId controller_id)
A rigid transform in CARLA's / Unreal's left-handed frame: x forward, y right, z up,...
void UpdateCrowd(const client::detail::EpisodeState &state)
update all walkers in crowd
bool RemoveAgent(ActorId id)
remove an agent
float GetWalkerSpeed(ActorId id)
get the walker current transform
bool Load(const std::string &filename)
load navigation data
bool UpdateVehicles(std::vector< VehicleCollisionInfo > vehicles)
add/update/delete vehicles in crowd
bool GetWalkerTransform(ActorId id, carla::geom::Transform &trans)
get the walker current transform
bool IsWalkerAlive(ActorId id, bool &alive)
return if the agent has been killed by a vehicle
void SetSimulator(std::weak_ptr< carla::client::detail::Simulator > simulator)
reference to the simulator to access API functions
std::variant< Point, Line, Arrow, Box, String > primitive
Definition DebugShape.h:65
This file contains definitions of common data structures used in traffic manager.
struct to send info about vehicles to the crowd
Definition Navigation.h:47