Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an python example to change speeds #502

Merged
merged 34 commits into from
Aug 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
10768dc
Remove GetAgentById.
clalancette Jul 5, 2018
ab86154
Small include fixups.
clalancette Jul 11, 2018
2bccea3
Add py::keep_alive to the constructors for the classes.
clalancette Jul 11, 2018
1c1d411
Remove a now obsolete comment.
clalancette Jul 11, 2018
5c5550a
Add in a simple velocity controller.
clalancette Jul 11, 2018
8c4e00d
Increase the nominal (max) speed allowed for the rail cars.
clalancette Jul 11, 2018
66b8e30
Connect up a ConstantVectorSource to the Velocity Controller.
clalancette Jul 11, 2018
736f7a0
Rename get_current_simulation_time -> GetCurrentSimulationTime.
clalancette Jul 12, 2018
ee39e81
Expose get_current_simulation_time to the python API.
clalancette Jun 28, 2018
2b2844f
Change return value of GetDiagram and expose to Python.
clalancette Jul 12, 2018
5629b97
Add GetMutableContext, and expose to python.
clalancette Jul 12, 2018
b0916de
Add a SetVelocity call to the RailCar.
clalancette Jul 12, 2018
a514c9c
Make sure to return the agent pointer from add_rail_car.
clalancette Jul 12, 2018
5150ecf
Add a new demo to show off changing the speed over time.
clalancette Jul 12, 2018
290ad4d
Switch to using a class for monitoring the timeout.
clalancette Jul 12, 2018
59cc0cb
Remove unnecessary py::keep_alive.
clalancette Jul 19, 2018
bd338c6
Fixes from review.
clalancette Jul 19, 2018
ecc7cbc
Rename VelocityController -> SpeedController.
clalancette Jul 19, 2018
106e3af
Add in a speed system, rather than a controller.
clalancette Jul 23, 2018
1d36def
Protect speed_ with a mutex.
clalancette Jul 23, 2018
73ba8bf
Make sure to initialize the SpeedSystem properly.
clalancette Jul 23, 2018
2f7d817
Switch to returning an AgentBase pointer from AddAgent.
clalancette Jul 26, 2018
3c9671f
Fix review comments.
clalancette Aug 2, 2018
b3d4e25
Switch to a more generic constant_vector_settable.
clalancette Aug 8, 2018
be082b7
Revert "Switch to a more generic constant_vector_settable."
clalancette Aug 8, 2018
0c42cb1
Make SpeedSystem a templatized class.
clalancette Aug 8, 2018
8259cf9
Remove SetDefaultState.
clalancette Aug 8, 2018
85bd388
Split into two systems.
clalancette Aug 8, 2018
34220f9
Fix cpplint errors.
clalancette Aug 10, 2018
180a3c6
Fixes for update to latest drake.
clalancette Aug 14, 2018
de02677
Rename ConstantVectorSettable to VectorSource.
clalancette Aug 14, 2018
c962c66
Add TODO comment about make VectorSource an N-vector.
clalancette Aug 14, 2018
fbf8ede
Move the speed changing demo into the scriptlet demo instead.
clalancette Aug 14, 2018
355fe8f
More small fixes from review.
clalancette Aug 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion python/delphyne/agents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
** Includes
*****************************************************************************/

#include <string>
#include <vector>

#include <pybind11/functional.h>
Expand Down Expand Up @@ -53,7 +54,8 @@ PYBIND11_MODULE(agents, m) {
py::arg("lane"), py::arg("direction_of_travel"),
py::arg("longitudinal_position"), py::arg("lateral_offset"),
py::arg("speed"), py::arg("nominal_speed"),
py::arg("road_geometry"));
py::arg("road_geometry"))
.def("set_speed", &delphyne::RailCar::SetSpeed);

py::class_<delphyne::SimpleCar, delphyne::Agent>(m, "SimpleCar")
.def(py::init<const std::string&, double, double, double, double>(),
Expand Down
6 changes: 0 additions & 6 deletions python/delphyne/demos/crash.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,6 @@ def add_collision_callback(_, method):
def _method_wrapper(self, callback):
@wraps(callback)
def _callback_wrapper(agents_in_collision):
simulator = self.get_simulator()
agents_in_collision = [
(simulator.get_mutable_agent_by_id(agent1_id),
simulator.get_mutable_agent_by_id(agent2_id))
for agent1_id, agent2_id in agents_in_collision
]
callback(self, agents_in_collision)
return method(self, _callback_wrapper)
return _method_wrapper
Expand Down
66 changes: 65 additions & 1 deletion python/delphyne/demos/scriptlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@

from __future__ import print_function

import os.path

import random
import time

import delphyne.maliput as maliput
import delphyne.simulation as simulation
import delphyne.utilities as utilities

Expand Down Expand Up @@ -89,6 +92,29 @@ def parse_arguments():
)
return parser.parse_args()


