Working on pedestrian movement

This commit is contained in:
bernatx 2019-06-03 15:55:07 +02:00 committed by Néstor Subirón
parent 42a4ea0eb7
commit 007f9c7122
12 changed files with 262 additions and 165 deletions

View File

@ -100,12 +100,6 @@ namespace client {
return _simulator->ApplyBatchSync(std::move(commands), do_tick_cue);
}
std::vector<carla::geom::Location> CreateWalker(
carla::geom::Location From,
carla::geom::Location To) const {
return _simulator->CreateWalker(From, To);
};
private:
std::shared_ptr<detail::Simulator> _simulator;

View File

@ -19,7 +19,8 @@ namespace client {
}
void WalkerAIController::GoToLocation(const carla::geom::Location &destination) {
auto nav = GetEpisode().Lock()->GetNavigation();
nav->SetWalkerTarget(GetParent()->GetId(), destination);
logging::log("GO TO LOCATION:", destination.x, destination.y, destination.z);
}

View File

@ -7,6 +7,7 @@
#pragma once
#include "carla/client/Actor.h"
#include "carla/client/detail/WalkerNavigation.h"
#include "carla/geom/Vector3D.h"
namespace carla {
@ -22,7 +23,6 @@ namespace client {
void GoToLocation(const carla::geom::Location &destination);
void SetMaxSpeed(const float max_speed);
};
} // namespace client

View File

