RoboidControl-cpp/NetworkSync.cpp
2024-05-29 12:18:11 +02:00

435 lines
13 KiB
C++

#include "NetworkSync.h"
// #define RC_DEBUG 1
#ifdef RC_DEBUG
#include <Arduino.h>
#endif
#include "LinearAlgebra/Angle8.h"
#include "LinearAlgebra/Spherical.h"
#include "float16/float16.h"
#include <string.h>
NetworkSync::NetworkSync(Roboid *roboid) { this->roboid = roboid; }
void NetworkSync::ReceiveMessage(Roboid *roboid, unsigned char bytecount) {
networkPerception->ProcessPacket(roboid, buffer, bytecount);
switch (buffer[0]) {
case NetworkIdMsg:
// this->networkId = NetworkIdMsg;
ReceiveNetworkId();
break;
}
}
void NetworkSync::ReceiveNetworkId() {
this->networkId = buffer[1];
#ifdef RC_DEBUG
printf("_Received network Id %d\n", this->networkId);
#endif
PublishModel(roboid);
}
void NetworkSync::NewObject(InterestingThing *thing) {
if (thing == nullptr || thing->networkId != 0x00)
return;
unsigned char ix = 0;
buffer[ix++] = CreateMsg;
buffer[ix++] = thing->id;
buffer[ix++] = thing->type;
SendBuffer(ix);
#ifdef RC_DEBUG
printf("Sent CreateMsg %d %d\n", buffer[1], buffer[2]);
#endif
// PublishTrackedObject(roboid, obj);
}
void NetworkSync::PublishModel(Roboid *roboid) {
if (roboid->modelUrl == nullptr)
return;
int len = strlen(roboid->modelUrl);
if (len > 255)
return;
unsigned char ix = 0;
buffer[ix++] = 0x90; // modelMsg
buffer[ix++] = 0x00; // objectId
// SendVector3(buffer, &ix, position);
// Polar polar = Polar(Vector2(position));
// SendPolar(buffer, &ix, polar);
Spherical s = Spherical(roboid->modelPosition);
SendSpherical(buffer, &ix, s);
SendFloat16(buffer, &ix, roboid->modelScale);
buffer[ix++] = len;
// printf("send url %d, scale = %f \n", ix, sscale);
for (int urlIx = 0; urlIx < len; urlIx++) {
buffer[ix++] = roboid->modelUrl[urlIx];
}
SendBuffer(ix);
}
void NetworkSync::DestroyObject(InterestingThing *thing) {
unsigned char ix = 0;
buffer[ix++] = DestroyMsg;
buffer[ix++] = thing->id;
SendBuffer(ix);
#if RC_DEBUG
printf("Sent DestroyMsg %d %d\n", buffer[1], buffer[2]);
#endif
}
void NetworkSync::SendPose(Roboid *roboid) {
if (roboid->propulsion == nullptr)
return;
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);
unsigned char buffer[3 + 12 + 12] = {
PoseMsg,
0, // objectId;
Pose_LinearVelocity | Pose_AngularVelocity,
};
unsigned char ix = 3;
SendVector3(buffer, &ix, worldVelocity3);
SendVector3(buffer, &ix, worldAngularVelocity);
SendBuffer(ix);
}
void NetworkSync::SendVector3(unsigned char *data, unsigned char *startIndex,
const Vector3 v) {
SendSingle100(data, *startIndex, v.Right());
(*startIndex) += 4;
SendSingle100(data, *startIndex, v.Up());
(*startIndex) += 4;
SendSingle100(data, *startIndex, v.Forward());
(*startIndex) += 4;
}
void NetworkSync::SendQuaternion(unsigned char *data, const int startIndex,
const Quaternion q) {
Vector3 angles = Quaternion::ToAngles(q);
int ix = startIndex;
SendAngle8(data, ix++, angles.Right());
SendAngle8(data, ix++, angles.Up());
SendAngle8(data, ix++, angles.Forward());
}
void NetworkSync::SendPolar(unsigned char *data, unsigned char *startIndex,
Polar p) {
SendAngle8(data, *startIndex, (const float)p.angle);
SendSingle100(data, (*startIndex) + 1, p.distance);
}
void NetworkSync::SendSpherical(unsigned char *data, unsigned char *startIndex,
Spherical s) {
SendAngle8(data, (*startIndex)++, s.horizontalAngle);
SendAngle8(data, (*startIndex)++, s.verticalAngle);
// SendAngle8(data, startIndex++, s.distance);
SendFloat16(data, startIndex, s.distance);
}
// void NetworkSync::SendSpherical16(unsigned char *data, int startIndex,
// Spherical s) {
// SendAngle16(data, startIndex, s.horizontalAngle);
// SendAngle16(data, startIndex += 2, s.verticalAngle);
// SendSingle100(data, startIndex += 2, s.distance);
// }
// void NetworkSync::SendSpherical32(unsigned char *data, int startIndex,
// Spherical s) {
// SendAngle32(data, startIndex, s.horizontalAngle);
// SendAngle32(data, startIndex += 4, s.verticalAngle);
// SendSingle100(data, startIndex += 4, s.distance);
// }
void NetworkSync::SendQuat32(unsigned char *data, unsigned char *startIndex,
const Quaternion q) {
unsigned char qx = (char)(q.x * 127 + 128);
unsigned char qy = (char)(q.y * 127 + 128);
unsigned char qz = (char)(q.z * 127 + 128);
unsigned char qw = (char)(q.w * 255);
if (q.w < 0) {
qx = -qx;
qy = -qy;
qz = -qz;
qw = -qw;
}
// Serial.printf(" (%d) %d:%d:%d:%d ", startIndex, qx, qy, qz, qw);
data[(*startIndex)++] = qx;
data[(*startIndex)++] = qy;
data[(*startIndex)++] = qz;
data[(*startIndex)++] = qw;
}
void NetworkSync::SendAngle8(unsigned char *data, unsigned int startIndex,
const float angle) {
AngleUsing<signed char> packedAngle = AngleUsing<signed char>(angle);
data[startIndex] = packedAngle.GetValue();
}
// void NetworkSync::SendAngle16(unsigned char *data, unsigned int startIndex,
// const float angle) {
// AngleUsing<signed short> packedAngle = AngleUsing<signed short>(angle);
// signed short value = packedAngle.GetValue();
// data[startIndex] = value >> 8;
// data[startIndex + 1] = value & 0xFF;
// }
// void NetworkSync::SendAngle32(unsigned char *data, unsigned int startIndex,
// const float angle) {
// AngleUsing<signed long> packedAngle = AngleUsing<signed long>(angle);
// unsigned long value = packedAngle.GetValue();
// data[startIndex] = value >> 24 & 0xFF;
// data[startIndex + 1] = value >> 16 & 0xFF;
// data[startIndex + 2] = value >> 8 & 0xFF;
// data[startIndex + 3] = value & 0xFF;
// // Serial.printf(" %lu=%d:%d:%d:%d ", value, data[startIndex],
// // data[startIndex + 1], data[startIndex + 2],
// // data[startIndex + 3]);
// }
void NetworkSync::SendSingle100(unsigned char *data, unsigned int startIndex,
float value) {
// Sends a float with truncated 2 decimal precision
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::SendFloat16(unsigned char *data, unsigned char *startIndex,
float value) {
float16 value16 = float16(value);
short binary = value16.getBinary();
data[(*startIndex)++] = (binary >> 8) & 0xFF;
data[(*startIndex)++] = binary & 0xFF;
}
void NetworkSync::SendInt32(unsigned char *data, unsigned int startIndex,
Int32 value) {
for (unsigned char ix = 0; ix < 4; ix++) {
data[startIndex++] = ((unsigned char *)&value)[ix];
}
}
// static unsigned char buffer[100];
void NetworkSync::SendBuffer(unsigned char bufferSize) {}
void NetworkSync::PublishClient() {
unsigned char ix = 0;
buffer[ix++] = ClientMsg;
buffer[ix++] = 0; // No network ID
SendBuffer(ix);
#ifdef RC_DEBUG
printf("Sent new Client\n");
#endif
}
void NetworkSync::PublishTrackedObjects(Roboid *roboid,
InterestingThing **objects) {
int n = 0;
for (unsigned char objIx = 0; objIx < Perception::maxObjectCount; objIx++) {
InterestingThing *obj = objects[objIx];
if (obj == nullptr)
continue;
if (obj->sensor->type == Thing::ExternalType)
continue;
if (obj->confidence > 0) {
PublishTrackedObject(roboid, obj);
}
n++;
}
}
void NetworkSync::PublishTrackedObject(Roboid *roboid,
InterestingThing *object) {
if (object == nullptr || object->updated == false ||
object->networkId != 0x00) {
return;
}
// if (object->parentId != 0)
// return PublishRelativeObject(object);
Vector3 roboidPosition = roboid->GetPosition();
Quaternion roboidOrientation = roboid->GetOrientation();
// Vector3 localPosition = object->position.ToVector3();
Vector3 localPosition = Vector3(object->position);
Vector3 worldPosition = roboidPosition + roboidOrientation * localPosition;
Quaternion worldOrientation = roboidOrientation * object->orientation;
unsigned char ix = 0;
buffer[ix++] = PoseMsg; // Position2DMsg;
buffer[ix++] = object->id; // objectId;
buffer[ix++] = Pose_Position | Pose_Orientation;
// SendPolar(buffer, &ix, polar); // 3 bytes
SendVector3(buffer, &ix, worldPosition);
// SendQuat32(buffer, &ix, worldOrientation);
SendBuffer(ix);
object->updated = false;
#if DEBUG
printf("PublishTrackedObj [%d/%d] (%f %f)\n", object->networkId, buffer[1],
worldPosition.Right(), worldPosition.Forward());
#endif
}
// void NetworkSync::PublishTrackedObjects(Buffer sendBuffer,
// InterestingThing **objects) {
// for (unsigned char objIx = 0; objIx < Perception::maxObjectCount; objIx++)
// {
// InterestingThing *obj = objects[objIx];
// if (obj == nullptr)
// continue;
// if (obj->networkId != 0x00)
// continue; // object is external
// // if (obj->sensor->type == Thing::ExternalType)
// // continue;
// // tmp
// obj->id = objIx;
// PublishTrackedObject(sendBuffer, obj);
// }
// }
// void NetworkSync::PublishTrackedObject(Buffer sendBuffer,
// InterestingThing *object) {
// Vector2 worldPosition2 =
// Vector2::Rotate(Vector2::forward * object->position.distance,
// -object->position.horizontalAngle);
// 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.Right());
// Serial.print(", ");
// Serial.print(worldPosition3.Up());
// Serial.print(", ");
// Serial.println(worldPosition3.Forward());
// #else
// const UInt16 bufferSize = 3 + 12;
// UInt8 buffer[bufferSize] = {
// PoseMsg,
// (UInt8)object->id,
// Pose_Position,
// };
// unsigned char ix = 3;
// SendVector3(buffer, &ix, worldPosition3);
// sendBuffer(buffer, bufferSize);
// #endif
// }
// void NetworkSync::PublishRelativeObject(Buffer sendBuffer, UInt8 parentId,
// InterestingThing *object) {
// const UInt16 bufferSize = 4 + 12;
// UInt8 buffer[bufferSize] = {
// RelativePoseMsg,
// (UInt8)parentId,
// (UInt8)object->id,
// Pose_Position,
// };
// unsigned char ix = 4;
// SendSpherical(buffer, &ix, object->position);
// // SendVector3(buffer, ix, worldPosition3);
// sendBuffer(buffer, bufferSize);
// }
void NetworkSync::SendPoseMsg(Buffer 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.Right());
Serial.print(", ");
Serial.print(worldVelocity3.Up());
Serial.print(", ");
Serial.print(worldVelocity3.Forward());
Serial.print(" AngularVelocity ");
Serial.print(worldAngularVelocity.Right());
Serial.print(", ");
Serial.print(worldAngularVelocity.Up());
Serial.print(", ");
Serial.println(worldAngularVelocity.Forward());
#else
const unsigned int bufferSize = 3 + 12 + 12;
unsigned char buffer[bufferSize] = {
PoseMsg,
0, // objectId;
Pose_LinearVelocity | Pose_AngularVelocity,
};
unsigned char ix = 3;
SendVector3(buffer, &ix, worldVelocity3);
SendVector3(buffer, &ix, worldAngularVelocity);
sendBuffer(buffer, bufferSize);
#endif
}
void NetworkSync::SendDestroyObject(Buffer sendBuffer, InterestingThing *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
}
void NetworkSync::SendInvestigateThing(InterestingThing *thing) {
#ifdef RC_DEBUG
printf("Investigate [%d/%d]\n", thing->networkId, thing->id);
#endif
unsigned char ix = 0;
buffer[ix++] = InvestigateMsg;
buffer[ix++] = thing->networkId;
buffer[ix++] = thing->id;
SendBuffer(ix);
}
void NetworkSync::SendText(const char *s) {
unsigned char length;
for (length = 0; length < 253; length++) {
if (s[length] == '\0')
break;
}
if (length >= 253)
return;
unsigned char ix;
buffer[ix++] = 0xB0;
buffer[ix++] = length;
for (int urlIx = 0; urlIx < length; urlIx++)
buffer[ix++] = s[urlIx];
SendBuffer(ix);
}