class TimeMonitor(object):
'''
A class to monitor the time on every callback and perform an action after
ten seconds have elapsed.
'''
def __init__(self, simulator, agent):
self.simulator = simulator
self.agent = agent
self.changed_speed = False

def check_tick(self):
'''
The callback called on every simulator iteration. It checks
to see if the elapsed simulator_time is greater than 10 seconds, and
once it is, it changes the speed of the agent.
'''
if self.simulator.get_current_simulation_time() >= 10.0 \
and not self.changed_speed:
self.agent.set_speed(20.0)
self.changed_speed = True


##############################################################################
# Main
##############################################################################
Expand All @@ -101,26 +127,64 @@ def main():
stats = SimulationStats()

simulator = simulation.AutomotiveSimulator()

filename = "{0}/roads/circuit.yaml".format(
utilities.get_delphyne_resource_root())

if not os.path.isfile(filename):
print("Required file {} not found."
" Please, make sure to install the latest delphyne-gui."
.format(os.path.abspath(filename)))
quit()

# The road geometry
road_geometry = simulator.set_road_geometry(
maliput.create_multilane_from_file(
file_path=filename
)
)

utilities.add_simple_car(
simulator,
name=str(0),
position_x=0.0,
position_y=0.0)

# Setup railcar
railcar_speed = 4.0 # (m/s)
railcar_s = 0.0 # (m)
robot_id = 1
lane_1 = road_geometry.junction(2).segment(0).lane(0)
myagent = utilities.add_rail_car(
simulator,
name=str(robot_id),
lane=lane_1,
position=railcar_s,
offset=0.0,
speed=railcar_speed,
road_geometry=road_geometry)

runner = simulation.SimulatorRunner(
simulator=simulator,
time_step=0.001, # (secs)
realtime_rate=args.realtime_rate,
paused=args.paused
paused=args.paused,
log=args.log,
logfile_name=args.logfile_name
)

monitor = TimeMonitor(simulator, myagent)

with utilities.launch_interactive_simulation(runner) as launcher:
# Add a callback to record and print statistics
runner.add_step_callback(stats.record_tick)

# Add a second callback that prints a message roughly every 500 calls
runner.add_step_callback(random_print)

# Add a third callback to check on the time elapsed and change speed
runner.add_step_callback(monitor.check_tick)

stats.start()

if args.duration < 0:
Expand Down
1 change: 0 additions & 1 deletion python/delphyne/maliput.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
*****************************************************************************/

#include <limits>
#include <memory>

