296 lines
8.8 KiB
C++
296 lines
8.8 KiB
C++
#include "Perception.h"
|
|
#include "Angle.h"
|
|
#include "DistanceSensor.h"
|
|
#include "NetworkSync.h"
|
|
#include "Switch.h"
|
|
|
|
#include <math.h>
|
|
|
|
Perception::Perception() {
|
|
for (unsigned char objIx = 0; objIx < maxObjectCount; objIx++)
|
|
this->perceivedObjects[objIx] = nullptr;
|
|
}
|
|
|
|
Perception::Perception(Placement *sensors, unsigned int sensorCount)
|
|
: Perception() {
|
|
this->sensorCount = sensorCount;
|
|
this->sensorPlacements = (Placement *)sensors;
|
|
}
|
|
|
|
unsigned int Perception::GetSensorCount() { return this->sensorCount; }
|
|
|
|
Sensor *Perception::GetSensor(unsigned int sensorId) {
|
|
if (sensorId >= this->sensorCount)
|
|
return nullptr;
|
|
|
|
Thing *thing = this->sensorPlacements[sensorId].thing;
|
|
if (thing->IsSensor())
|
|
return (Sensor *)thing;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
Sensor *Perception::FindSensorOfType(unsigned int sensorType) {
|
|
for (unsigned int sensorIx = 0; sensorIx < this->sensorCount; sensorIx++) {
|
|
Sensor *sensor = (Sensor *)this->sensorPlacements[sensorIx].thing;
|
|
if (sensor->type == sensorType)
|
|
return sensor;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
float Perception::GetDistance(float direction, float range) {
|
|
float minDistance = INFINITY;
|
|
if (range < 0)
|
|
range = -range;
|
|
|
|
for (unsigned char objIx = 0; objIx < maxObjectCount; objIx++) {
|
|
PerceivedObject *obj = perceivedObjects[objIx];
|
|
if (obj == nullptr)
|
|
continue;
|
|
if (obj->position.angle > direction - range &&
|
|
obj->position.angle < direction + range) {
|
|
|
|
minDistance = fmin(minDistance, obj->position.distance);
|
|
}
|
|
}
|
|
return minDistance;
|
|
}
|
|
|
|
float Perception::GetDistance(float horizontalDirection,
|
|
float verticalDirection, float range) {
|
|
float minDistance = INFINITY;
|
|
if (range < 0)
|
|
range = -range;
|
|
|
|
for (unsigned char objIx = 0; objIx < maxObjectCount; objIx++) {
|
|
PerceivedObject *obj = perceivedObjects[objIx];
|
|
if (obj == nullptr)
|
|
continue;
|
|
if (obj->position.angle > horizontalDirection - range &&
|
|
obj->position.angle < horizontalDirection + range) {
|
|
|
|
minDistance = fmin(minDistance, obj->position.distance);
|
|
}
|
|
}
|
|
|
|
return minDistance;
|
|
}
|
|
bool Perception::ObjectNearby(float direction, float range) {
|
|
if (range < 0)
|
|
range = -range;
|
|
|
|
for (unsigned char objIx = 0; objIx < maxObjectCount; objIx++) {
|
|
PerceivedObject *obj = perceivedObjects[objIx];
|
|
if (obj == nullptr)
|
|
continue;
|
|
|
|
if (obj->position.angle > direction - range &&
|
|
obj->position.angle < direction + range) {
|
|
if (obj->position.distance <= nearbyDistance)
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/***
|
|
* Oject perception
|
|
***/
|
|
|
|
PerceivedObject::PerceivedObject() {
|
|
this->id = 0;
|
|
this->confidence = maxConfidence;
|
|
this->position = Polar(0, INFINITY);
|
|
this->radius = INFINITY;
|
|
}
|
|
|
|
PerceivedObject::PerceivedObject(Sensor *sensor, Polar position, float radius)
|
|
: PerceivedObject() {
|
|
this->sensor = sensor;
|
|
this->position = position;
|
|
this->radius = radius;
|
|
}
|
|
|
|
bool PerceivedObject::IsTheSameAs(PerceivedObject *otherObj) {
|
|
if (id != 0 && id == otherObj->id)
|
|
return true;
|
|
if (abs(position.distance - otherObj->position.distance) > equalityDistance)
|
|
return false;
|
|
if (abs(position.angle - otherObj->position.angle) > equalityAngle)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool PerceivedObject::DegradeConfidence(float deltaTime) {
|
|
unsigned char confidenceDrop =
|
|
(unsigned char)((float)confidenceDropSpeed * deltaTime);
|
|
// Make sure the confidence always drops
|
|
if (confidenceDrop == 0)
|
|
confidenceDrop = 1;
|
|
|
|
if (confidence <= confidenceDrop) {
|
|
// object is dead
|
|
confidence = 0;
|
|
return false;
|
|
} else {
|
|
confidence -= confidenceDrop;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void PerceivedObject::Refresh(Polar position, float radius) {
|
|
this->position = position;
|
|
this->radius = radius;
|
|
this->confidence = maxConfidence;
|
|
}
|
|
|
|
void Perception::AddPerceivedObject(Sensor *sensor, Polar position) {
|
|
// int objCount = PerceivedObjectCount();
|
|
// printf("perc obj count %d\n");
|
|
|
|
PerceivedObject *obj = new PerceivedObject(sensor, position);
|
|
// objCount = PerceivedObjectCount();
|
|
// printf("perc obj count %d\n");
|
|
// AddPerceivedObject(obj);
|
|
// }
|
|
|
|
// void Perception::AddPerceivedObject(PerceivedObject *obj) {
|
|
unsigned char farthestObjIx = 0;
|
|
unsigned char availableSlotIx = 0;
|
|
for (unsigned char objIx = 0; objIx < maxObjectCount; objIx++) {
|
|
// printf("[%d] %d\n", objIx, this->perceivedObjects[objIx]);
|
|
// Is this slot available?
|
|
if (this->perceivedObjects[objIx] == nullptr) {
|
|
availableSlotIx = objIx;
|
|
}
|
|
// Do we see the same object?
|
|
else {
|
|
// printf("(%d) my %f %f =^= received %f %f\n", objIx,
|
|
// this->perceivedObjects[objIx]->position.distance,
|
|
// this->perceivedObjects[objIx]->position.angle,
|
|
// obj->position.distance, obj->position.angle);
|
|
if (obj->IsTheSameAs(this->perceivedObjects[objIx])) {
|
|
// printf("[%d] Updating...\n", objIx);
|
|
this->perceivedObjects[objIx]->Refresh(obj->position, obj->radius);
|
|
return;
|
|
}
|
|
// Is this the fartest object we see?
|
|
else if (this->perceivedObjects[farthestObjIx] == nullptr ||
|
|
(this->perceivedObjects[objIx]->position.distance >
|
|
this->perceivedObjects[farthestObjIx]->position.distance)) {
|
|
farthestObjIx = objIx;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if an perception slot is available (we currently see less than the
|
|
// max number of objects)
|
|
if (availableSlotIx < maxObjectCount) {
|
|
// a slot is available
|
|
// printf("[%d] new object \n", availableSlotIx);
|
|
this->perceivedObjects[availableSlotIx] = obj;
|
|
}
|
|
// If this object is closer than the farthest object, then replace it
|
|
else if (obj->position.distance <
|
|
this->perceivedObjects[farthestObjIx]->position.distance) {
|
|
this->perceivedObjects[farthestObjIx] = obj;
|
|
// we may want to destroy the fartest object, but if it is created
|
|
// externally, other links may still exist...
|
|
}
|
|
}
|
|
|
|
unsigned char Perception::PerceivedObjectCount() {
|
|
unsigned char objectCount = 0;
|
|
for (unsigned char objIx = 0; objIx < maxObjectCount; objIx++) {
|
|
if (this->perceivedObjects[objIx] != nullptr)
|
|
objectCount++;
|
|
}
|
|
return objectCount;
|
|
}
|
|
|
|
PerceivedObject **Perception::GetPerceivedObjects() {
|
|
return this->perceivedObjects;
|
|
}
|
|
|
|
void Perception::Update(float currentTimeMs) {
|
|
float deltaTime = currentTimeMs - lastUpdateTimeMs;
|
|
if (deltaTime <= 0)
|
|
return;
|
|
|
|
lastUpdateTimeMs = currentTimeMs;
|
|
|
|
// Update sensing
|
|
for (unsigned int sensorIx = 0; sensorIx < this->sensorCount; sensorIx++) {
|
|
Placement thingPlacement = sensorPlacements[sensorIx];
|
|
Thing *thing = thingPlacement.thing;
|
|
if (thing == nullptr)
|
|
continue;
|
|
|
|
if (thing->type == Thing::DistanceSensorType) {
|
|
DistanceSensor *distanceSensor = (DistanceSensor *)thing;
|
|
|
|
float distance = distanceSensor->GetDistance();
|
|
float angle = thingPlacement.horizontalDirection;
|
|
Polar position = Polar(angle, distance);
|
|
AddPerceivedObject(distanceSensor, position);
|
|
} else if (thing->type == Thing::SwitchType) {
|
|
Switch *switchSensor = (Switch *)thing;
|
|
if (switchSensor != nullptr && switchSensor->IsOn()) {
|
|
Polar position =
|
|
Polar(thingPlacement.horizontalDirection, nearbyDistance);
|
|
AddPerceivedObject(switchSensor, position);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (unsigned char objIx = 0; objIx < maxObjectCount; objIx++) {
|
|
PerceivedObject *obj = perceivedObjects[objIx];
|
|
if (obj == nullptr)
|
|
continue;
|
|
|
|
if (obj->DegradeConfidence(deltaTime) == false) {
|
|
// delete obj
|
|
// printf("[%d] delete object\n", objIx);
|
|
if (roboid != nullptr && roboid->networkSync != nullptr)
|
|
roboid->networkSync->DestroyObject(obj);
|
|
this->perceivedObjects[objIx] = nullptr;
|
|
// } else {
|
|
// Serial.printf("[%d] confidence: %d\n", objIx,
|
|
// this->perceivedObjects[objIx]->confidence);
|
|
}
|
|
}
|
|
if (this->perceivedObjects[0] != nullptr) {
|
|
}
|
|
}
|
|
|
|
void Perception::UpdatePose(Polar translation) {
|
|
for (unsigned char objIx = 0; objIx < maxObjectCount; objIx++) {
|
|
PerceivedObject *obj = perceivedObjects[objIx];
|
|
if (obj == nullptr)
|
|
continue;
|
|
|
|
Polar newPosition = obj->position - translation;
|
|
obj->position = newPosition;
|
|
}
|
|
}
|
|
|
|
void Perception::UpdatePose(Quaternion rotation) {
|
|
// only rotation around vertical axis is supported for now
|
|
float rotationAngle;
|
|
Vector3 rotationAxis;
|
|
rotation.ToAngleAxis(&rotationAngle, &rotationAxis);
|
|
// Make sure rotation axis is positive
|
|
if (rotationAxis.y < 0)
|
|
rotationAngle = -rotationAngle;
|
|
|
|
for (unsigned char objIx = 0; objIx < maxObjectCount; objIx++) {
|
|
PerceivedObject *obj = perceivedObjects[objIx];
|
|
if (obj == nullptr)
|
|
continue;
|
|
|
|
float updatedAngle = Angle::Normalize(obj->position.angle - rotationAngle);
|
|
obj->position.angle = updatedAngle;
|
|
}
|
|
} |