Recently, I am trying to construct a "BaseContoller" to control the motion of "Atlas" in "Drake".
To get the contact result of the multibody plant in the controller, I tried to declare an abstract input port in the controller leafsystem, which is to be connected to the contact results output port of the multibodyplant.
Then, in the Calc method of torque output port, I tried to get contact result from the abstract input port.
All the code can be compiled successfully, but during the runtime "Segmentation fault (core dumped)" occured. I wonder if I have missed something.
// Atlas.cpp
int do_main(){
systems::DiagramBuilder<double> builder;
auto [plant, scene_graph] = AddMultibodyPlantSceneGraph(
&builder,
std::make_unique<MultibodyPlant<double>>(
FLAGS_mbp_discrete_update_period));
const std::string full_name =
FindResourceOrThrow("drake/../../../../home/hampton/Atlas/urdf/atlas.urdf");
multibody::Parser(&plant).AddModelFromFile(full_name);
// register the ground as visual geometry and collision geometry;
...
plant.Finalize();
plant.set_penetration_allowance(FLAGS_penetration_allowance);
plant.set_stiction_tolerance(FLAGS_stiction_tolerance);
// connect the controller;
auto controller = builder.AddSystem<systems::controllers::BaseController<double>>(plant);
builder.Connect(controller->get_output_port_control(),
plant.get_applied_generalized_force_input_port());
builder.Connect(plant.get_state_output_port(),
controller->get_input_port_estimated_state());
builder.Connect(plant.get_contact_results_output_port(),
controller->get_input_port_contact_result());
auto constant_zero_torque = builder.AddSystem<systems::ConstantVectorSource<double>>(
Eigen::VectorXd::Zero(plant.num_actuators()));
builder.Connect(constant_zero_torque->get_output_port(),
plant.get_actuation_input_port());
ConnectContactResultsToDrakeVisualizer(&builder, plant, scene_graph);
geometry::DrakeVisualizerd::AddToBuilder(&builder, scene_graph);
auto diagram = builder.Build();
std::unique_ptr<systems::Context<double>> diagram_context =
diagram->CreateDefaultContext();
// Do the initialization of context;
...
// Set the simulator;
auto simulator =
MakeSimulatorFromGflags(*diagram, std::move(diagram_context));
simulator->AdvanceTo(FLAGS_simulation_time);
simulator->set_publish_every_time_step(true);
return 0;
}
//BaseController.h
template <typename T>
class BaseController : public LeafSystem<T>{
public:
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(BaseController);
BaseController(
const multibody::MultibodyPlant<T>& palnt);
~BaseController();
const InputPort<T>& get_input_port_estimated_state() const {
return this->System<T>::get_input_port(input_port_index_state_);
}
const OutputPort<T>& get_output_port_control() const{
return this->System<T>::get_output_port(output_port_index_control_);
}
const InputPort<T>& get_input_port_contact_result() const {
return this->System<T>::get_input_port(input_port_index_contact_result_);
}
private:
// Output Calc Function;
void CalcOutputTorque(const Context<T>& context,
BasicVector<T>* force) const;
...
const multibody::MultibodyPlant<T>* const multibody_plant_;
InputPortIndex input_port_index_state_{0};
OutputPortIndex output_port_index_control_{0};
InputPortIndex input_port_index_contact_result_{0};
const int q_dim_{0};
const int v_dim_{0};
drake::systems::CacheIndex multibody_plant_context_cache_index_;
};
// BaseController.cpp
template <typename T>
BaseController<T>::BaseController(
const multibody::MultibodyPlant<T>& plant)
: multibody_plant_(&plant),
q_dim_(plant.num_positions()),
v_dim_(plant.num_velocities())
{
DRAKE_DEMAND(plant.is_finalized());
input_port_index_state_ =
this->DeclareVectorInputPort(
"Estimated State",
q_dim_ + v_dim_).get_index();
output_port_index_control_ =
this->DeclareVectorOutputPort(
"Control Torque",
v_dim_,
&BaseController<T>::CalcOutputTorque).get_index();
input_port_index_contact_result_ =
this->systems::LeafSystem<T>::DeclareAbstractInputPort(
"Contact Result",
Value<multibody::ContactResults<T>>()).get_index();
// *AbstractValue::Make(multibody::ContactResults<T>())).get_index();
auto multibody_plant_context = multibody_plant_->
System<double>::CreateDefaultContext();
multibody_plant_context_cache_index_ =
this->SystemBase::DeclareCacheEntry(
"multibody_plant_context_cache",
*multibody_plant_context,
&BaseController<T>::SetMultibodyContext,
{this->input_port_ticket(
get_input_port_estimated_state().get_index())})
.cache_index();
}
...
template <typename T>
void BaseController<T>::CalcOutputTorque(
const Context<T>& context,
BasicVector<T>* force) const{
...
const auto& contact_results =
get_input_port_contact_result().template Eval<multibody::ContactResults<T>>(context);
// const AbstractValue* abstract_value =
// this->EvalAbstractInput(context, input_port_index_contact_result_);
// const multibody::ContactResults<T>& contact_result_ =
// abstract_value->get_value<multibody::ContactResults<T>>();
}
template class BaseController<double>;