#include <pybind11/functional.h>
#include <pybind11/pybind11.h>
Expand Down
15 changes: 8 additions & 7 deletions python/delphyne/simulation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,19 @@ PYBIND11_MODULE(simulation, m) {
py::class_<AutomotiveSimulator<double>>(m, "AutomotiveSimulator")
.def(py::init(
[](void) { return std::make_unique<AutomotiveSimulator<double>>(); }))
.def("add_agent", &AutomotiveSimulator<double>::AddAgent)
.def("get_agent_by_id",
&AutomotiveSimulator<double>::GetAgentById,
.def("add_agent", &AutomotiveSimulator<double>::AddAgent,
py::return_value_policy::reference_internal)
.def("get_mutable_agent_by_id",
&AutomotiveSimulator<double>::GetMutableAgentById,
.def("get_collisions", &AutomotiveSimulator<double>::GetCollisions,
py::return_value_policy::reference_internal)
.def("get_collisions", &AutomotiveSimulator<double>::GetCollisions)
.def("start", &AutomotiveSimulator<double>::Start)
.def("set_road_geometry", &AutomotiveSimulator<double>::SetRoadGeometry,
"Transfer a road geometry to the control of the simulator",
py::arg("road_geometry"));
py::arg("road_geometry"))
.def("get_current_simulation_time",
&AutomotiveSimulator<double>::GetCurrentSimulationTime)
.def("get_mutable_context",
&AutomotiveSimulator<double>::GetMutableContext,
py::return_value_policy::reference_internal);
}

/*****************************************************************************
Expand Down
4 changes: 2 additions & 2 deletions python/delphyne/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@ def add_rail_car(simulator, name, lane, position, offset,
longitudinal_position=position, # lane s-coordinate (m)
lateral_offset=offset, # lane r-coordinate (m)
speed=speed, # initial speed in s-direction (m/s)
nominal_speed=5.0, # nominal_speed (m/s)
nominal_speed=20.0, # nominal_speed (m/s)
road_geometry=road_geometry) # maliput road geometry
simulator.add_agent(agent)
return simulator.add_agent(agent)


# pylint: disable=too-many-arguments
Expand Down
22 changes: 22 additions & 0 deletions src/agents/rail_car.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <drake/automotive/maliput/api/segment.h>
#include <drake/common/eigen_types.h>
#include <drake/systems/framework/context.h>
#include <drake/systems/primitives/constant_vector_source.h>

// public headers
#include "delphyne/macros.h"
Expand All @@ -31,6 +32,8 @@
#include "systems/rail_follower.h"
#include "systems/rail_follower_params.h"
#include "systems/rail_follower_state.h"
#include "systems/speed_system.h"
#include "systems/vector_source.h"

/*****************************************************************************
** Namespaces
Expand Down Expand Up @@ -127,6 +130,21 @@ std::unique_ptr<Agent::DiagramBundle> RailCar::BuildDiagram() const {
context_numeric_parameters));
rail_follower_system->set_name(name_ + "_system");

vel_setter_ = builder.template AddSystem(
std::make_unique<delphyne::VectorSource<double>>(-1));

delphyne::SpeedSystem<double>* speed_system = builder.AddSystem(
std::make_unique<delphyne::SpeedSystem<double>>());

builder.Connect(speed_system->acceleration_output(),
rail_follower_system->command_input());

builder.Connect(rail_follower_system->velocity_output(),
speed_system->feedback_input());

builder.Connect(vel_setter_->output(),
speed_system->command_input());

/*********************
* Diagram Outputs
*********************/
Expand All @@ -137,4 +155,8 @@ std::unique_ptr<Agent::DiagramBundle> RailCar::BuildDiagram() const {
return std::move(builder.Build());
}

void RailCar::SetSpeed(double new_speed_mps) {
vel_setter_->Set(new_speed_mps);
}

} // namespace delphyne
11 changes: 11 additions & 0 deletions src/agents/rail_car.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
#include <drake/automotive/maliput/api/lane.h>
#include <drake/automotive/maliput/api/road_geometry.h>
#include <drake/common/drake_copyable.h>
#include <drake/systems/primitives/constant_vector_source.h>

// public headers
#include "delphyne/mi6/agent_base.h"
#include "systems/speed_system.h"
#include "systems/vector_source.h"

/*****************************************************************************
** Namespaces
Expand Down Expand Up @@ -65,6 +68,12 @@ class RailCar : public delphyne::Agent {

std::unique_ptr<DiagramBundle> BuildDiagram() const;

///
/// @brief Change the speed of this agent.
///
/// @param new_speed_mps[in] The new speed for the agent in meters/second
void SetSpeed(double new_speed_mps);

private:
// Container for the agent's initial configuration.
//
Expand All @@ -90,6 +99,8 @@ class RailCar : public delphyne::Agent {
nominal_speed(nominal_speed) {}
} initial_parameters_;

mutable delphyne::VectorSource<double>* vel_setter_;

const drake::maliput::api::RoadGeometry& road_geometry_;
};

Expand Down
43 changes: 16 additions & 27 deletions src/backend/automotive_simulator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,9 @@ std::unique_ptr<ignition::msgs::Scene> AutomotiveSimulator<T>::GetScene() {
return std::move(scene_msg);
}

// TODO(jwnimmer-tri): Modify the various vehicle model systems to be more
// uniform so common code from the following AddFooCar() methods can be moved
// into a shared method.

template <typename T>
int AutomotiveSimulator<T>::AddAgent(std::unique_ptr<AgentBase<T>> agent) {
delphyne::AgentBase<T>* AutomotiveSimulator<T>::AddAgent(
std::unique_ptr<AgentBase<T>> agent) {
/*********************
* Checks
*********************/
Expand Down Expand Up @@ -167,7 +164,8 @@ int AutomotiveSimulator<T>::AddAgent(std::unique_ptr<AgentBase<T>> agent) {

// save a handle to it
agents_[id] = std::move(agent);
return id;

return agents_[id].get();
}

template <typename T>
Expand All @@ -180,22 +178,6 @@ const RoadGeometry* AutomotiveSimulator<T>::SetRoadGeometry(
return road_geometry_.get();
}

