Eric Cousineau
Eric Cousineau

Reputation: 2004

pydrake: builder.Connect() fails with "Unable to cast Python instance to C++ type"

I am trying something like the following (using drake@00cdef03)

Note: This is not proper idiomatic Drake; you should declare a separate subclass when making a novel LeafSystem. This post just shows a compact, but hacky, form.

from pydrake.all import (
    AbstractValue,
    DiagramBuilder,
    LeafSystem,
    SpatialForce,
    Value,
)

def fake_calc(context, output):
    raise NotImplemented()

producer = LeafSystem()
producer.DeclareAbstractOutputPort("output", alloc=SpatialForce, calc=fake_calc)
consumer = LeafSystem()
consumer.DeclareAbstractInputPort("input", model_value=AbstractValue.Make(SpatialForce()))

builder = DiagramBuilder()
builder.AddSystem(producer)
builder.AddSystem(consumer)
builder.Connect(producer.get_output_port(), consumer.get_input_port())

For some reason, it fails on builder.Connect(...) with the following error:

Unable to cast Python instance to C++ type (compile in debug mode for details)

If I print the value of the ports, they seem like the match the signature of the function:

>>> producer.get_output_port()
<pydrake.systems.framework.LeafOutputPort_[float] object at 0x7febb5dba930>
>>> consumer.get_input_port()
<pydrake.systems.framework.InputPort_[float] object at 0x7febb5ff0930>

What's going on?

Upvotes: 0

Views: 281

Answers (1)

Eric Cousineau
Eric Cousineau

Reputation: 2004

The issue lies in the fact that alloc=SpatialForce is being used, but it should be should be alloc=Value[SpatialForce].

The following shows the difference between good and bad:

system = LeafSystem()
# Good!
good = system.DeclareAbstractOutputPort("good", alloc=Value[SpatialForce], calc=fake_calc)
good.Allocate()

# BAD!
bad = system.DeclareAbstractOutputPort("bad", alloc=SpatialForce, calc=fake_calc)
bad.Allocate()  # Fails here

This happens because alloc must produce an instance of AbstractValue, which is used by OutputPort::Alocate() (in C++), which uses this std::function<> type:
drake/.../value_producer.h

It happens during .Connect() because that will ultimately call Allocate():
drake/.../diagram_builder.cc

Because Python returns something not of an AbstractValue type, it is unable to cast, hence the error message

Upvotes: 1

Related Questions