@ -52,6 +52,12 @@ namespace detail {
std::shared_ptr<WalkerNavigation> CreateNavigationIfMissing();
std::shared_ptr<WalkerNavigation> GetNavigation() const {
auto nav = _navigation.load();
DEBUG_ASSERT(nav != nullptr);
return nav;
}
void RegisterActor(rpc::Actor actor) {
_actors.Insert(std::move(actor));
}

View File

@ -19,6 +19,7 @@
#include "carla/client/detail/Client.h"
#include "carla/client/detail/Episode.h"
#include "carla/client/detail/EpisodeProxy.h"
#include "carla/client/detail/WalkerNavigation.h"
#include "carla/profiler/LifetimeProfiled.h"
#include "carla/rpc/TrafficLightState.h"
@ -181,6 +182,10 @@ namespace detail {
void RegisterAIController(const WalkerAIController &controller);
std::shared_ptr<WalkerNavigation> GetNavigation() {
return _episode->GetNavigation();
}
/// @}
// =========================================================================
/// @name General operations with actors
@ -342,12 +347,6 @@ namespace detail {
_client.SetReplayerTimeFactor(time_factor);
}
std::vector<carla::geom::Location> CreateWalker(
carla::geom::Location From,
carla::geom::Location To) const {
return _client.CreateWalker(From, To);
};
/// @}
// =========================================================================
/// @name Operations with walkers

View File

@ -14,34 +14,38 @@ namespace carla {
namespace client {
namespace detail {
static geom::Transform TickWalker(
const float delta_seconds,
geom::Transform transform) {
transform.location += delta_seconds * 2.778f * transform.GetForwardVector();
return transform;
}
WalkerNavigation::WalkerNavigation(Client &client) : _client(client) {
// Here call the server to retrieve the navmesh data.
_nav.Load(_client.GetNavigationMesh());
// query the navigation to find a path of points
// std::vector<carla::geom::Location> Path;
// if (!_nav.GetPath(From, To, nullptr, Path)) {
// logging::log("NAV: Path not found");
// }
// return Path;
}
void WalkerNavigation::Tick(const EpisodeState &state) const {
void WalkerNavigation::Tick(const EpisodeState &state) {
auto walkers = _walkers.Load();
if (walkers->empty()) {
return;
}
// update crowd in navigation module
_nav.UpdateCrowd(state);
carla::geom::Transform trans;
using Cmd = rpc::Command;
std::vector<Cmd> commands;
commands.reserve(walkers->size());
for (auto handle : *walkers) {
commands.emplace_back(
Cmd::ApplyTransform{
handle.walker,
TickWalker(
static_cast<float>(state.GetTimestamp().delta_seconds),
state.GetActorState(handle.walker).transform)});
// get the transform of the walker
if (_nav.GetWalkerTransform(handle.walker, trans)) {
// logging::log("Nav: walker at ", trans.location.x, trans.location.y, trans.location.z);
commands.emplace_back(Cmd::ApplyTransform{ handle.walker, trans });
}
}
_client.ApplyBatch(std::move(commands), false);

View File

@ -7,6 +7,7 @@
#pragma once
#include "carla/AtomicList.h"
#include "carla/nav/Navigation.h"
#include "carla/NonCopyable.h"
#include "carla/client/Timestamp.h"
#include "carla/client/detail/EpisodeProxy.h"
@ -29,15 +30,26 @@ namespace detail {
explicit WalkerNavigation(Client &client);
void RegisterWalker(ActorId walker_id, ActorId controller_id) {
_walkers.Push(WalkerHandle{walker_id, controller_id});
// add to list
_walkers.Push(WalkerHandle { walker_id, controller_id });
// create the walker in the crowd (to manage its movement in Detour)
_nav.AddWalker(walker_id);
}
void Tick(const EpisodeState &episode_state) const;
void Tick(const EpisodeState &episode_state);
// set a new target point to go
bool SetWalkerTarget(ActorId id, carla::geom::Location to) {
return _nav.SetWalkerTarget(id, to);
}
private:
Client &_client;
carla::nav::Navigation _nav;
struct WalkerHandle {
ActorId walker;
ActorId controller;

View File

@ -23,9 +23,9 @@ namespace nav {
}
Navigation::~Navigation() {
dtFreeCrowd(Crowd);
dtFreeNavMeshQuery(NavQuery);
dtFreeNavMesh(NavMesh);
dtFreeCrowd(_crowd);
dtFreeNavMeshQuery(_navQuery);
dtFreeNavMesh(_navMesh);
}
// load navigation data
@ -37,15 +37,15 @@ namespace nav {
f.open(filename, std::ios::binary);
if (!f.is_open())
return false;
std::vector<uint8_t> Content(start, end);
std::vector<uint8_t> content(start, end);
f.close();
// parse the content
return Load(Content);
return Load(content);
}
// load navigation data from memory
bool Navigation::Load(const std::vector<uint8_t> Content) {
bool Navigation::Load(const std::vector<uint8_t> content) {
const int NAVMESHSET_MAGIC = 'M'<<24 | 'S'<<16 | 'E'<<8 | 'T'; //'MSET';
const int NAVMESHSET_VERSION = 1;
#pragma pack(push, 1)
@ -62,9 +62,9 @@ namespace nav {
#pragma pack(pop)
// read the file header
unsigned long Pos = 0;
memcpy(&header, &Content[Pos], sizeof(header));
Pos += sizeof(header);
unsigned long pos = 0;
memcpy(&header, &content[pos], sizeof(header));
pos += sizeof(header);
// check file magic and version
if (header.magic != NAVMESHSET_MAGIC || header.version != NAVMESHSET_VERSION) {
@ -84,9 +84,9 @@ namespace nav {
NavMeshTileHeader tileHeader;
// read the tile header
memcpy(&tileHeader, &Content[Pos], sizeof(tileHeader));
Pos += sizeof(tileHeader);
if (Pos >= Content.size()) {
memcpy(&tileHeader, &content[pos], sizeof(tileHeader));
pos += sizeof(tileHeader);
if (pos >= content.size()) {
dtFreeNavMesh(mesh);
return false;
}
@ -101,9 +101,9 @@ namespace nav {
// read the tile
memset(data, 0, static_cast<size_t>(tileHeader.dataSize));
memcpy(data, &Content[Pos], static_cast<size_t>(tileHeader.dataSize));
Pos += static_cast<unsigned long>(tileHeader.dataSize);
if (Pos > Content.size()) {
memcpy(data, &content[pos], static_cast<size_t>(tileHeader.dataSize));
pos += static_cast<unsigned long>(tileHeader.dataSize);
if (pos > content.size()) {
dtFree(data);
dtFreeNavMesh(mesh);
return false;
@ -114,72 +114,72 @@ namespace nav {
}
// exchange
dtFreeNavMesh(NavMesh);
NavMesh = mesh;
dtFreeNavMesh(_navMesh);
_navMesh = mesh;
// prepare the query object
dtFreeNavMeshQuery(NavQuery);
NavQuery = dtAllocNavMeshQuery();
NavQuery->init(NavMesh, 2048);
dtFreeNavMeshQuery(_navQuery);
_navQuery = dtAllocNavMeshQuery();
_navQuery->init(_navMesh, 2048);
// create and init the crowd manager
CreateCrowd();
// copy
BinaryMesh = Content;
_binaryMesh = content;
return true;
}
void Navigation::CreateCrowd(void) {
if (Crowd != nullptr)
if (_crowd != nullptr)
return;
// create and init
Crowd = dtAllocCrowd();
Crowd->init(MAX_AGENTS, AGENT_RADIUS, NavMesh);
_crowd = dtAllocCrowd();
_crowd->init(MAX_AGENTS, AGENT_RADIUS, _navMesh);
// make polygons with 'disabled' flag invalid
Crowd->getEditableFilter(0)->setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
_crowd->getEditableFilter(0)->setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
// Setup local avoidance params to different qualities.
dtObstacleAvoidanceParams Params;
dtObstacleAvoidanceParams params;
// Use mostly default settings, copy from dtCrowd.
memcpy(&Params, Crowd->getObstacleAvoidanceParams(0), sizeof(dtObstacleAvoidanceParams));
memcpy(&params, _crowd->getObstacleAvoidanceParams(0), sizeof(dtObstacleAvoidanceParams));
// Low (11)
Params.velBias = 0.5f;
Params.adaptiveDivs = 5;
Params.adaptiveRings = 2;
Params.adaptiveDepth = 1;
Crowd->setObstacleAvoidanceParams(0, &Params);
params.velBias = 0.5f;
params.adaptiveDivs = 5;
params.adaptiveRings = 2;
params.adaptiveDepth = 1;
_crowd->setObstacleAvoidanceParams(0, &params);
// Medium (22)
Params.velBias = 0.5f;
Params.adaptiveDivs = 5;
Params.adaptiveRings = 2;
Params.adaptiveDepth = 2;
Crowd->setObstacleAvoidanceParams(1, &Params);
params.velBias = 0.5f;
params.adaptiveDivs = 5;
params.adaptiveRings = 2;
params.adaptiveDepth = 2;
_crowd->setObstacleAvoidanceParams(1, &params);
// Good (45)
Params.velBias = 0.5f;
Params.adaptiveDivs = 7;
Params.adaptiveRings = 2;
Params.adaptiveDepth = 3;
Crowd->setObstacleAvoidanceParams(2, &Params);
params.velBias = 0.5f;
params.adaptiveDivs = 7;
params.adaptiveRings = 2;
params.adaptiveDepth = 3;
_crowd->setObstacleAvoidanceParams(2, &params);
// High (66)
Params.velBias = 0.5f;
Params.adaptiveDivs = 7;
Params.adaptiveRings = 3;
Params.adaptiveDepth = 3;
params.velBias = 0.5f;
params.adaptiveDivs = 7;
params.adaptiveRings = 3;
params.adaptiveDepth = 3;
Crowd->setObstacleAvoidanceParams(3, &Params);
_crowd->setObstacleAvoidanceParams(3, &params);
}
// return the path points to go from one position to another
bool Navigation::GetPath(const carla::geom::Location From, const carla::geom::Location To, dtQueryFilter* Filter, std::vector<carla::geom::Location> &Path) {
bool Navigation::GetPath(const carla::geom::Location from, const carla::geom::Location to, dtQueryFilter* filter, std::vector<carla::geom::Location> &path) {
// path found
float m_straightPath[MAX_POLYS*3];
unsigned char m_straightPathFlags[MAX_POLYS];
@ -190,9 +190,9 @@ namespace nav {
dtPolyRef m_polys[MAX_POLYS];
int m_npolys;
// check to load the binary navmesh from server
logging::log("Nav: ", BinaryMesh.size());
if (BinaryMesh.size() == 0) {
// check to load the binary _navMesh from server
logging::log("Nav: ", _binaryMesh.size());
if (_binaryMesh.size() == 0) {
return false;
}
@ -203,26 +203,26 @@ namespace nav {
m_polyPickExt[2] = 2;
// filter
dtQueryFilter m_filter;
if (Filter == nullptr) {
m_filter.setIncludeFlags(SAMPLE_POLYFLAGS_ALL ^ SAMPLE_POLYFLAGS_DISABLED);
m_filter.setExcludeFlags(0);
Filter = &m_filter;
dtQueryFilter filter2;
if (filter == nullptr) {
filter2.setIncludeFlags(SAMPLE_POLYFLAGS_ALL ^ SAMPLE_POLYFLAGS_DISABLED);
filter2.setExcludeFlags(0);
filter = &filter2;
}
// set the points
dtPolyRef m_startRef = 0;
dtPolyRef m_endRef = 0;
float m_spos[3] = { From.x, From.z, From.y };
float m_epos[3] = { To.x, To.z, To.y };
NavQuery->findNearestPoly(m_spos, m_polyPickExt, Filter, &m_startRef, 0);
NavQuery->findNearestPoly(m_epos, m_polyPickExt, Filter, &m_endRef, 0);
float m_spos[3] = { from.x, from.z, from.y };
float m_epos[3] = { to.x, to.z, to.y };
_navQuery->findNearestPoly(m_spos, m_polyPickExt, filter, &m_startRef, 0);
_navQuery->findNearestPoly(m_epos, m_polyPickExt, filter, &m_endRef, 0);
if (!m_startRef || !m_endRef) {
return false;
}
// get the path of nodes
NavQuery->findPath(m_startRef, m_endRef, m_spos, m_epos, Filter, m_polys, &m_npolys, MAX_POLYS);
_navQuery->findPath(m_startRef, m_endRef, m_spos, m_epos, filter, m_polys, &m_npolys, MAX_POLYS);
// get the path of points
m_nstraightPath = 0;
@ -234,100 +234,122 @@ namespace nav {
float epos[3];
dtVcopy(epos, m_epos);
if (m_polys[m_npolys-1] != m_endRef)
NavQuery->closestPointOnPoly(m_polys[m_npolys-1], m_epos, epos, 0);
_navQuery->closestPointOnPoly(m_polys[m_npolys-1], m_epos, epos, 0);
// get the points
NavQuery->findStraightPath(m_spos, epos, m_polys, m_npolys,
_navQuery->findStraightPath(m_spos, epos, m_polys, m_npolys,
m_straightPath, m_straightPathFlags,
m_straightPathPolys, &m_nstraightPath, MAX_POLYS, m_straightPathOptions);
// copy the path to the output buffer
Path.clear();
Path.reserve(static_cast<unsigned long>(m_nstraightPath));
path.clear();
path.reserve(static_cast<unsigned long>(m_nstraightPath));
for (int i=0; i<m_nstraightPath*3; i+=3) {
// export for Unreal axis (x, z, y)
Path.emplace_back(m_straightPath[i], m_straightPath[i+2], m_straightPath[i+1]);
path.emplace_back(m_straightPath[i], m_straightPath[i+2], m_straightPath[i+1]);
}
return true;
}
// create a new walker
bool Navigation::AddWalker(ActorId Id, carla::geom::Location From) {
dtCrowdAgentParams Params;
// create a new walker but not yet add in crowd
void Navigation::AddWalker(ActorId id) {
// add to the queue to be added later and next tick where we can access the transform
_walkersQueueToAdd.push_back(id);
}
if (Crowd == nullptr) {
// create a new walker in crowd
bool Navigation::AddWalkerInCrowd(ActorId id, carla::geom::Location from) {
dtCrowdAgentParams params;
if (_crowd == nullptr) {
return false;
}
// set parameters
memset(&Params, 0, sizeof(Params));
Params.radius = AGENT_RADIUS;
Params.height = AGENT_HEIGHT;
Params.maxAcceleration = 8.0f;
Params.maxSpeed = 3.5f;
Params.collisionQueryRange = Params.radius * 12.0f;
Params.pathOptimizationRange = Params.radius * 30.0f;
memset(&params, 0, sizeof(params));
params.radius = AGENT_RADIUS;
params.height = AGENT_HEIGHT;
params.maxAcceleration = 8.0f;
params.maxSpeed = 3.5f;
params.collisionQueryRange = params.radius * 12.0f;
params.pathOptimizationRange = params.radius * 30.0f;
// flags
Params.updateFlags = 0;
Params.updateFlags |= DT_CROWD_ANTICIPATE_TURNS;
Params.updateFlags |= DT_CROWD_OPTIMIZE_VIS;
Params.updateFlags |= DT_CROWD_OPTIMIZE_TOPO;
Params.updateFlags |= DT_CROWD_OBSTACLE_AVOIDANCE;
Params.updateFlags |= DT_CROWD_SEPARATION;
Params.obstacleAvoidanceType = 3;
Params.separationWeight = 2.0;
params.updateFlags = 0;
params.updateFlags |= DT_CROWD_ANTICIPATE_TURNS;
params.updateFlags |= DT_CROWD_OPTIMIZE_VIS;
params.updateFlags |= DT_CROWD_OPTIMIZE_TOPO;
params.updateFlags |= DT_CROWD_OBSTACLE_AVOIDANCE;
params.updateFlags |= DT_CROWD_SEPARATION;
params.obstacleAvoidanceType = 3;
params.separationWeight = 2.0;
// add walker
float PointFrom[3] = { From.x, From.y, From.z };
int Index = Crowd->addAgent(PointFrom, &Params);
if (Index != -1) {
float PointFrom[3] = { from.x, from.y, from.z };
int index = _crowd->addAgent(PointFrom, &params);
if (index != -1) {
// save the id
MappedId[Id] = Index;
_mappedId[id] = index;
}
return true;
}
// set a new target point to go
bool Navigation::SetWalkerTarget(ActorId Id, carla::geom::Location To) {
bool Navigation::SetWalkerTarget(ActorId id, carla::geom::Location to) {
// get the internal index
auto It = MappedId.find(Id);
if (It == MappedId.end())
auto it = _mappedId.find(id);
if (it == _mappedId.end())
return false;
// get the index found
int Index = It->second;
if (Index != -1) {
int index = it->second;
if (index == -1)
return false;
// set target position
float PointTo[3] = { To.x, To.y, To.z };
float Nearest[3];
const dtQueryFilter *Filter = Crowd->getFilter(0);
dtPolyRef TargetRef;
NavQuery->findNearestPoly(PointTo, Crowd->getQueryHalfExtents(), Filter, &TargetRef, Nearest);
if (TargetRef)
Crowd->requestMoveTarget(Index, TargetRef, PointTo);
}
logging::log("Nav: ", index, it->first);
// set target position
float pointTo[3] = { to.x, to.y, to.z };
float nearest[3];
const dtQueryFilter *filter = _crowd->getFilter(0);
dtPolyRef targetRef;
_navQuery->findNearestPoly(pointTo, _crowd->getQueryHalfExtents(), filter, &targetRef, nearest);
if (targetRef)
_crowd->requestMoveTarget(index, targetRef, pointTo);
return true;
}
// update all walkers in crowd
void Navigation::UpdateCrowd(float DeltaTime) {
void Navigation::UpdateCrowd(const client::detail::EpisodeState &state) {
if (!NavMesh || !Crowd) {
if (!_navMesh || !_crowd) {
return;
}
// update all
Crowd->update(DeltaTime, nullptr);
// check if we have more walkers in the queue to add
while (_walkersQueueToAdd.size() > 0) {
// add it
ActorId id = _walkersQueueToAdd.back();
carla::geom::Transform trans = state.GetActorState(id).transform;
trans.location.z -= (AGENT_HEIGHT / 2.0f);
if (!AddWalkerInCrowd(id, trans.location)) {
break;
}
// remove it
_walkersQueueToAdd.pop_back();
}
// update all
double deltaTime = state.GetTimestamp().delta_seconds;
_crowd->update(static_cast<float>(deltaTime), nullptr);
/*
// get all walker positions
for (int i = 0; i < Crowd->getAgentCount(); ++i)
for (int i = 0; i < _crowd->getAgentCount(); ++i)
{
const dtCrowdAgent* ag = Crowd->getAgent(i);
const dtCrowdAgent* ag = _crowd->getAgent(i);
if (!ag->active)
continue;
@ -336,6 +358,33 @@ namespace nav {
// trail->htrail = (trail->htrail + 1) % AGENT_MAX_TRAIL;
// dtVcopy(&trail->trail[trail->htrail*3], ag->npos);
}
*/
}
// get the walker current transform
bool Navigation::GetWalkerTransform(ActorId id, carla::geom::Transform &trans) {
// get the internal index
auto it = _mappedId.find(id);
if (it == _mappedId.end())
return false;
// get the index found
int index = it->second;
if (index == -1)
return false;
// get the walker
const dtCrowdAgent *agent = _crowd->getAgent(index);
// set its position
trans.location.x = agent->npos[0];
trans.location.y = agent->npos[2];
trans.location.z = agent->npos[1] + (AGENT_HEIGHT / 2.0f);
// set its rotation
trans.rotation.pitch = asin(agent->nvel[2]);
trans.rotation.yaw = asin(agent->nvel[0]);
trans.rotation.roll = 0;
return true;
}
} // namespace nav

View File

@ -6,8 +6,10 @@
#pragma once
#include "carla/rpc/ActorId.h"
#include "carla/client/detail/EpisodeState.h"
#include "carla/geom/Location.h"
#include "carla/geom/Transform.h"
#include "carla/rpc/ActorId.h"
#include "recast/Recast.h"
#include "recast/DetourCrowd.h"
#include "recast/DetourNavMesh.h"
@ -51,30 +53,35 @@ namespace nav {
Navigation();
~Navigation();
// load navigation data
bool Load(const std::string Filename);
bool Load(const std::string filename);
// load navigation data from memory
bool Load(const std::vector<uint8_t> Content);
bool Load(const std::vector<uint8_t> content);
// return the path points to go from one position to another
bool GetPath(const carla::geom::Location From, const carla::geom::Location To, dtQueryFilter* Filter, std::vector<carla::geom::Location> &Path);
bool GetPath(const carla::geom::Location from, const carla::geom::Location to, dtQueryFilter* filter, std::vector<carla::geom::Location> &path);
// create the crowd object
void CreateCrowd(void);
// add a walker
bool AddWalker(ActorId Id, carla::geom::Location From);
// create a new walker but not yet add in crowd
void AddWalker(ActorId id);
// create a new walker in crowd
bool AddWalkerInCrowd(ActorId id, carla::geom::Location from);
// set a new target point to go
bool SetWalkerTarget(ActorId Id, carla::geom::Location To);
bool SetWalkerTarget(ActorId id, carla::geom::Location to);
// get the walker current transform
bool GetWalkerTransform(ActorId id, carla::geom::Transform &trans);
// update all walkers in crowd
void UpdateCrowd(float DeltaTime);
void UpdateCrowd(const client::detail::EpisodeState &state);
private:
std::vector<uint8_t> BinaryMesh;
std::vector<uint8_t> _binaryMesh;
std::vector<ActorId> _walkersQueueToAdd;
// meshes
dtNavMesh *NavMesh { nullptr };
dtNavMeshQuery *NavQuery { nullptr };
dtNavMesh *_navMesh { nullptr };
dtNavMeshQuery *_navQuery { nullptr };
// crowd
dtCrowd *Crowd { nullptr };
dtCrowd *_crowd { nullptr };
// mapping Id
std::unordered_map<ActorId, int> MappedId;
std::unordered_map<ActorId, int> _mappedId;
};
} // namespace nav

View File

@ -39,6 +39,7 @@ def get_libcarla_extensions():
os.path.join(pwd, 'dependencies/lib/libboost_filesystem.a'),
os.path.join(pwd, 'dependencies/lib/libRecast.a'),
os.path.join(pwd, 'dependencies/lib/libDetour.a'),
os.path.join(pwd, 'dependencies/lib/libDetourCrowd.a'),
os.path.join(pwd, 'dependencies/lib', pylib)]
extra_compile_args = [
'-isystem', 'dependencies/include/system', '-fPIC', '-std=c++14',

View File

@ -71,6 +71,5 @@ void export_client() {
.def("set_replayer_time_factor", &cc::Client::SetReplayerTimeFactor, (arg("time_factor")))
.def("apply_batch", &ApplyBatchCommands, (arg("commands"), arg("do_tick")=false))
.def("apply_batch_sync", &ApplyBatchCommandsSync, (arg("commands"), arg("do_tick")=false))
.def("create_walker", CALL_RETURNING_LIST_2(cc::Client, CreateWalker, carla::geom::Location, carla::geom::Location), (arg("location"), arg("location")))
;
}

View File

@ -55,17 +55,42 @@ def main():
world = client.get_world()
m = world.get_map()
debug = world.debug
a = carla.Location(-141.789, -143.839, 0.139954)
b = carla.Location(-29.7504, -26.8764, 0.270432)
points = []
points = client.create_walker(a, b)
for i in range(len(points)-1):
a1 = carla.Location(points[i].x, points[i].y, points[i].z)
b1 = carla.Location(points[i+1].x, points[i+1].y, points[i+1].z)
# print(a.x, a.y, a.z)
debug.draw_line(a1, b1, color=orange, thickness=0.5, life_time=12)
# debug.draw_line(a, a+carla.Location(z=1000), color=orange, thickness=0.2, life_time=12)
debug.draw_point(a1, 1, red, 12)
spawn_point = carla.Transform()
spawn_point.location.x = -18
spawn_point.location.y = 1.2
spawn_point.location.z = 18
spawn_point.rotation.roll = 0.0
spawn_point.rotation.pitch = 0.0
# player
# print(world.get_blueprint_library())
# exit(1)
blueprint = random.choice(world.get_blueprint_library().filter('walker.pedestrian.0002'))
player = world.spawn_actor(blueprint, spawn_point)
# controller
blueprint = random.choice(world.get_blueprint_library().filter('controller.ai.walker'))
walker_controller = world.spawn_actor(blueprint, spawn_point, attach_to=player)
walker_controller.start()
time.sleep(0.5)
walker_controller.go_to_location(carla.Location(-48, 1.2, 27))
# walker_controller.set_max_speed(40)
while (1):
time.sleep(1);
# a = carla.Location(-141.789, -143.839, 0.139954)
# b = carla.Location(-29.7504, -26.8764, 0.270432)
# points = []
# points = client.create_walker(a, b)
# for i in range(len(points)-1):
# a1 = carla.Location(points[i].x, points[i].y, points[i].z)
# b1 = carla.Location(points[i+1].x, points[i+1].y, points[i+1].z)
# # print(a.x, a.y, a.z)
# debug.draw_line(a1, b1, color=orange, thickness=0.5, life_time=12)
# # debug.draw_line(a, a+carla.Location(z=1000), color=orange, thickness=0.2, life_time=12)
# debug.draw_point(a1, 1, red, 12)
finally:
pass