template <typename T>
const delphyne::AgentBase<T>&
AutomotiveSimulator<T>::GetAgentById(int agent_id) const {
DELPHYNE_VALIDATE(agents_.count(agent_id) != 0, std::runtime_error,
"No agent found with the given ID.");
return *agents_.at(agent_id);
}

template <typename T>
delphyne::AgentBase<T>* AutomotiveSimulator<T>::GetMutableAgentById(
int agent_id) {
DELPHYNE_VALIDATE(agents_.count(agent_id) != 0, std::runtime_error,
"No agent found with the given ID.");
return agents_[agent_id].get();
}

template <typename T>
void AutomotiveSimulator<T>::GenerateAndLoadRoadNetworkUrdf() {
std::string filename = road_geometry_->id().string();
Expand Down Expand Up @@ -240,16 +222,17 @@ struct IsSourceOf {
} // namespace

template <typename T>
const std::vector<std::pair<int, int>> AutomotiveSimulator<T>::GetCollisions()
const {
const std::vector<std::pair<delphyne::AgentBase<T>*, delphyne::AgentBase<T>*>>
AutomotiveSimulator<T>::GetCollisions() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@clalancette I had to test the delphyne-crash demo several times because I couldn't understand how it was not breaking. I would have thought that a returning a vector by-value and sticking a reference_internal return value policy to the binding would've left us with a dangling reference to a value in the stack (as intermediary containers are not internal to the simulator, only the leaf pointers are) but, alas, it doesn't. It seems I failed to see that pybind11 code that deals with STL containers always returns a Python primitive (list, tuple, etc.) regardless of the specified return value policy.

So kudos, no need for the solution in #508 for this specific issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@clalancette I had to test the delphyne-crash demo several times because I couldn't understand how it was not breaking. I would have thought that a returning a vector by-value and sticking a reference_internal return value policy to the binding would've left us with a dangling reference to a value in the stack (as intermediary containers are not internal to the simulator, only the leaf pointers are) but, alas, it doesn't. It seems I failed to see that pybind11 code that deals with STL containers always returns a Python primitive (list, tuple, etc.) regardless of the specified return value policy.

But wouldn't the existing code have the same problem? It is also returning a vector by value, just templated on different types. Or am I misunderstanding your point?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation on master was not using a reference_internal return value policy (check here). Yours is and to my surprise it works just fine (unless I've misunderstood a part of pybind11).

DELPHYNE_VALIDATE(has_started(), std::runtime_error,
"Can only get collisions on a running simulation");
using drake::geometry::GeometryId;
using drake::geometry::QueryObject;
using drake::geometry::PenetrationAsPointPair;
const std::vector<PenetrationAsPointPair<T>> collisions =
scene_query_->GetValue<QueryObject<T>>().ComputePointPairPenetration();
std::vector<std::pair<int, int>> agents_colliding;
std::vector<std::pair<delphyne::AgentBase<T>*, delphyne::AgentBase<T>*>>
agents_colliding;
for (const auto& collision : collisions) {
const auto it_A = std::find_if(agents_.begin(), agents_.end(),
IsSourceOf<T, GeometryId>(collision.id_A));
Expand All @@ -259,7 +242,8 @@ const std::vector<std::pair<int, int>> AutomotiveSimulator<T>::GetCollisions()
IsSourceOf<T, GeometryId>(collision.id_B));
DELPHYNE_VALIDATE(it_B != agents_.end(), std::runtime_error,
"Could not find second agent in list of agents");
agents_colliding.emplace_back(it_A->first, it_B->first);
agents_colliding.emplace_back(agents_[it_A->first].get(),
agents_[it_B->first].get());
}
return agents_colliding;
}
Expand Down Expand Up @@ -447,7 +431,7 @@ void AutomotiveSimulator<T>::StepBy(const T& time_step) {
}

template <typename T>
double AutomotiveSimulator<T>::get_current_simulation_time() const {
double AutomotiveSimulator<T>::GetCurrentSimulationTime() const {
return drake::ExtractDoubleOrThrow(simulator_->get_context().get_time());
}

Expand Down Expand Up @@ -477,6 +461,11 @@ PoseBundle<T> AutomotiveSimulator<T>::GetCurrentPoses() const {
return pose_bundle;
}

template <typename T>
drake::systems::Context<T>* AutomotiveSimulator<T>::GetMutableContext() {
return &simulator_->get_mutable_context();
}

template class AutomotiveSimulator<double>;

} // namespace delphyne
Loading