riebl / artery

OMNeT++ V2X simulation framework for ETSI ITS-G5
GNU General Public License v2.0
204 stars 132 forks source link

ASSERT: Condition 'mController' does not hold in function 'getVehicleController' #330

Closed zanouni closed 4 months ago

zanouni commented 8 months ago

Hi @riebl I am using CollectivePerceptionMockService. I am trying to add a static object to the object container in the generatePacket function. To initiate this object, I tried the following: std::weak_ptr object; auto& vehicle = getFacilities().get_const(); std::unique_ptr uniqueObject = std::make_unique(&vehicle, id); And then: uniqueObject->mCentrePoint = position; object = std::weak_ptr(std::shared_ptr(std::move(uniqueObject))); CollectivePerceptionMockMessage::ObjectContainer objc; objc.object = object; objc.objectId = id; objc.sensorId = 0; objc.timeOfMeasurement = omnetpp::simTime();

After that, I used this function to add the newly created object: objectContainers1.emplace_back(...) Now, when I try to run my project, I encounter the following error: "ASSERT: Condition 'mController' does not hold in function 'getVehicleController' at //artery/src/artery/traci/VehicleMobility.cc:36 -- in module (artery::VehiclePositionProvider) World.node[0].vanetza[0].position (id=105), during network initialization."

Can you help me understand the problem or provide any other ideas to create the static object? Thank you.

riebl commented 8 months ago

The field object in ObjectContainer refers to a EnvironmentModelObject managed by the environment model. Just do not set this field if the object container shall include an object that is not tracked by the environment model at all.

The failing assertion seems to be unrelated to your modification. Possibly an invalid object is dereferenced (maybe by your receiving service?) and thus triggering the assertion because of a memory violation.

zanouni commented 7 months ago

Thank you @riebl After successfully adding the objects to the object container of each packet, do you have any ideas on how to make them appear in the simulation? Thank you again for your help!

riebl commented 7 months ago

If you want your fake objects to become detectable by sensors, you will need to extend the GlobalEnvironmentModel accordingly. For example, you could track these artificial objects in a secondary ObjectDB.

zanouni commented 7 months ago

Hi @riebl I tried to create this function in GlobalEnvironmentModel.cc:

bool GlobalEnvironmentModel::addFakeVehicle(traci::VehicleController* vehicle, std::shared_ptr object, uint32_t id) { const std::string& idString = std::to_string(id); FakeObjects.emplace(idString, object); auto box = boost::geometry::return_envelope(object->getOutline()); FakeObjectRtree.insert(ObjectRtreeValue{std::move(box), object}); return true; }

And I used a new ObjectDB FakeObjects, then I added the fake object that I created using this function like this:

res = const_cast<GlobalEnvironmentModel*>(globalenv)->addFakeVehicle(&FakevehicleController, object.lock(), id);

But during the simulation, I encountered this error: libsumo::TraCIException: .. Answered with error to command (164), [description: Vehicle '100' is not known.] – in module artery::GVattackService, World.node[0].middleware.GVattackService (id=100), at t=0.334426574409s, event 13.

Do you know what causes this error? And thank you again.

riebl commented 7 months ago

Currently the EnvironmentModelObject is quite tightly bound to SUMO, e.g. it depends on traci::VehicleController. I suggest making EnvironmentModelObject an interface class and moving all the TraCI specific code to a child class TraCIEnvironmentModelObject. For your fake objects, you can then instantiate objects of another child class FakeEnvironmentModelObject, which does not depend on TraCI/SUMO at all. This approach should avoid too many headaches.

zanouni commented 7 months ago

Thank you @riebl So, with this solution, will the fake object appear on the network where the presence of other nodes and modules? This is actually the core idea of my project: to assess the behavior of valid existing nodes when they detect fake objects sent or created by a malicious node.

riebl commented 7 months ago

All objects registered at the GlobalEnvironmentModel are supposed to be "real". So if "fake" means in your context that the object has no meaningful interpretation at all, it should be registered at the global model. However, refactoring the EnvironmentModelObject is still useful then: Within the GlobalEnvironmentModel we can then use TraCIEnvironmentModelObjects while you can forge "malicious" objects (type named MaliciousEnvironmentModelObject?).

zanouni commented 7 months ago

Thank you, Mr. @riebl , once again. I've updated the project by incorporating the TraCIEnvironmentModelObject and BaseEnvironmentModelObject, as you suggested. Then, I attempted to create a fake object using the following function:

