477 lines
14 KiB
C++
477 lines
14 KiB
C++
#include "NetworkSync.h"
|
|
|
|
// #define RC_DEBUG 1
|
|
|
|
#ifdef RC_DEBUG
|
|
#include <Arduino.h>
|
|
#endif
|
|
|
|
#include "LinearAlgebra/Angle8.h"
|
|
#include "LinearAlgebra/AngleUsing.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;
|
|
}
|
|
}
|
|
|
|
#include <Arduino.h>
|
|
|
|
void NetworkSync::ReceiveNetworkId() {
|
|
this->networkId = buffer[1];
|
|
#ifdef RC_DEBUG
|
|
printf("_Received network Id %d\n", this->networkId);
|
|
#endif
|
|
PublishModel(roboid);
|
|
for (unsigned char childIx = 0; childIx < roboid->childCount; childIx++) {
|
|
Thing* child = roboid->GetChild(childIx);
|
|
if (child != nullptr)
|
|
PublishRelativeThing(child, true);
|
|
}
|
|
}
|
|
|
|
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] %d\n", networkId, buffer[1], buffer[2]);
|
|
#endif
|
|
|
|
thing->updated = true;
|
|
PublishTrackedObject(roboid, thing);
|
|
}
|
|
|
|
void NetworkSync::PublishRelativeThing(Thing* thing, bool recurse) {
|
|
Thing* parentThing = thing->GetParent();
|
|
|
|
unsigned char ix = 0;
|
|
buffer[ix++] = RelativePoseMsg;
|
|
buffer[ix++] = thing->id;
|
|
if (parentThing != nullptr)
|
|
buffer[ix++] = parentThing->id;
|
|
else
|
|
buffer[ix++] = 0x00;
|
|
SendSpherical16(buffer, &ix, thing->position);
|
|
SendBuffer(ix);
|
|
|
|
PublishModel(thing);
|
|
|
|
if (recurse) {
|
|
for (unsigned char childIx = 0; childIx < thing->childCount; childIx++) {
|
|
Thing* child = thing->GetChild(childIx);
|
|
if (child != nullptr)
|
|
PublishRelativeThing(child, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void NetworkSync::PublishModel(Roboid* roboid) {
|
|
if (roboid->modelUrl == nullptr)
|
|
return;
|
|
|
|
unsigned char len = strlen(roboid->modelUrl);
|
|
if (len > 255)
|
|
return;
|
|
|
|
unsigned char ix = 0;
|
|
buffer[ix++] = 0x90; // modelMsg
|
|
buffer[ix++] = 0x00; // objectId
|
|
Spherical s = Spherical::zero; //(roboid->modelPosition);
|
|
SendSpherical(buffer, &ix, s);
|
|
SendFloat16(buffer, &ix, 1); // roboid->modelScale);
|
|
|
|
buffer[ix++] = len;
|
|
for (int urlIx = 0; urlIx < len; urlIx++)
|
|
buffer[ix++] = roboid->modelUrl[urlIx];
|
|
|
|
SendBuffer(ix);
|
|
}
|
|
|
|
void NetworkSync::PublishModel(Thing* thing) {
|
|
if (thing->modelUrl == nullptr)
|
|
return;
|
|
|
|
unsigned char len = strlen(thing->modelUrl);
|
|
if (len > 255)
|
|
return;
|
|
|
|
unsigned char ix = 0;
|
|
buffer[ix++] = 0x90; // modelMsg
|
|
buffer[ix++] = thing->id; // objectId
|
|
Spherical s = Spherical::zero; // Spherical(thing->modelPosition);
|
|
SendSpherical(buffer, &ix, s);
|
|
SendFloat16(buffer, &ix, 1); // thing->modelScale);
|
|
|
|
buffer[ix++] = len;
|
|
for (int urlIx = 0; urlIx < len; urlIx++)
|
|
buffer[ix++] = thing->modelUrl[urlIx];
|
|
|
|
SendBuffer(ix);
|
|
}
|
|
|
|
void NetworkSync::SendDestroyThing(InterestingThing* thing) {
|
|
if (networkId == 0) // We're not connected to a site yet
|
|
return;
|
|
|
|
unsigned char ix = 0;
|
|
buffer[ix++] = DestroyMsg;
|
|
buffer[ix++] = thing->id;
|
|
SendBuffer(ix);
|
|
|
|
#if RC_DEBUG
|
|
printf("Sent DestroyMsg [%d/%d]\n", thing->networkId, thing->id);
|
|
#endif
|
|
}
|
|
|
|
void NetworkSync::SendPose(Roboid* roboid, bool recurse) {
|
|
if (networkId == 0) // We're not connected to a site yet
|
|
return;
|
|
|
|
unsigned char ix = 0;
|
|
buffer[ix++] = PoseMsg;
|
|
buffer[ix++] = 0x00;
|
|
buffer[ix++] = Pose_Position | Pose_Orientation;
|
|
SendSpherical(buffer, &ix, Spherical::FromVector3(roboid->GetPosition()));
|
|
SendQuat32(buffer, &ix, roboid->GetOrientation());
|
|
SendBuffer(ix);
|
|
|
|
#if RC_DEBUG
|
|
// printf("Sent PoseMsg [%d/%d]\n", networkId, buffer[1]);
|
|
#endif
|
|
|
|
if (recurse) {
|
|
for (unsigned char childIx = 0; childIx < roboid->childCount; childIx++) {
|
|
Thing* child = roboid->GetChild(childIx);
|
|
if (child != nullptr)
|
|
SendPose(child, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void NetworkSync::SendPose(Thing* thing, bool recurse) {
|
|
unsigned char ix = 0;
|
|
buffer[ix++] = PoseMsg;
|
|
buffer[ix++] = thing->id;
|
|
buffer[ix++] = Pose_Position | Pose_Orientation;
|
|
SendSpherical16(buffer, &ix, thing->position);
|
|
SendQuat32(buffer, &ix, thing->orientation);
|
|
SendBuffer(ix);
|
|
|
|
#if RC_DEBUG
|
|
printf("Sent PoseMsg Thing [%d/%d]\n", networkId, buffer[1]);
|
|
#endif
|
|
|
|
if (recurse) {
|
|
for (unsigned char childIx = 0; childIx < thing->childCount; childIx++) {
|
|
Thing* child = thing->GetChild(childIx);
|
|
if (child != nullptr)
|
|
SendPose(thing->GetChild(childIx), true);
|
|
}
|
|
}
|
|
}
|
|
|
|
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) {
|
|
if (networkId == 0) // We're not connected to a site yet
|
|
return;
|
|
|
|
int n = 0;
|
|
for (unsigned char objIx = 0; objIx < Perception::maxObjectCount; objIx++) {
|
|
InterestingThing* obj = objects[objIx];
|
|
if (obj == nullptr)
|
|
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 = object->position.ToVector3();
|
|
Vector3 worldPosition = roboidPosition + roboidOrientation * localPosition;
|
|
Quaternion worldOrientation =
|
|
roboidOrientation * object->orientation.ToQuaternion();
|
|
|
|
unsigned char ix = 0;
|
|
buffer[ix++] = PoseMsg; // Position2DMsg;
|
|
buffer[ix++] = object->id; // objectId;
|
|
buffer[ix++] = Pose_Position | Pose_Orientation;
|
|
SendSpherical(buffer, &ix, Spherical::FromVector3(worldPosition));
|
|
SendQuat32(buffer, &ix, worldOrientation);
|
|
// SendPolar(buffer, &ix, polar); // 3 bytes
|
|
// SendVector3(buffer, &ix, worldPosition);
|
|
// SendQuat32(buffer, &ix, worldOrientation);
|
|
SendBuffer(ix);
|
|
|
|
#if RC_DEBUG
|
|
printf("Sent Thing PoseMsg [%d/%d] %d\n", networkId, buffer[1], object->type);
|
|
#endif
|
|
|
|
object->updated = false;
|
|
|
|
#if RC_DEBUG
|
|
// printf("PublishTrackedObj [%d/%d] (%f %f)\n", object->networkId, buffer[1],
|
|
// worldPosition.Right(), worldPosition.Forward());
|
|
#endif
|
|
}
|
|
|
|
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::SendDestroyThing(Buffer sendBuffer, InterestingThing*
|
|
// thing) {
|
|
// unsigned char ix = 0;
|
|
// buffer[ix++] = DestroyMsg;
|
|
// buffer[ix++] = thing->id;
|
|
// SendBuffer(ix);
|
|
// #ifdef RC_DEBUG
|
|
// printf("Sent DestroyThing [%d/%d]", thing->networkId, thing->id);
|
|
// #endif
|
|
// }
|
|
|
|
void NetworkSync::SendInvestigate(InterestingThing* thing) {
|
|
unsigned char ix = 0;
|
|
buffer[ix++] = InvestigateMsg;
|
|
buffer[ix++] = thing->networkId;
|
|
buffer[ix++] = thing->id;
|
|
SendBuffer(ix);
|
|
#ifdef RC_DEBUG
|
|
printf("Sent Investigate [%d/%d]\n", thing->networkId, thing->id);
|
|
#endif
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void NetworkSync::SendInt(const int x) {
|
|
String s = String(x);
|
|
byte length = s.length();
|
|
|
|
unsigned char ix;
|
|
buffer[ix++] = 0xB0;
|
|
buffer[ix++] = length;
|
|
for (int urlIx = 0; urlIx < length; urlIx++)
|
|
buffer[ix++] = s[urlIx];
|
|
|
|
SendBuffer(ix);
|
|
}
|
|
|
|
// Low-level functions
|
|
|
|
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.ToFloat());
|
|
SendSingle100(data, (*startIndex) + 1, p.distance);
|
|
}
|
|
|
|
void NetworkSync::SendSpherical(unsigned char* data,
|
|
unsigned char* startIndex,
|
|
Spherical s) {
|
|
SendAngle8(data, (*startIndex)++, s.horizontal.ToFloat());
|
|
SendAngle8(data, (*startIndex)++, s.vertical.ToFloat());
|
|
SendFloat16(data, startIndex, s.distance);
|
|
}
|
|
|
|
void NetworkSync::SendSpherical16(unsigned char* data,
|
|
unsigned char* startIndex,
|
|
Spherical16 s) {
|
|
SendAngle8(data, (*startIndex)++, s.horizontal.ToFloat());
|
|
SendAngle8(data, (*startIndex)++, s.vertical.ToFloat());
|
|
SendFloat16(data, startIndex, 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) {
|
|
AngleOf<signed char> packedAngle2 = AngleOf<signed char>(angle);
|
|
data[startIndex] = packedAngle2.GetBinary();
|
|
}
|
|
|
|
// 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];
|
|
}
|
|
}
|
|
|
|
void NetworkSync::SendBuffer(unsigned char bufferSize) {}
|