Sorting Incoming Radio Data for DAC Output Coding Help

Started by ItzGenX, July 04, 2020, 06:15:29 PM

ItzGenX

Before I begin, I'd like to mention that I am pretty new at this, like 2 weeks kind of new.  I have some C knowledge from high school, but that was 20 years ago, and everything was kind of lost.  So everything is a refresher course or full blown learning intervention.  Anyhow, go easy on me.

My project setup and functioning goal:
4 wireless torque transducers are on 4 rotating axles of a vehicle reporting torque telemetry to a central gateway receiver.  The gateway receiver takes the incoming telemetry, combines the sum value of all 4, then converts the value to a DAC output for a data acquisition unit (race car's ECU).  This results in an analog voltage signal that the ECU can report back as the total real time torque the engine is producing to the axle shafts.  I call it an "onboard chassis dyno".

The setup:
All 5 units, gateway receiver and 4 remote torque sensing nodes are running on Moteino M0's with RFM69HCW radios.  The nodes also operate a HX711 load cell amplifier to read the strain gauge adhered to each axle.

Don't mind my dumb comments here and there, I leave them as personal notes to help understand what it is or how it works.

I have all of the nodes able to report their values and send them as follows:
Torque Sensing Nodes
#include <RFM69.h>         
#include <RFM69_ATC.h>  
#include <SPI.h>
#include "HX711.h"

//******************************************************************************
//Call the load cell
HX711 scale;
  //Load cell pin settings
  uint8_t dataPin = 3; 
  uint8_t clockPin = 2;

uint32_t start, stop; //not sure what this setting is, probably the power on/off of the HX7111
volatile float f; //float value to read strain value
char ScaleString[7]; //definition for a string value converted from the float later on

//Done calling the load cell
//******************************************************************************
//******************************************************************************
//RADIO SETTINGS
// Addresses for this node. CHANGE THESE FOR EACH NODE!

#define NETWORKID     100   // Must be the same for all nodes
#define MYNODEID      4   // My node ID
#define TONODEID      1   // Destination node ID

// RFM69 frequency, uncomment the frequency of your module:

//#define FREQUENCY   RF69_433MHZ
#define FREQUENCY     RF69_915MHZ

// AES encryption (or not):

#define ENCRYPT       true // Set to "true" to use encryption
#define ENCRYPTKEY    "sampleEncryptKey" // Use the same 16-byte key on all nodes

// Use ACKnowledge when sending messages (or not):

#define USEACK        false // Request ACKs or not

#define ENABLE_ATC    //comment out this line to disable AUTO TRANSMISSION CONTROL
#define ATC_RSSI      -50

#define SERIAL_BAUD   115200 //choose baud rate

// Create a library object for our RFM69HCW module:
// Create ATC library object if activated
#ifdef ENABLE_ATC
  RFM69_ATC radio;
#else
  RFM69 radio;
#endif
//******************************************************************************


void setup()
{
  //Start load cell setup
  scale.begin(dataPin, clockPin);
  scale.set_scale(420.0983);
  scale.tare();
  //End load cell setup
   
  Serial.begin(SERIAL_BAUD);
  Serial.print("Node ");
  Serial.print(MYNODEID,DEC);
  Serial.println(" ready");  

    // Initialize the RFM69HCW:
  // radio.setCS(10);  //uncomment this if using Pro Micro
  radio.initialize(FREQUENCY, MYNODEID, NETWORKID);
  radio.setHighPower(); // Always use this for RFM69HCW

  // Turn on encryption if desired:

  if (ENCRYPT)
    radio.encrypt(ENCRYPTKEY);
}

  // Set up LED blinking parameters.
void Blink(byte PIN, int DELAY_MS)
{
  pinMode(PIN, OUTPUT);
  digitalWrite(PIN,HIGH);
  delay(DELAY_MS);
  digitalWrite(PIN,LOW);
}

void loop()
{
//Read scale value as a float, convert to a string, drop string into radio packet and send, print the string value sent, then blink the LED  
  f = scale.get_units();
  //f = scale.read();
  dtostrf(f,7,2,ScaleString); //turning float value into a string of characters (float, string length, decimals to display, defined char name)
        radio.send(TONODEID, ScaleString, strlen(ScaleString));
        Serial.println(ScaleString);
        Blink(LED_BUILTIN,3);

//Check to see if we received anything
  if (radio.receiveDone()) // Got one!
  {
    // Print out the information:

    Serial.print("received from node ");
    Serial.print(radio.SENDERID, DEC);
    Serial.print(", message [");

    // The actual message is contained in the DATA array,
    // and is DATALEN bytes in size:

    for (byte i = 0; i < radio.DATALEN; i++)
      Serial.print((char)radio.DATA[i]);

    // RSSI is the "Receive Signal Strength Indicator",
    // smaller numbers mean higher power.

    Serial.print("], RSSI ");
    Serial.println(radio.RSSI);

    // Send an ACK if requested.
    // (You don't need this code if you're not using ACKs.)

    if (radio.ACKRequested())
    {
      radio.sendACK();
      Serial.println("ACK sent");
    }
    Blink(LED_BUILTIN,3);
  }
  delay(100); //Frequency of the data reporting.
}


The gateway receiver takes on all this information and needs to do something with it.  It currently just prints it to the serial monitor.
// **********************************************************************************
#include <RFM69.h>        
#include <RFM69_ATC.h>     
//#include <SPIFlash.h>      
#include <SPI.h>           

//*********************************************************************************************
//************ IMPORTANT SETTINGS - YOU MUST CHANGE/CONFIGURE TO FIT YOUR HARDWARE *************
//*********************************************************************************************
#define NODEID        1    //unique for each node on same network
#define NETWORKID     100  //the same on all nodes that talk to each other
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
//#define FREQUENCY     RF69_433MHZ
//#define FREQUENCY     RF69_868MHZ
#define FREQUENCY     RF69_915MHZ
#define ENCRYPTKEY    "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
#define IS_RFM69HW_HCW  //uncomment only for RFM69HW/HCW! Leave out if you have RFM69W/CW!
//*********************************************************************************************
//Auto Transmission Control - dials down transmit power to save battery
//Usually you do not need to always transmit at max output power
//By reducing TX power even a little you save a significant amount of battery power
//This setting enables this gateway to work with remote nodes that have ATC enabled to
//dial their power down to only the required level
#define ENABLE_ATC    //comment out this line to disable AUTO TRANSMISSION CONTROL
//*********************************************************************************************
#define SERIAL_BAUD   115200

#ifdef ENABLE_ATC
  RFM69_ATC radio;
#else
  RFM69 radio;
#endif

//SPIFlash flash(SS_FLASHMEM, 0xEF30); //EF30 for 4mbit  Windbond chip (W25X40CL)
bool promiscuousMode = false; //set to 'true' to sniff all packets on the same network

void setup() {
  Serial.begin(SERIAL_BAUD);
//  delay(10);
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
#ifdef IS_RFM69HW_HCW
  radio.setHighPower(); //must include this only for RFM69HW/HCW!
#endif

#ifdef ENCRYPTKEY
  radio.encrypt(ENCRYPTKEY);
#else
  radio.promiscuous(promiscuousMode);
#endif
    
#ifdef ENABLE_ATC
  Serial.println("RFM69_ATC Enabled (Auto Transmission Control)");
#endif
}

byte ackCount=0;
uint32_t packetCount = 0;
void loop() {

  if (radio.receiveDone())
  {
    //Serial.print("#[");
    //Serial.print(++packetCount);
      Serial.print('<');
      Serial.print(radio.SENDERID, DEC);Serial.print(",");

    for (byte i = 0; i < radio.DATALEN; i++)
      Serial.print((char)radio.DATA[i]);
      Serial.print(">");
    //Serial.print("   [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]");
    
    if (radio.ACKRequested())
    {
      byte theNodeID = radio.SENDERID;
      radio.sendACK();
      Serial.print(" - ACK sent.");

      // When a node requests an ACK, respond to the ACK
      // and also send a packet requesting an ACK (every 3rd one only)
      // This way both TX/RX NODE functions are tested on 1 end at the GATEWAY
      if (ackCount++%3==0)
      {
        Serial.print(" Pinging node ");
        Serial.print(theNodeID);
        Serial.print(" - ACK...");
        delay(3); //need this when sending right after reception .. ?
        if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0))  // 0 = only 1 attempt, no retries
          Serial.print("ok!");
        else Serial.print("nothing");
      }
    }
    Serial.println();
    Blink(LED_BUILTIN,3);
  }
}

