Sending Values via 433 MHz

Good evening guys,

I ran into a problem, which many people have. I read Sensordata from a Accel+Gyro Sensor (datatype: float). I want to send those values in exact this way on a second arduino.
I tried the solution of this topic:

http://forum.arduino.cc/index.php?topic=67005.0

Well it works, but I need to have a lager spectrum than 0...255. Also it would be nice, not to loose the digits after the comma.

my Current solution looks like this:

RX
Sending Value: 16.23

TX
Receiving Value: 16

RX-CODE:

    void loop()
{  
    byte val[VW_MAX_MESSAGE_LEN];
    byte vallen = VW_MAX_MESSAGE_LEN;
    
    if (vw_get_message(val, &vallen))
    {
      Serial.print(val[0], DEC); 
      delay(100);
    }

significant TX-CODE:

int value0=(euler[0] * 180/M_PI);
vw_send((uint8_t *)&value0, sizeof(value0));

I readt so much about Bit-shifting and using Byte-Datatyp, but non of those solutions worked. Maybe it was always a little mistake in it...

Does someone has a nice solution?

You need to either convert the variable to a text string and send that (using dtostrf() for example), or send and receive the entire variable in binary form. Your last example will work, if you replace "int value0" with "float value0".

Hey jremington,

I tried to use dtostrf():

            char *value0;
            dtostrf(euler[0], 3, 2, value0);
            vw_send((uint8_t *)value0, sizeof(value0));

Doesn't work - Arduino does#nt send anything now.

Also it didn't make a differecen to use a float instead of int. It still looses the digits after comma.

But thank you anyway!

You made several mistakes in both attempts.

This:

char *value0;
dtostrf(euler[0], 3, 2, value0);

certainly won't work. Both lines are wrong. See example at http://www.hobbytronics.co.uk/arduino-float-vars

If you want help, post ALL your code.

TX-Code:

// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================

void loop() {
    // if programming failed, don't try to do anything
    if (!dmpReady) return;

    // wait for MPU interrupt or extra packet(s) available
    while (!mpuInterrupt && fifoCount < packetSize) {
        // other program behavior stuff here
        // .
        // .
        // .
        // if you are really paranoid you can frequently test in between other
        // stuff to see if mpuInterrupt is true, and if so, "break;" from the
        // while() loop to immediately process the MPU data
        // .
        // .
        // .
    }

    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();

    // get current FIFO count
    fifoCount = mpu.getFIFOCount();

    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        Serial.println(F("FIFO overflow!"));

    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
        // read a packet from FIFO
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        // track FIFO count here in case there is > 1 packet available
        // (this lets us immediately read more without waiting for an interrupt)
        fifoCount -= packetSize;

        #ifdef OUTPUT_READABLE_EULER     
            float value0=(euler[0] * 180/M_PI);
            //char *value0;
            //dtostrf(euler[0], 3, 2, value0);
            vw_send((uint8_t *)&value0, sizeof(value0));
            //int value1=(euler[1] * 180/M_PI);
            //vw_send((uint8_t *)&value1, sizeof(value1));
            //int value2=(euler[2] * 180/M_PI);
            //vw_send((uint8_t *)&value2, sizeof(value2));
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetEuler(euler, &q);
            Serial.print("euler\t");
            Serial.print(euler[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(euler[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(euler[2] * 180/M_PI);
        #endif


        // blink LED to indicate activity
        blinkState = !blinkState;
        digitalWrite(LED_PIN, blinkState);
    }
}

RX-CODE:

#include <VirtualWire.h>
void setup()
{
    vw_set_ptt_inverted(true); // Required for DR3100
    vw_set_rx_pin(2);
    vw_setup(4000);  // Bits per sec
    pinMode(13, OUTPUT);
    Serial.begin(9600);
    vw_rx_start();       // Start the receiver PLL running
}
    void loop()
{  
    byte val[VW_MAX_MESSAGE_LEN];
    byte vallen = VW_MAX_MESSAGE_LEN;
   

    if (vw_get_message(val, &vallen))
    {
      Serial.print(val[0], DEC); 
     
      delay(100);
    }
    
    }
      Serial.print(val[0], DEC);

This prints the first byte, of the four that were sent, as a decimal value. It should not be a surprise that this doesn't work.

Try this:

  if (vw_get_message(val, &vallen))
    {
   float x; 
   memcpy(&x, val, 4); //copy four bytes received to the float variable
   Serial.print(x);
...

Note: a good programmer would check that "vallen" is actually equal to 4, after the message is received.

Read this post, it uses a different 433 library but you should be able to pick the needed parts to send all the floats you want.

http://forum.arduino.cc/index.php?topic=313587.msg2172824#msg2172824

Hey guys.

Thank you very much. It works 70% :smiley: - No just kidding. I now can receive values. Problem is that the values get modified by the connection (hidden unclear data-cast anywhere?). Also there is too big latency on receiver-side. Sometime the receiver-arduino freezes by shaking the sensor.

Here are the working codes:

RX:

#include <RH_ASK.h>
#include <SPI.h> // Not actualy used but needed to compile
RH_ASK driver(8000,2);//constructor to change any default setting/pins
struct dataStruct{
  float ax;
  float ay;
  float az;
}myData;
void setup()
{
    Serial.begin(9600);  // Debugging only
    if (!driver.init())
         Serial.println("init failed");
    
}
void loop()
{
    uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
    uint8_t buflen = sizeof(buf);

    if (driver.recv(buf, &buflen)) // Non-blocking
    {
   // Message with a good checksum received, dump it.
        memcpy(&myData, buf, sizeof(myData));
        Serial.println("");
        Serial.print("ax: ");
        Serial.print(myData.ax);
        Serial.print("  ay: ");
        Serial.print(myData.ay);
        Serial.print("  az: ");
        Serial.print(myData.az); 
       }
}

The latency on Transmitter-side is okay.

TX:

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include <RH_ASK.h>
#include <SPI.h> // Not actually used but needed to compile
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif
MPU6050 mpu;
//#define OUTPUT_READABLE_QUATERNION
#define OUTPUT_READABLE_EULER
//#define OUTPUT_READABLE_YAWPITCHROLL
//#define OUTPUT_READABLE_REALACCEL
//#define OUTPUT_READABLE_WORLDACCEL
//#define OUTPUT_TEAPOT
#define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
bool blinkState = false;
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
struct dataStruct{
  float ax;
  float ay;
  float az;
  }myData;
byte tx_buf[sizeof(myData)] = {0};
RH_ASK driver(8000,8,4,8,false);//constructor to change any default setting/pins
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector
uint8_t teapotPacket[14] = { '

, 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };

// ================================================================
// ===              INTERRUPT DETECTION ROUTINE                ===
// ================================================================

volatile bool mpuInterrupt = false;    // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}

// ================================================================
// ===                      INITIAL SETUP                      ===
// ================================================================

void setup() {
    // +++ SENSOR SETUP +++ //
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif
    Serial.begin(9600);
    if (!driver.init())
    Serial.println("init failed");
    while (!Serial); // wait for Leonardo enumeration, others continue immediately
    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();
    // verify connection
    Serial.println(F("Testing device connections..."));
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
    // wait for ready
    Serial.println(F("\nSend any character to begin DMP programming and demo: "));
    while (Serial.available() && Serial.read()); // empty buffer
    while (!Serial.available());                // wait for data
    while (Serial.available() && Serial.read()); // empty buffer again
    // load and configure the DMP
    Serial.println(F("Initializing DMP..."));
    devStatus = mpu.dmpInitialize();
    // supply your own gyro offsets here, scaled for min sensitivity
    mpu.setXGyroOffset(220);
    mpu.setYGyroOffset(76);
    mpu.setZGyroOffset(-85);
    mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
    // make sure it worked (returns 0 if so)
    if (devStatus == 0) {
        // turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);
        // enable Arduino interrupt detection
        Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
        attachInterrupt(0, dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();
        // set our DMP Ready flag so the main loop() function knows it's okay to use it
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        dmpReady = true;
        // get expected DMP packet size for later comparison
        packetSize = mpu.dmpGetFIFOPacketSize();
    } else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print(F("DMP Initialization failed (code "));
        Serial.print(devStatus);
        Serial.println(F(")"));
    }
    // configure LED for output
    pinMode(LED_PIN, OUTPUT);
}
void loop() {
    // if programming failed, don't try to do anything
    if (!dmpReady) return;
    // wait for MPU interrupt or extra packet(s) available
    while (!mpuInterrupt && fifoCount < packetSize) {
    }
    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    // get current FIFO count
    fifoCount = mpu.getFIFOCount();
    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        Serial.println(F("FIFO overflow!"));
    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;   
          #ifdef OUTPUT_READABLE_EULER
            myData.ax=euler[0];
            myData.ay=euler[1];
            myData.az=euler[2];
            memcpy(tx_buf, &myData, sizeof(myData));
            byte zize=sizeof(myData);
            driver.send((uint8_t *)tx_buf, zize);
            driver.waitPacketSent();
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetEuler(euler, &q);
            Serial.print("euler\t");
            Serial.print(euler[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(euler[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(euler[2] * 180/M_PI);
        #endif
        blinkState = !blinkState;
        digitalWrite(LED_PIN, blinkState);

Problem is that the values get modified by the connection)

How are they modified?

The following is a bad idea, because you may be copying nonsensical data:

    if (driver.recv(buf, &buflen)) // Non-blocking
    {
   // Message with a good checksum received, dump it.
        memcpy(&myData, buf, sizeof(myData));

You should replace "sizeof(myData)" with "buflen". Also, the Non-blocking comment had better be wrong.

@jremington

If I use "Sizeof(myData)" with "buflen" it receives bullshit. And after 5 times it freezes:

Output Receiver with "buflen" instead of "sizeof(myData)":

ax
ax: 1þ
áÿ
°

I have two example-Codes for reading the sensor Data. One is displaying the raw Values of the sensor. I can send those values without problems to the other arduino (okay there is latency and low perfomance..).
The second example-code (see last post of me), calculates the real sensor data and prints them. Now i want to send THOSE values to the other arduino, but receives shit.

Sendt Data:

euler	-13.04  -7.64

Received Data:

ax: -0.21  az: -0.13

Also it has low perfomance and if you shake the sensor, it seems to freeze (rx-arduino)...

wow i become desperate..

Sounds like several problems, including intermittent wiring connections.

I use and recommend VirtualWire. Ignore the warnings about discontinued support, it has been pretty thoroughly debugged and is perfect for your application.

mhm, Well i don't get the problem. With the Raw-Values code it sends the perfect data. Why not with the other code?

#ifdef OUTPUT_READABLE_EULER
            myData.ax=euler[0];
            myData.ay=euler[1];
            myData.az=euler[2];
            memcpy(tx_buf, &myData, sizeof(myData));
            byte zize=sizeof(myData);
            driver.send((uint8_t *)tx_buf, zize);
            driver.waitPacketSent();
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetEuler(euler, &q);
            Serial.print("euler\t");
            Serial.print(euler[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(euler[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(euler[2] * 180/M_PI);
        #endif

Do I understand correctly. If you place myData.ax = euler[0] in the struct all is good, but if you use myData.ax = (euler[0] * 180/M_PI) garbage comes across.

No. with this code, the transmission works (with latency and low perfomance):

void loop() {
    // if programming failed, don't try to do anything
    if (!dmpReady) return;
    // wait for MPU interrupt or extra packet(s) available
    while (!mpuInterrupt && fifoCount < packetSize) {
    }
    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    // get current FIFO count
    fifoCount = mpu.getFIFOCount();
    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        Serial.println(F("FIFO overflow!"));
    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;
        #ifdef OUTPUT_READABLE_EULER
            myData.ax=euler[0];
            myData.az=euler[2];
            memcpy(tx_buf, &myData, sizeof(myData));
            byte zize=sizeof(myData);
            driver.send((uint8_t *)tx_buf, zize);
            driver.waitPacketSent();
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetEuler(euler, &q);
            Serial.print("euler\t");
            Serial.print(euler[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(euler[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(euler[2] * 180/M_PI);
        #endif
        blinkState = !blinkState;
        digitalWrite(LED_PIN, blinkState);
    }
}

with this code, garbage comes across:

void loop() {
    // if programming failed, don't try to do anything
    if (!dmpReady) return;
    // wait for MPU interrupt or extra packet(s) available
    while (!mpuInterrupt && fifoCount < packetSize) {
    }
    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    // get current FIFO count
    fifoCount = mpu.getFIFOCount();
    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        Serial.println(F("FIFO overflow!"));
    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;
        #ifdef OUTPUT_READABLE_QUATERNION
            // display quaternion values in easy matrix form: w x y z
            mpu.dmpGetQuaternion(&q, fifoBuffer);
        #ifdef OUTPUT_READABLE_EULER
            myData.ax=euler[0];
            myData.az=euler[2];
            memcpy(tx_buf, &myData, sizeof(myData));
            byte zize=sizeof(myData);
            driver.send((uint8_t *)tx_buf, zize);
            driver.waitPacketSent();
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetEuler(euler, &q);
            Serial.print("euler\t");
            Serial.print(euler[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(euler[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(euler[2] * 180/M_PI);
        #endif
        blinkState = !blinkState;
        digitalWrite(LED_PIN, blinkState);
    }
}

Hello i will take a look at the 433 code again in the evening, just a fast question are you running this code on ordinary arduinos? (pro mini, arduino uno, mega...)

arduino uno. Thank you.

#Update:
I now use Virtualwire again. It works fine now. Thank you guys for your help!

I now use Virtualwire again. It works fine now.

The issue is not likely be the library used (Virtual Wire, or RH_ASK in RadioHead) but in your set up. For example are you using VW at the 8000 baud rate of the RH_ASK sketch or the 4000 baud rate of the first code posted?