std::shared_ptr<traci::API> traciApi = Inicontroller->getTraCI();
if (traciApi) {
    traci::PersonController FakePersonController(traciApi, idString); 
    FakePersonController.setSpeed(1.2 * Inicontroller->getSpeed());
    std::shared_ptr<TraCIEnvironmentModelObject> Fobject = std::make_shared<TraCIEnvironmentModelObject>(&FakePersonController, id);
    if (Fobject) {
        // Create the fake position
        artery::Position Fakeposition;
        using Length = decltype(Fakeposition.x);
        Length deltaX = 10 * boost::units::si::meter;
        Length deltaY = id * boost::units::si::meter;
        Fakeposition.x = Inicontroller->getPosition().x  + deltaX;
        Fakeposition.y = Inicontroller->getPosition().y  + deltaY;
        Fobject->mCentrePoint = Fakeposition;
        bool res = const_cast<GlobalEnvironmentModel*>(globalenv)->addFObject(Fobject, id);

I've also added a function in the GlobalEnvironmentModel:

bool GlobalEnvironmentModel::addFObject(std::shared_ptr<TraCIEnvironmentModelObject> object, uint32_t id) {
    const std::string& idString = std::to_string(id);
    auto insertion = FObjects.emplace(object->getExternalId(), object);
    if (insertion.second) {
        auto box = boost::geometry::return_envelope<geometry::Box>(object->getOutline());
        FakeObjectRtree.insert(FObjectRtreeValue { std::move(box), object });
    }
    ASSERT(FObjects.size() == FakeObjectRtree.size());
    return insertion.second;
}

And here are the types and variables used:

using FObjectDB = std::unordered_map<std::string, std::shared_ptr<TraCIEnvironmentModelObject>>;
using FObjectRtreeValue = std::pair<geometry::Box, std::shared_ptr<TraCIEnvironmentModelObject>>;
using FObjectRtree = boost::geometry::index::rtree<FObjectRtreeValue, boost::geometry::index::quadratic<16>>;
FObjectDB FObjects;
FObjectRtree FakeObjectRtree;

And these modifications were integrated into the initialization function of the service:

globalenv = getFacilities().get_mutable_ptr<GlobalEnvironmentModel>();
if (globalenv != nullptr) {
    auto vehicle = inet::findContainingNode(this);
    auto mMiddleware = inet::getModuleFromPar<artery::Middleware>(par("middlewareModule"), vehicle);
    Inicontroller = globalenv->getController(vehicle);
} else {
    std::cerr << "Error: Global environment model is not valid." << std::endl;
}

Despite these modifications, the issue persists. I encountered the error libsumo::TraCIException: .. Answered with error to command (206), [description: Person '100' is not known] -- in module (artery::CollectivePerceptionMockService) World.node[0].middleware.CollectivePerceptionMockService (id=100), at t=0.334426574409s, after using the function like this: createGV(100); In the generatePacket function. If anyone has a solution, I would greatly appreciate it. Thank you once again.

awillecke commented 7 months ago

Hi,

for better readability, you could post your code in tags or push your code to a fork on GitHub so it is easier to follow your code and also see its context.

Your error is thrown by SUMO which does not know the object you are referencing in a TraCI call.

traci::PersonController FakePersonController(traciApi, idString);
FakePersonController.setSpeed(1.2 * Inicontroller->getSpeed());

As far as I understand your code, here, you create a new controller for an SUMO object with some ID and then you try to set its speed in SUMO. If the ID is arbitrary, SUMO might throw this error.

riebl commented 7 months ago

As @awillecke has pointed out, you are (probably) forging some idString which does not refer to an actual SUMO entity. This approach is prone to fail. You should create FakeEnvironmentModelObject objects and use these instead of TraCIEnvironmentModelObject. So far, no FakeEnvironmentModelObject class exists yet but you can easily create one by sub-classing BaseEnvironmentModelObject. You can entirely abandon the FakePersonController by adding setter methods to FakeEnvironmentModelObject which simply store length, width etc. in the member attributes of the object.

zanouni commented 7 months ago

If I change the type of the fake objects, for example, like this: std::shared_ptr Fobject = std::make_shared(&FakePersonController, id); I still need a valid controller, and therein lies the problem. I don't know how to obtain it correctly. Additionally, if I change the type of the fake objects, I won't be able to add them to the global environment, right? Consequently, I can't add them to the network, and the real vehicles can't detect the presence of these fake objects.

awillecke commented 7 months ago

You only need a controller, if your object relates to an object in SUMO. In that case, you can instantiate a controller with the ID of a SUMO object, e.g. vehicle ID, and request its attributes and such.

In your case, I suppose, you want an object in the EnvMod that is unrelated to SUMO objects. In that case, you do not need nor want a controller. With @riebl changes, you can implement your own envmod object, by creating a new class, that inherits from BaseEnvironmentModelObject and behaves like you want it to.

The GlobalEnvironmentModel still handles EnvironmentModelObject, but it is an interface class now. When implementing a FakeEnvironmentModelObject that inherits from the BaseEnvironmentModelObject and thus, implements the EnvironmentModelObject interface, it should be possible to add your fake objects to mObjects or create sensor trackings for fake trackings in sensors.

zanouni commented 7 months ago

Hi @riebl and @awillecke , Thank you again for your help. Now, after I've created the FakeEnvironmentModelObject and instantiated the fake object as a FakeEnvironmentModelObject like this: std::make_shared(id); bool res = const_cast<GlobalEnvironmentModel*>(globalenv)->addFObject(Fobject, idString);

Using the function I've created in the global environment: GlobalEnvironmentModel::addFObject(std::shared_ptr object, const std::string& id) { auto existingObject = mObjects.find(id); if (existingObject != mObjects.end()) { std::cerr << "Error: Object with ID " << id << " already exists in the database." << std::endl; return false; } auto insertion = mObjects.emplace(id, object); if (insertion.second) { auto box = boost::geometry::return_envelope(object->getOutline()); mObjectRtree.insert(ObjectRtreeValue { std::move(box), object }); ASSERT(mObjects.size() == mObjectRtree.size()); return true; } else { std::cerr << "Error: Failed to insert object into the database." << std::endl; return false; } } After successfully adding the fake object to the database mObjects, do you have any ideas on how to make those fake objects appear in the simulation so that other vehicles will be aware of them? Thank you again for your help.

awillecke commented 6 months ago

If your fake objects are added successfully to the mObjects and mObjectRtree by your function, they should be detectable by any FovSensor (c.f. FovSensor::detectObjects()) or SeeThroughSensor that is attached to a vehicle or RSU, if they are in range (and line of sight).

You can check if it works as you expect with a debugger or by equipping the EnvmodPrinter service.

You could also use the Envmod visualizer in Omnet++ GUI. Here, you would have to enable the drawing feature with:

*.node[*].environmentModel.*.drawSensorCone = true
*.node[*].environmentModel.*.drawLinesOfSight = true
*.node[*].environmentModel.*.drawDetectedObjects = true
*.node[*].environmentModel.*.drawBlockingObstacles = true