0

I am using a 9-axis accelerator on an Arduino Uno (Atmega 328P processor) with a BLE Nordic rRF8001 chipset.

I am trying to send the accelerometer data via bluetooth to a smart phone (android).

The problem I am having is that the data shown on the serial monitor (which is correct, is not the data that is received via bluetooth. I think it has something to do with either the casting of the variables or that I am screwing up when converting the formats. Below is where I'm currently at and what I have tried.

The error I'm having is that the accelerometer data shown on the serial monitor screen (which is correct):

  1. A_x: -0.12 A_y: 0.53 A_z: 0.83
  2. A_x: -0.12 A_y: 0.53 A_z: 0.83
  3. A_x: -0.12 A_y: 0.53 A_z: 0.83

Does not agree with what the smart phone receives: (See image 1) enter image description here

If I hard code in the x,y,z values in the arduino sketch

  1. float x = (float) 0.52;
  2. float y = (float) 0.52;
  3. float z = (float) 0.52;

I get the following results (see image 2): Accel. Data

And here is the Arduino sketch I am working with:

//-------------------------------------------------------------------------------
//  TinyCircuits 9 Axis and Nordic BLE TinyShield Example Sketch

#include <Wire.h>
#include "RTIMUSettings.h"
#include "RTIMU.h"
#include "RTFusionRTQF.h"
#include <SPI.h>

#include "lib_aci.h"
#include "aci_setup.h"
#include "uart_over_ble.h"
#include "services.h"

#if defined (ARDUINO_ARCH_AVR)
#define SerialMonitorInterface Serial

#elif defined(ARDUINO_ARCH_SAMD)
#define SerialMonitorInterface SerialUSB
#endif

#define DISPLAY_INTERVAL 100




RTIMU *imu;                                           // the IMU object
RTFusionRTQF fusion;                                  // the fusion object
RTIMUSettings settings;                               // the settings object

unsigned long displayInterval = 50;
unsigned long lastDisplay;
unsigned long lastRate;
int sampleCount;


#define BLE_DEBUG false
uint8_t ble_rx_buffer[21];
volatile uint8_t ble_rx_buffer_len = 0;
volatile uint8_t ble_can_sleep = false;
volatile uint8_t ble_connection_state = false;



#ifdef SERIAL_POR_MONITOR
  #define SerialMonitor SERIAL_PORT_MONITOR
#else
  #define SerialMonitor Serial
#endif



void setup(void)
{
//  SerialMonitorInterface.begin(230400);
  SerialMonitor.begin(230400);

  int errcode;

  while (!SerialMonitor);

  Wire.begin();
  imu = RTIMU::createIMU(&settings);                        // create the imu object

  SerialMonitorInterface.print("ArduinoIMU starting using device "); SerialMonitorInterface.println(imu->IMUName());
  if ((errcode = imu->IMUInit()) < 0) {
    SerialMonitorInterface.print("Failed to init IMU: "); SerialMonitorInterface.println(errcode);
  }

  if (imu->getCalibrationValid())
    SerialMonitorInterface.println("Using compass calibration");
  else
    SerialMonitorInterface.println("No valid compass calibration data");

  lastDisplay = lastRate = millis();
  sampleCount = 0;

  // Slerp power controls the fusion and can be between 0 and 1
  // 0 means that only gyros are used, 1 means that only accels/compass are used
  // In-between gives the fusion mix.

  fusion.setSlerpPower(0.02);

  // use of sensors in the fusion algorithm can be controlled here
  // change any of these to false to disable that sensor

  fusion.setGyroEnable(true);
  fusion.setAccelEnable(true);
  fusion.setCompassEnable(true);
  BLEsetup();
}

void loop() {
  aci_loop();//Process any ACI commands or events from the NRF8001- main BLE handler, must run often. Keep main loop short.
  unsigned long now = millis();
  unsigned long delta;

  if (imu->IMURead()) {                                // get the latest data if ready yet
    fusion.newIMUData(imu->getGyro(), imu->getAccel(), imu->getCompass(), imu->getTimestamp());
    sampleCount++;
    if ((delta = now - lastRate) >= 1000) {
      /*SerialMonitorInterface.print("Sample rate: "); SerialMonitorInterface.print(sampleCount);
        if (imu->IMUGyroBiasValid())
        SerialMonitorInterface.println(", gyro bias valid");
        else
        SerialMonitorInterface.println(", calculating gyro bias - don't move IMU!!");
      */
      sampleCount = 0;
      lastRate = now;
    }
    if ((now - lastDisplay) >= displayInterval) {
      lastDisplay = now;
      RTVector3 accelData = imu->getAccel();
      RTVector3 gyroData = imu->getGyro();
      RTVector3 compassData = imu->getCompass();
      RTVector3 fusionData = fusion.getFusionPose();
      char sendBuffer[30] = " ";
      uint8_t sendLength = 0;
      //displayAxis("Accel:", accelData.x(), accelData.y(), accelData.z());        // accel data
      //displayAxis("Gyro:", gyroData.x(), gyroData.y(), gyroData.z());            // gyro data
      //displayAxis("Mag:", compassData.x(), compassData.y(), compassData.z());    // compass data
      //displayDegrees("Pose:", fusionData.x(), fusionData.y(), fusionData.z());   // fused output
      float x = (float)(accelData.x() );//* RTMATH_RAD_TO_DEGREE);
      float y = (float)(accelData.y() );//* RTMATH_RAD_TO_DEGREE);
      float z = (float)(accelData.z() );// * RTMATH_RAD_TO_DEGREE);
//      float x = (float) 0.52;
//      float y = (float) 0.52;
//      float z = (float) 0.52;
      sendLength = sprintf(sendBuffer, "% 2.3d % 2.3d % 2.3d", x, y, z);
      if (sendLength > 20)sendLength = 20;
      if (!lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, (uint8_t*)sendBuffer, sendLength))
      {
        SerialMonitorInterface.println(F("TX dropped!"));
      }
      SerialMonitorInterface.println();


      SerialMonitor.print(" A_x: "); SerialMonitor.print(x);
      SerialMonitor.print(" A_y: "); SerialMonitor.print(y);
      SerialMonitor.print(" A_z: "); SerialMonitor.println(z);      

    }
  }
}

Any thoughts on why the data sent over BLE is incorrect?

1 Answer 1

1

The problem has nothing to do with the bluetooth. It is purely down to how you are formatting the data:

% 2.3d % 2.3d % 2.3d

d is a signed integer. You can't format a floating point value as a signed integer, it just messes up.

Also I don't think the Arduino's sprintf even has floating point support by default (it makes it all too big).

So you will need to find another way to format your data. Maybe use dtostrf() instead.

1
  • Thank you for the response. Using what you said as a starting point, I was able to piece together the solution. Your statement about sprintf not having sprintf floating point support was also seen because the number recieved was really large compared to the value it should have been. So my solution was to convert the floating point numbers to strings using dtostrf: Ex: dtostrf( x, 5, 2, tempx); which I repeated for the other two variables. Then in sprintf I changed the format to read: sprintf(sendBuffer, "% 3s % 3s % 3s", tempx, tempy, tempz); And it works perfectly!
    – K. B
    Commented Mar 22, 2017 at 23:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.