Serial out

First working example of sending data back to the remote. For now we send some dummy data.
This commit is contained in:
philsson 2018-09-30 21:00:46 +02:00
parent 21164824f5
commit 4e7aeee1d9
5 changed files with 250 additions and 67 deletions

View File

@ -19,6 +19,7 @@
"string": "cpp", "string": "cpp",
"initializer_list": "cpp", "initializer_list": "cpp",
"string_view": "cpp", "string_view": "cpp",
"utility": "cpp" "utility": "cpp",
"algorithm": "cpp"
} }
} }

View File

@ -29,7 +29,7 @@ OSCErrorCode error;
// Start "on" // Start "on"
unsigned int ledState = HIGH; unsigned int ledState = HIGH;
typedef struct Packet { typedef struct PacketOut {
int16_t MagicWordLow; int16_t MagicWordLow;
int16_t MagicWordHigh; int16_t MagicWordHigh;
@ -46,21 +46,34 @@ typedef struct Packet {
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
const int bufferSize = sizeof(Packet); // Size of Packet struct PacketIn {
uint8_t buffer[bufferSize];
int16_t BatteryLevel;
int16_t Mode;
uint8_t checksum;
} __attribute__ ((__packed__));
Packet* pPacket = (Packet*)buffer; const int bufferOutSize = sizeof(PacketOut); // Size of Packet
uint8_t bufferOut[bufferOutSize];
PacketOut* pPacketOut = (PacketOut*)bufferOut;
const int bufferInSize = sizeof(PacketIn);
uint8_t bufferIn[bufferInSize];
PacketIn* pPacketIn = (PacketIn*)bufferIn;
void calcChecksum() void calcChecksum()
{ {
uint16_t sum = 0; uint16_t sum = 0;
for (int i = 4; i < (bufferSize - 1); i++) for (int i = 4; i < (bufferOutSize - 1); i++)
{ {
sum += buffer[i]; sum += bufferOut[i];
} }
pPacket->checksum = (uint8_t)(sum & 0xFF); pPacketOut->checksum = (uint8_t)(sum & 0xFF);
//Serial.print("sum: "); //Serial.print("sum: ");
//Serial.println(sum); //Serial.println(sum);
//Serial.print("checksum: "); //Serial.print("checksum: ");
@ -79,22 +92,22 @@ void setup() {
Udp.begin(localPort); Udp.begin(localPort);
// Initialize the packet // Initialize the packet
pPacket->MagicWordLow = 0x0DED; pPacketOut->MagicWordLow = 0x0DED;
pPacket->MagicWordHigh = 0x0DEC; pPacketOut->MagicWordHigh = 0x0DEC;
pPacket->Throttle = 1; pPacketOut->Throttle = 1;
pPacket->Steering = 2; pPacketOut->Steering = 2;
pPacket->Kp = 3; pPacketOut->Kp = 3;
pPacket->Ki = 4; pPacketOut->Ki = 4;
pPacket->Kd = 5; pPacketOut->Kd = 5;
pPacket->Enabled = false; pPacketOut->Enabled = false;
pPacket->checksum = 0; pPacketOut->checksum = 0;
} }
void sendPacket() void sendPacket()
{ {
calcChecksum(); calcChecksum();
Serial.write(buffer, bufferSize); Serial.write(bufferOut, bufferOutSize);
} }
void OSCMsgReceive() void OSCMsgReceive()
@ -122,17 +135,24 @@ void OSCMsgReceive()
void sendUdp(OSCMessage* pMessage) void sendUdp(OSCMessage* pMessage)
{ {
IPAddress remoteIp = Udp.remoteIP(); IPAddress remoteIp = Udp.remoteIP();
/* Address is exchanged for 0.0.0.0 so when
* forwarding from the other board the
* package does not reach the phone
* TODO: Check for address other than 0.0.0.0
* before saving
if (remoteIp != outIp) if (remoteIp != outIp)
{ {
outIp = remoteIp; outIp = remoteIp;
Serial.print("New source address: "); Serial.print("New source address: ");
Serial.println(outIp); Serial.println(outIp);
} }
*/
//send osc message back to controll object in TouchOSC //send osc message back to controll object in TouchOSC
//Local feedback is turned off in the TouchOSC interface. //Local feedback is turned off in the TouchOSC interface.
//The button is turned on in TouchOSC interface whe the conrol receives this message. //The button is turned on in TouchOSC interface whe the conrol receives this message.
Udp.beginPacket(Udp.remoteIP(), outPort); Udp.beginPacket(outIp, outPort);
pMessage->send(Udp); // send the bytes pMessage->send(Udp); // send the bytes
Udp.endPacket(); // mark the end of the OSC Packet Udp.endPacket(); // mark the end of the OSC Packet
pMessage->empty(); // free space occupied by message pMessage->empty(); // free space occupied by message
@ -146,7 +166,7 @@ void funcEnabled(OSCMessage &msg, int addrOffset){
msgOUT.add(!ledState); msgOUT.add(!ledState);
sendUdp(&msgOUT); sendUdp(&msgOUT);
pPacket->Enabled = !ledState; pPacketOut->Enabled = !ledState;
//Serial.println( ledState ? "Robot disabled" : "Robot enabled"); //Serial.println( ledState ? "Robot disabled" : "Robot enabled");
} }
@ -157,7 +177,7 @@ void funcThrottle(OSCMessage &msg, int addrOffset ){
OSCMessage msgOUT("/Fader/Throttle"); OSCMessage msgOUT("/Fader/Throttle");
msgOUT.add(value); msgOUT.add(value);
sendUdp(&msgOUT); sendUdp(&msgOUT);
pPacket->Throttle = value; pPacketOut->Throttle = value;
} }
void funcSteering(OSCMessage &msg, int addrOffset ){ void funcSteering(OSCMessage &msg, int addrOffset ){
@ -166,7 +186,7 @@ void funcSteering(OSCMessage &msg, int addrOffset ){
OSCMessage msgOUT("/Fader/Steering"); OSCMessage msgOUT("/Fader/Steering");
msgOUT.add(value); msgOUT.add(value);
sendUdp(&msgOUT); sendUdp(&msgOUT);
pPacket->Steering = value; pPacketOut->Steering = value;
} }
void funcKp(OSCMessage &msg, int addrOffset ){ void funcKp(OSCMessage &msg, int addrOffset ){
@ -175,7 +195,7 @@ void funcKp(OSCMessage &msg, int addrOffset ){
OSCMessage msgOUT("/Gain/Kp"); OSCMessage msgOUT("/Gain/Kp");
msgOUT.add(value); msgOUT.add(value);
sendUdp(&msgOUT); sendUdp(&msgOUT);
pPacket->Kp = value; pPacketOut->Kp = value;
// Redo this for label // Redo this for label
OSCMessage msgLABEL("/Gain/KpOut"); OSCMessage msgLABEL("/Gain/KpOut");
@ -189,7 +209,7 @@ void funcKi(OSCMessage &msg, int addrOffset ){
OSCMessage msgOUT("/Gain/Ki"); OSCMessage msgOUT("/Gain/Ki");
msgOUT.add(value); msgOUT.add(value);
sendUdp(&msgOUT); sendUdp(&msgOUT);
pPacket->Ki = value; pPacketOut->Ki = value;
// Redo this for label // Redo this for label
OSCMessage msgLABEL("/Gain/KiOut"); OSCMessage msgLABEL("/Gain/KiOut");
@ -203,7 +223,7 @@ void funcKd(OSCMessage &msg, int addrOffset ){
OSCMessage msgOUT("/Gain/Kd"); OSCMessage msgOUT("/Gain/Kd");
msgOUT.add(value); msgOUT.add(value);
sendUdp(&msgOUT); sendUdp(&msgOUT);
pPacket->Kd = value; pPacketOut->Kd = value;
// Redo this for label // Redo this for label
OSCMessage msgLABEL("/Gain/KdOut"); OSCMessage msgLABEL("/Gain/KdOut");
@ -211,6 +231,72 @@ void funcKd(OSCMessage &msg, int addrOffset ){
sendUdp(&msgLABEL); sendUdp(&msgLABEL);
} }
// Send OSC packets updating touchOSC on the mobile
void remotePresentation()
{
OSCMessage msgLABEL("/battery");
msgLABEL.add(pPacketIn->BatteryLevel);
sendUdp(&msgLABEL);
// TODO: Add the desired data to be forwarded from pPacketIn
}
bool parsePacket()
{
static uint8_t magicWord[4];
static uint32_t* pMagicWord = (uint32_t*)magicWord;
static uint8_t byteCounter = 0;
static const uint8_t payloadSize = sizeof(PacketIn);
static uint8_t payload[payloadSize];
static PacketIn* pPacketInWorker = (PacketIn*)payload;
uint8_t newByte = Serial.read();
// We have the header correct
if (*pMagicWord == 0xDEC0DED)
{
payload[byteCounter++] = newByte;
static uint16_t sum = 0;
if (byteCounter >= payloadSize)
{
*pMagicWord = 0; // Unvalidate the magic word
byteCounter = 0; // Reset the read counter
uint8_t checksum = sum & 0xFF;
sum = 0;
if (checksum == pPacketInWorker->checksum)
{
// If robot enabled we blink
// when receiving data
if (pPacketOut->Enabled)
{
ledState = !ledState;
digitalWrite(BUILTIN_LED, ledState);
}
*pPacketIn = *((PacketIn*)payload);
remotePresentation();
return true; // new package available
}
}
sum +=newByte; // placed here not to include the checksum
}
else
{
*pMagicWord = *pMagicWord >> 8 | newByte << 8*3; // Works on revo
//Serial.print("Byte: ");
//Serial.println(newByte);
}
return false;
}
void loop() { void loop() {
OSCMsgReceive(); OSCMsgReceive();
@ -226,5 +312,11 @@ void loop() {
previousMillis = currentMillis; previousMillis = currentMillis;
sendPacket(); // Send on UART sendPacket(); // Send on UART
} }
if (Serial.available())
{
parsePacket();
}
} }

View File

@ -37,8 +37,8 @@ RawSerial serial(PA_2, PA_3, 250000);
RCProtocol RC; RCProtocol RC;
// Pool to send Remote Control packages between threads // Pool to send Remote Control packages between threads
MemoryPool<RCProtocol::Packet, 16> mpool; MemoryPool<RCProtocol::PacketIn, 16> mpool;
Queue<RCProtocol::Packet, 16> RCQueue; Queue<RCProtocol::PacketIn, 16> RCQueue;
// MPU setup // MPU setup
SPI spi(PA_7, PA_6, PA_5); //define the SPI (mosi, miso, sclk). Default frequency is 1Mhz SPI spi(PA_7, PA_6, PA_5); //define the SPI (mosi, miso, sclk). Default frequency is 1Mhz
@ -73,12 +73,12 @@ void runControl()
static ImuFusion imuFusion(&imu); static ImuFusion imuFusion(&imu);
static float controlOutput(0.0f); static float controlOutput(0.0f);
static RCProtocol::Packet remote; static RCProtocol::PacketIn remote;
osEvent evt = RCQueue.get(0); osEvent evt = RCQueue.get(0);
if (evt.status == osEventMessage) { if (evt.status == osEventMessage) {
RCProtocol::Packet* pPacket = (RCProtocol::Packet*)evt.value.p; RCProtocol::PacketIn* pPacketIn = (RCProtocol::PacketIn*)evt.value.p;
remote = *pPacket; remote = *pPacketIn;
mpool.free(pPacket); mpool.free(pPacketIn);
throttleControl.setGainScaling(remote.Ki, remote.Kd); throttleControl.setGainScaling(remote.Ki, remote.Kd);
//throttleControl.setGainScaling(0, 0); //throttleControl.setGainScaling(0, 0);
@ -183,7 +183,7 @@ void runControl()
/* -------------------------- /* --------------------------
Lastly the steering is added Lastly the steering is added
straight on the output straight on the output.
-------------------------- */ -------------------------- */
float steering = remote.Steering*0.5; float steering = remote.Steering*0.5;
if (remote.Steering < 50 && remote.Steering > -50) {steering = 0;} if (remote.Steering < 50 && remote.Steering > -50) {steering = 0;}
@ -204,20 +204,38 @@ void serialISR()
// Receive // Receive
while (serial.readable()) while (serial.readable())
{ {
bool newPackage = RC.appendByte(serial.getc()); bool newPackage = RC.readByte(serial.getc());
if (newPackage) if (newPackage)
{ {
RCProtocol::Packet* pPacket = mpool.alloc(); RCProtocol::PacketIn* pPacketIn = mpool.alloc();
*pPacket = RC.read(); *pPacketIn = RC.readPacket();
RCQueue.put(pPacket); RCQueue.put(pPacketIn);
} }
} }
// Sleep some? }
//Thread::wait(1);
void serialWrite()
{
RCProtocol::PacketOut packetOut;
packetOut.BatteryLevel = 123;
packetOut.Mode = 213;
RC.setOutput(packetOut);
bool done;
// Transmit while (true)
// serial.putc()... {
while (!serial.writeable());
serial.putc(RC.writeByte(done));
// If we successfully complete
// writing a packet we sleep
if (done)
{
Thread::wait(500);
}
}
} }
// This context just pulses the blue LED // This context just pulses the blue LED
@ -284,7 +302,7 @@ int main() {
// Start the pulsing blue led // Start the pulsing blue led
ledBlue.period_ms(10); // Any period. This will be overwritten by motors ledBlue.period_ms(10); // Any period. This will be overwritten by motors
Thread ledPulseThread; Thread ledPulseThread;
//ledPulseThread.start(callback(&pulseLedContext)); ledPulseThread.start(callback(&pulseLedContext));
Thread::wait(100); Thread::wait(100);
// Serial in / out // Serial in / out
@ -295,6 +313,10 @@ int main() {
// ISR won't be called if the serial is not emptied first. // ISR won't be called if the serial is not emptied first.
serialISR(); serialISR();
// Serial Write thread
Thread serialWriteThread;
serialWriteThread.start(callback(&serialWrite));
// Enable/Activate the Gyro interrupt // Enable/Activate the Gyro interrupt
imu.enableInterrupt(); imu.enableInterrupt();

View File

@ -43,14 +43,14 @@ void testParser()
dummy[15] = 0x00; // !?? calculate dummy[15] = 0x00; // !?? calculate
RCProtocol::Packet pkt = *((RCProtocol::Packet*)(dummy+4)); RCProtocol::PacketIn pkt = *((RCProtocol::PacketIn*)(dummy+4));
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
bool newPackage = RCProt.appendByte(dummy[i]); bool newPackage = RCProt.readByte(dummy[i]);
if (newPackage) if (newPackage)
{ {
RCProtocol::Packet prot = RCProt.read(); RCProtocol::PacketIn prot = RCProt.readPacket();
} }
} }
} }
@ -58,26 +58,27 @@ void testParser()
} }
RCProtocol::RCProtocol() RCProtocol::RCProtocol()
: m_packet() : m_packetIn()
, m_packetOut()
//, m_semaphore(0) //, m_semaphore(0)
{ {
} }
RCProtocol::Packet RCProtocol::read() RCProtocol::PacketIn RCProtocol::readPacket()
{ {
//m_semaphore.wait(); //m_semaphore.wait();
return m_packet; return m_packetIn;
//m_semaphore.release(); //m_semaphore.release();
} }
bool RCProtocol::appendByte(uint8_t newByte) bool RCProtocol::readByte(uint8_t newByte)
{ {
static uint8_t header[4]; // 4 bytes for our header static uint8_t header[4]; // 4 bytes for our header
static uint32_t* pHeader32 = (uint32_t*)header; static uint32_t* pHeader32 = (uint32_t*)header;
static const int payloadSize = sizeof(RCProtocol::Packet); static const int payloadSize = sizeof(RCProtocol::PacketIn);
static uint8_t payload[12]; static uint8_t payload[payloadSize];
static RCProtocol::Packet* pPacket = (RCProtocol::Packet*)payload; static RCProtocol::PacketIn* pPacketIn = (RCProtocol::PacketIn*)payload;
static int byteCounter = 0; static int byteCounter = 0;
@ -95,11 +96,11 @@ bool RCProtocol::appendByte(uint8_t newByte)
uint8_t checksum = sum & 0xFF; uint8_t checksum = sum & 0xFF;
sum = 0; sum = 0;
if (checksum == pPacket->Checksum) if (checksum == pPacketIn->Checksum)
{ {
// Create package // Create package
//m_semaphore.wait(); //m_semaphore.wait();
m_packet = *((Packet*)payload); m_packetIn = *((PacketIn*)payload);
//m_semaphore.release(); //m_semaphore.release();
return true; // new package available return true; // new package available
} }
@ -113,4 +114,40 @@ bool RCProtocol::appendByte(uint8_t newByte)
return false; // Continue parsing return false; // Continue parsing
} }
uint8_t RCProtocol::writeByte(bool& done)
{
static const uint8_t* pByte = (uint8_t*)&m_packetOut;
static uint8_t i = 0;
static const uint8_t max = sizeof(RCProtocol::PacketOut);
uint8_t outByte = pByte[i];
i++;
i = i % max;
done = (i == 0) ? true : false;
return outByte;
}
void RCProtocol::setOutput(RCProtocol::PacketOut& packetOut)
{
m_packetOut = packetOut;
// Now we calculate the checksum
uint8_t* pByte = (uint8_t*)&m_packetOut;
uint16_t sum = 0;
for (int i = 4; i < sizeof(RCProtocol::PacketOut) - 1; i++)
{
sum += pByte[i];
}
uint8_t checksum = sum & 0xFF;
m_packetOut.Checksum = checksum;
}
} }

View File

@ -11,7 +11,7 @@ class RCProtocol
public: public:
struct Packet { struct PacketIn {
int16_t Throttle; int16_t Throttle;
int16_t Steering; int16_t Steering;
@ -24,13 +24,34 @@ public:
uint8_t Checksum; uint8_t Checksum;
Packet() PacketIn()
: Throttle(0.0f) : Throttle(0)
, Steering(0.0f) , Steering(0)
, Kp(0.0f) , Kp(0)
, Ki(0.0f) , Ki(0)
, Kd(0.0f) , Kd(0)
, Enabled(false) , Enabled(false)
, Checksum(0)
{
}
} __attribute__ ((__packed__));
struct PacketOut {
int32_t MagicWord;
int16_t BatteryLevel;
int16_t Mode;
uint8_t Checksum;
PacketOut()
: MagicWord(0xDEC0DED)
, BatteryLevel(0)
, Mode(0)
, Checksum(0)
{ {
} }
@ -38,12 +59,20 @@ public:
RCProtocol(); RCProtocol();
//! Read the latest package //! Append a byte to read until we have a hole package.
RCProtocol::Packet read();
//! Append a byte until we have a package to read.
//! Returns true when a hole package is available //! Returns true when a hole package is available
bool appendByte(uint8_t newByte); bool readByte(uint8_t newByte);
//! Read the latest package
RCProtocol::PacketIn readPacket();
//! Generate a byte to write
//! @done is set to true when a hole packet
//! has been passed
uint8_t writeByte(bool& done);
//! Set the data to be written
void setOutput(RCProtocol::PacketOut& packetOut);
//Semaphore m_semaphore; //Semaphore m_semaphore;
@ -51,7 +80,9 @@ public:
private: private:
RCProtocol::Packet m_packet; RCProtocol::PacketIn m_packetIn;
RCProtocol::PacketOut m_packetOut;
}; };