void Blink(byte PIN, int DELAY_MS)
{
  pinMode(PIN, OUTPUT);
  digitalWrite(PIN,HIGH);
  delay(DELAY_MS);
  digitalWrite(PIN,LOW);
}


Received Output Example:
<1, 103.90>
<2,  83.80>
<3,  53.76>
<4,  43.76>


I am pretty sure there's a ton of ways to skin a cat here, but I need the most efficient way of course.  I have no idea how to start sorting the data and outputting it to the DAC.  As an output example above, I need to submit a total value of 285.22 to the DAC analog voltage output.

Question #1, do we even need to print the received data to the serial monitor?  Can it be read from a buffer or memory of some sort to begin parsing it?  I imagine the serial printing is slowing it down, good for debugging I think.  Each node transmits up to 10 times per second.  So that's 40 data inputs at the gateway per second.

Question #2, if we need to serial print, how would we go about splitting this data into 4 unique variables in order to sum them up?  Like assign data from node 1 FrontLeft, node 2 FrontRight, node 3 RearLeft, node 4 RearRight.  At that point, we can just throw some arithmetic at it, where FrontLeft+FrontRight+RearLeft+RearRight = TotalTorque value.

Any help is much appreciated.  Thanks!

ItzGenX

Ok I have been trying the "serial basics" guide that seems to be referred in every single post regarding parsing data with Arduino and C code on the internet.  It is not to say I understand it all, but the basics of it appear to revolve around reading from serial.

The problem here is I can use Serial.read(); and it comes back with nothing. Opening up the gateway/receiver serial monitor, I see readings incoming from the nodes in the format from the above post.  How do I parse data I can't even read into a char aray?

Is there a different way to receive radio transmissions besides this that I am using from an example?
if (radio.receiveDone()) {
for (byte i = 0; i < radio.DATALEN; i++)
Serial.print((char)radio.DATA[i]);
Serial.println()


Follow that basic receive code shows the incoming readings in the console, but trying to read it with the following gives me absolutely nothing extra in the console.  It is like the serial isn't available or the information somehow is coming in through a different way to get to the console.
while (Serial.available() > 0) {
x = Serial.read();
Serial.print(x);
}


So let's massage the cat. Step 1, how do I get this information extracted into a char aray or something that I can further read and parse? Is this the right way to receive the radio transmission?

Felix

The radio uses a BYTE array, it does not care what that byte array data is. A char takes 1 byte of memory. How you interpret or cast it is up to you.
The various examples in the library show you how to read serial, how to transmit strings, integers, structs etc.