Improved network sync

This commit is contained in:
Pascal Serrarens 2024-01-12 17:16:08 +01:00
parent 89e0bf6f77
commit c07f81bce3
9 changed files with 311 additions and 22 deletions

View File

@ -25,7 +25,7 @@ void DifferentialDrive::SetDimensions(float wheelDiameter,
float wheelSeparation) {
this->wheelDiameter = wheelDiameter;
this->wheelSeparation = wheelSeparation;
this->rpsToMs = wheelDiameter * Angle::PI;
this->rpsToMs = wheelDiameter * Angle::pi;
float distance = this->wheelSeparation / 2;
this->motors[0]->position.distance = distance;
@ -73,7 +73,7 @@ Polar DifferentialDrive::GetVelocity() {
Motor *rightMotor = motors[1];
float leftSpeed = leftMotor->GetActualSpeed(); // in revolutions per second
float rightSpeed = rightMotor->GetActualSpeed(); // in revolutions per second
// float rpsToMs = wheelDiameter * Angle::PI;
// float rpsToMs = wheelDiameter * Angle::pi;
leftSpeed = leftSpeed * rpsToMs; // in meters per second
rightSpeed = rightSpeed * rpsToMs; // in meters per second
@ -85,19 +85,22 @@ Polar DifferentialDrive::GetVelocity() {
return velocity;
}
#include <Arduino.h>
float DifferentialDrive::GetAngularVelocity() {
Motor *leftMotor = motors[0];
Motor *rightMotor = motors[1];
float leftSpeed = leftMotor->GetActualSpeed(); // in revolutions per second
float rightSpeed = rightMotor->GetActualSpeed(); // in revolutions per second
// float rpsToMs = wheelDiameter * Angle::PI;
// float rpsToMs = wheelDiameter * Angle::pi;
leftSpeed = leftSpeed * rpsToMs; // in meters per second
rightSpeed = rightSpeed * rpsToMs; // in meters per second
float angularSpeed = (rightSpeed - leftSpeed) / 2;
float angularDistance = wheelSeparation / 2 * Angle::PI;
float angularDistance = wheelSeparation / 2 * Angle::pi;
float rotationsPerSecond = angularSpeed / angularDistance;
float degreesPerSecond = 360 * rotationsPerSecond;
float degreesPerSecond = Angle::Normalize(360 * rotationsPerSecond);
float angularVelocity = degreesPerSecond;
return angularVelocity;

78
NetworkPerception.cpp Normal file
View File

@ -0,0 +1,78 @@
#include "NetworkPerception.h"
#include "RoboidControl/NetworkSync.h"
void NetworkPerception::ProcessPacket(Roboid *roboid, unsigned char *buffer,
int packetsize) {
// printf("packet received, type = 0x%02x %d %d %d %d\n", buffer[0],
// buffer[2], buffer[3], buffer[4], buffer[5]);
if (buffer[0] == NetworkSync::PoseMsg) {
ReceiveObject(buffer, roboid);
}
}
Int32 NetworkPerception::ReceiveInt32(unsigned char *data, int startIndex) {
Int32 a = Int32((UInt32)(data[startIndex + 3]) << 24 |
(UInt32)(data[startIndex + 2]) << 16 |
(UInt32)(data[startIndex + 1]) << 8 |
(UInt32)(data[startIndex + 0]));
return a;
}
float NetworkPerception::ReceiveFloat100(unsigned char *data, int startIndex) {
Int32 intValue = ReceiveInt32(data, startIndex);
float f = (float)intValue / 100.0F;
return f;
}
Vector3 NetworkPerception::ReceiveVector3(unsigned char *data, int startIndex) {
float x = ReceiveFloat100(data, startIndex);
float y = ReceiveFloat100(data, startIndex + 4);
float z = ReceiveFloat100(data, startIndex + 8);
Vector3 v = Vector3(x, y, z);
return v;
}
void NetworkPerception::ReceiveObject(unsigned char *data, Roboid *roboid) {
unsigned char objectId = data[1];
char poseType = data[2];
Vector3 worldPosition = ReceiveVector3(data, 3);
Vector3 worldAngles = ReceiveVector3(data, 15);
Quaternion worldOrientation = Quaternion::Euler(worldAngles);
Vector3 worldDirection = worldOrientation * Vector3::forward;
if (objectId == 0) {
roboid->SetPosition(worldPosition);
roboid->SetOrientation(worldOrientation);
// printf("Received pose (%f, %f) (%f, %f)\n", worldPosition.x,
// worldPosition.z, worldDirection.x, worldDirection.z);
} else {
Vector3 myPosition = roboid->GetPosition(); // Vector3::zero;
Vector2 myPosition2 = Vector3::ProjectHorizontalPlane(myPosition);
Quaternion myOrientation = roboid->GetOrientation();
Vector3 myDirection = myOrientation * Vector3::forward;
Vector2 myDirection2 = Vector3::ProjectHorizontalPlane(myDirection);
Vector3 localPosition =
Quaternion::Inverse(myOrientation) * (worldPosition - myPosition);
// float distance = Vector3::Distance(myPosition, worldPosition);
// float angle = Vector3::SignedAngle(myDirection, localPosition,
// Vector3::up);
float distance = Vector3::Magnitude(localPosition);
float angle =
Vector3::SignedAngle(Vector3::forward, localPosition, Vector3::up);
Polar position = Polar(angle, distance);
// int objCount = roboid->perception->TrackedObjectCount();
// printf("object received at (%f, %f)/(%f, %f) -> (%f %f)\n",
// worldPosition.x,
// worldPosition.z, localPosition.x, localPosition.z, distance,
// angle);
roboid->perception->AddTrackedObject(this, position);
}
}

23
NetworkPerception.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include "RoboidControl/Roboid.h"
#include "RoboidControl/Sensor.h"
#include "RoboidControl/Types.h"
namespace Passer {
namespace RoboidControl {
class NetworkPerception : public Sensor {
public:
void ProcessPacket(Roboid *roboid, unsigned char *buffer, int packetsize);
protected:
void ReceiveObject(unsigned char *data, Roboid *roboid);
Int32 ReceiveInt32(unsigned char *data, int startIndex);
float ReceiveFloat100(unsigned char *data, int startIndex);
Vector3 ReceiveVector3(unsigned char *data, int startIndex);
};
} // namespace RoboidControl
} // namespace Passer

View File

@ -1,20 +1,115 @@
#include "NetworkSync.h"
#ifdef RC_DEBUG
#include <Arduino.h>
#endif
void NetworkSync::SendVector3(unsigned char *data, int startIndex, Vector3 v) {
SendFloat100(data, startIndex, v.x);
SendFloat100(data, startIndex + 4, v.y);
SendFloat100(data, startIndex + 8, v.z);
SendSingle100(data, startIndex, v.x);
SendSingle100(data, startIndex + 4, v.y);
SendSingle100(data, startIndex + 8, v.z);
}
void NetworkSync::SendFloat100(unsigned char *data, int startIndex,
float value) {
void NetworkSync::SendSingle100(unsigned char *data, int startIndex,
float value) {
// Sends a float with truncated 2 decimal precision
#ifdef ARDUINO_AVR_UNO
long intValue = value * 100;
#else
int intValue = value * 100;
#endif
Int32 intValue = value * 100;
SendInt32(data, startIndex, intValue);
// for (unsigned char ix = 0; ix < 4; ix++) {
// data[startIndex + ix] = ((unsigned char *)&intValue)[ix];
// }
}
void NetworkSync::SendInt32(unsigned char *data, int startIndex, Int32 value) {
for (unsigned char ix = 0; ix < 4; ix++) {
data[startIndex + ix] = ((unsigned char *)&intValue)[ix];
data[startIndex + ix] = ((unsigned char *)&value)[ix];
}
}
void NetworkSync::PublishTrackedObjects(SendBuffer sendBuffer,
TrackedObject **objects) {
for (unsigned char objIx = 0; objIx < Perception::maxObjectCount; objIx++) {
TrackedObject *obj = objects[objIx];
if (obj == nullptr)
continue;
// if (obj->sensor->type == Thing::ExternalType)
// continue;
// tmp
obj->id = objIx;
PublishTrackedObject(sendBuffer, obj);
}
}
void NetworkSync::PublishTrackedObject(SendBuffer sendBuffer,
TrackedObject *object) {
Vector2 worldPosition2 = Vector2::Rotate(
Vector2::forward * object->position.distance, -object->position.angle);
Vector3 worldPosition3 = Vector3(worldPosition2.x, 0, worldPosition2.y);
#ifdef RC_DEBUG
Serial.print("Send Pose ");
Serial.print((int)object->id);
Serial.print(" Position ");
Serial.print(worldPosition3.x);
Serial.print(", ");
Serial.print(worldPosition3.y);
Serial.print(", ");
Serial.println(worldPosition3.z);
#else
UInt16 bufferSize = 3 + 12;
UInt8 buffer[bufferSize] = {
PoseMsg,
object->id,
Pose_Position,
};
SendVector3(buffer, 3, worldPosition3);
sendBuffer(buffer, bufferSize);
#endif
}
void NetworkSync::SendPoseMsg(SendBuffer sendBuffer, Roboid *roboid) {
Polar velocity = roboid->propulsion->GetVelocity();
Vector2 worldVelocity2 =
Vector2::Rotate(Vector2::forward * velocity.distance, velocity.angle);
Vector3 worldVelocity3 = Vector3(worldVelocity2.x, 0, worldVelocity2.y);
float angularVelocity = roboid->propulsion->GetAngularVelocity();
Vector3 worldAngularVelocity = Vector3(0, angularVelocity, 0);
#ifdef RC_DEBUG
Serial.print("Send Pose 0 LinearVelocity ");
Serial.print(worldVelocity3.x);
Serial.print(", ");
Serial.print(worldVelocity3.y);
Serial.print(", ");
Serial.print(worldVelocity3.z);
Serial.print(" AngularVelocity ");
Serial.print(worldAngularVelocity.x);
Serial.print(", ");
Serial.print(worldAngularVelocity.y);
Serial.print(", ");
Serial.println(worldAngularVelocity.z);
#else
const unsigned int bufferSize = 3 + 12 + 12;
unsigned char buffer[bufferSize] = {
PoseMsg,
0, // objectId;
Pose_LinearVelocity | Pose_AngularVelocity,
};
SendVector3(buffer, 3, worldVelocity3);
SendVector3(buffer, 15, worldAngularVelocity);
sendBuffer(buffer, bufferSize);
#endif
}
void NetworkSync::SendDestroyObject(SendBuffer sendBuffer, TrackedObject *obj) {
#ifdef RC_DEBUG
Serial.print("Send Destroy ");
Serial.println((int)obj->id);
#else
unsigned char buffer[2] = {DestroyMsg, (unsigned char)obj->id};
sendBuffer(buffer, 2);
#endif
}

View File

@ -1,7 +1,9 @@
#pragma once
#include "NetworkPerception.h"
#include "Perception.h"
#include "Roboid.h"
#include "Types.h"
namespace Passer {
namespace RoboidControl {
@ -33,8 +35,20 @@ public:
static const char DestroyMsg = 0x20;
typedef void (*SendBuffer)(UInt8 *buffer, UInt16 bufferSize);
void SendPoseMsg(SendBuffer sendBuffer, Roboid *roboid);
void SendDestroyObject(SendBuffer sendBuffer, TrackedObject *obj);
void PublishTrackedObjects(SendBuffer sendBuffer, TrackedObject **objects);
protected:
NetworkPerception *networkPerception;
void PublishTrackedObject(SendBuffer sendBuffer, TrackedObject *object);
void SendVector3(unsigned char *data, int startIndex, Vector3 v);
void SendFloat100(unsigned char *data, int startIndex, float value);
void SendSingle100(unsigned char *data, int startIndex, float value);
void SendInt32(unsigned char *data, int startIndex, Int32 value);
};
} // namespace RoboidControl

View File

@ -6,6 +6,14 @@
#include <math.h>
#ifdef RC_DEBUG2
#include <Arduino.h>
#endif
unsigned char Perception::maxObjectCount = 7; // 7 is typically the maximum
// number of object which can
// be tracked by a human
Perception::Perception() {
this->trackedObjects = new TrackedObject *[maxObjectCount];
for (unsigned char objIx = 0; objIx < maxObjectCount; objIx++)
@ -30,6 +38,22 @@ Sensor *Perception::GetSensor(unsigned int sensorId) {
return sensor;
}
unsigned int Perception::AddSensor(Sensor *newSensor) {
unsigned int newSensorCount = this->sensorCount + 1;
Sensor **newSensors = new Sensor *[newSensorCount];
for (unsigned char sensorIx = 0; sensorIx < this->sensorCount; sensorIx++)
newSensors[sensorIx] = sensors[sensorIx];
unsigned int sensorId = this->sensorCount;
newSensors[sensorId] = newSensor;
Sensor **oldSensors = this->sensors;
this->sensors = newSensors;
this->sensorCount = newSensorCount;
delete[] oldSensors;
return sensorId;
}
Sensor *Perception::FindSensorOfType(unsigned int sensorType) {
for (unsigned int sensorIx = 0; sensorIx < this->sensorCount; sensorIx++) {
Sensor *sensor = this->sensors[sensorIx];
@ -107,6 +131,11 @@ void Perception::AddTrackedObject(Sensor *sensor, Polar position) {
// Do we see the same object?
else {
if (obj->IsTheSameAs(this->trackedObjects[objIx])) {
#ifdef RC_DEBUG2
Serial.print((int)this->trackedObjects[objIx]->id);
Serial.println(": update tracked object");
#endif
this->trackedObjects[objIx]->Refresh(obj->position);
delete obj;
return;
@ -125,13 +154,28 @@ void Perception::AddTrackedObject(Sensor *sensor, Polar position) {
if (availableSlotIx < maxObjectCount) {
// a slot is available
this->trackedObjects[availableSlotIx] = obj;
obj->id = availableSlotIx;
#ifdef RC_DEBUG2
Serial.print((int)obj->id);
Serial.println(": new tracked object");
#endif
}
// If this object is closer than the farthest object, then replace it
else if (obj->position.distance <
this->trackedObjects[farthestObjIx]->position.distance) {
delete this->trackedObjects[farthestObjIx];
this->trackedObjects[farthestObjIx] = obj;
obj->id = availableSlotIx;
#ifdef RC_DEBUG2
Serial.print((int)obj->id);
Serial.println(": replaced tracked object");
#endif
} else {
#ifdef RC_DEBUG2
Serial.print((int)obj->id);
Serial.println(": delete tracked object");
#endif
// No available slot, delete trackedobject
delete obj;
}

View File

@ -26,6 +26,8 @@ public:
/// @brief The roboid of this perception system
Roboid *roboid = nullptr;
unsigned int AddSensor(Sensor *sensor);
/// @brief Get the number of Sensors
/// @return The number of sensors, zero when no sensors are present
unsigned int GetSensorCount();
@ -130,9 +132,9 @@ public:
float lastUpdateTimeMs = 0;
unsigned char maxObjectCount = 7; // 7 is typically the maximum
// number of object which can
// be tracked by a human
static unsigned char maxObjectCount; // = 7; // 7 is typically the maximum
// number of object which can
// be tracked by a human
TrackedObject **trackedObjects;
};

View File

@ -2,9 +2,17 @@
#include "NetworkSync.h"
Roboid::Roboid() {}
#ifdef RC_DEBUG
#include <Arduino.h>
#endif
Roboid::Roboid(Perception *perception, Propulsion *propulsion) {
Roboid::Roboid() {
#ifdef RC_DEBUG
Serial.begin(115200);
#endif
}
Roboid::Roboid(Perception *perception, Propulsion *propulsion) : Roboid() {
this->perception = perception;
perception->roboid = this;
this->propulsion = propulsion;

22
Types.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
using UInt8 = unsigned char;
using SInt8 = signed char;
using Int8 = SInt8;
using UInt16 = unsigned short;
using SInt16 = signed short;
using Int16 = SInt16;
#ifdef ARDUINO_AVR_UNO
using UInt32 = unsigned long;
using SInt32 = signed long;
#else
using UInt32 = unsigned int;
using SInt32 = signed int;
#endif
using Int32 = SInt32;
using UInt64 = unsigned long long;
using SInt64 = signed long long;
using Int64 = SInt64;