I am working with BLE 4.2 (ESP32) that sends IMU (accel, gyro, mag) data to my mobile app (Android). Unfortunately, I can send only 20 bytes in one packet.
This is the code I have: (I am connecting the float raw data (ax, ay,...my, mz...etc) read from the accelerometer.)
char myConcatenation[20];
char myStr[","];
.
.
.
sprintf(myConcatenation,"%3.2f%s%3.2f%s%3.2f%s%3.2f%s%3.2f%s%3.2f%s%3.2f%s%3.2f%s%3.2f%s%3.2f%s%3.2f%s%3.2f", ax, myStr, ay, myStr, az, myStr,gx,myStr, gy, myStr, gz, myStr, mx, myStr, my, myStr, mz, myStr, yaw, myStr, pitch, myStr, roll);
.
.
.
pCharacteristic->setValue(myConcatenation);
pCharacteristic->notify(); // Send the value to the app!
Do you know how to construct a code so I would notify the app with new data of 20 Byte length? For example, each packet constructed of every sensor reading:
1. (ax, ay, az)
2. (gx, gy, gz)
3. (mx, my, mz)
4. (yaw, pitch, roll)
Related
Am using arduino nano 33 Ble and am using the Lib Arduino_LSM9DS1
am trying to understand the equation but i dont get it
the say data[0]*4/32768 wher the lsb 32768.
it should be a 16 bit rigester where the lsb should 2^16 = 65536. or hier they use -+ 32768 ?
and what exactly 4 ? why the use this rang not a an 8 or 16 ?
can somone explin it to me ?
and how exactly get the acceleration and in which unit ?
int LSM9DS1Class::readAcceleration(float& x, float& y, float& z)
{
int16_t data[3];
if (!readRegisters(LSM9DS1_ADDRESS, LSM9DS1_OUT_X_XL, (uint8_t*)data, sizeof(data))) {
x = NAN;
y = NAN;
z = NAN;
return 0;
}
x = data[0] * 4.0 / 32768.0;
y = data[1] * 4.0 / 32768.0;
z = data[2] * 4.0 / 32768.0;
return 1;
}
The documentation states that:
Accelerometer range is set at [-4,+4]g -/+0.122 mg
So, the value returned by the function readAcceleration is in the range [-4,4], representing -4g to 4g
g is the gravitational acceleration = 9.81 m/s2
The code you're showing is the implementation of the function readAcceleration. As I understand it, the raw acceleration data represented as a 16-bit signed integer (between −32,768 to 32,767), which is then normalized (divided by 32,768) and multiplied by 4 to put in the correct range of [-4,4].
I am encoding 6 values (4x 3bit + 1bit) into a 16bit integer and transfer them via serial to an ATTINY84 splitting them into 2 bytes. That works all good until the point that I re-assemble the bytes into a 16bit int.
Example:
I am sending the following binary state 0001110000001100 which translates to 7180 and gets split into a byte array of [18, 28].
I am putting that byte array into the EEPROM and read it on the next power cycle.
After power cycle my serial debug output looks like this:
18
28
7180
Awesome. Looks all good and my code for that part is:
byte d0 = EEPROM.read(0);
byte d1 = EEPROM.read(1);
unsigned int w = d0 + (256 * d1);
But now the weirdest thing happens. When I do a bit-by-bit read I am getting back:
0011000000111000
should be:
0001110000001100
via:
for(byte t = 0; t < 16; t++) {
serial.print(bitRead(w, t) ? "1" : "0");
}
The bit representation is completely reversed. How is that possible? Or maybe I am missing something.
Also I confirmed when I extract the actual 3 bit location to receive my original value 0..7 it's all off.
Any help would be appreciated.
So it looks like I fell into the little/big endian trap.
Basically as Alain said, in the comments - everything is correct and it's just the representations.
I came up with the following method that can extract bits from a little endian stored number that needs to be in a big endian format:
/**
* #bex
*/
uint8_t bexd(uint16_t n, uint8_t o, uint8_t l, uint8_t d) {
uint8_t v = 0;
uint8_t ob = d - o;
for (uint8_t b=ob; b > (ob-l); b--) v = ( v << 1 ) | ( 0x0001 & ( n >> (b-1) ) );
return v;
}
uint8_t bexw(uint16_t n, uint8_t o, uint8_t l) {return bexd(n, o, l, 16);}
uint8_t bexb(uint8_t n, uint8_t o, uint8_t l) {return bexd(n, o, l, 8);}
For example:
In big endian the "second" value is stored in bit 3,4, and 5, compared to little endian where it will be stored in bit 10, 11, and 12. The method above allows to work a "little endian" value like it would be an "big endian" value.
To extract the second value from this value 0011000000111000 just do:
byte v = bex(7180, 3, 3); // 111
Serial.println(v); // prints 255
Hope that helps someone.
I am a newbie in MPU9150 9-axis IMU sensor, working on a project in which the Roll, pitch and Yaw value will be showed in a GUI. I have used the code from here: https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/MPU9150
The problem is, as in GUI I will show the 3D representation of the roll, pitch and yaw. What will be the specific conversion formula from the raw data?
my WHO_AM_I resistor value: 0x68,
Accelerometer configured : 2g ,
Gyroscope configured: 250 dps,
Any help will be GREAT. Thanks in advance!
In java,
float alpha=(float) 0.5;
double fXg=0.0,fYg=0.0,fZg=0.0;
fXg = xx * alpha + (fXg * (1.0 - alpha));
fYg = yy * alpha + (fYg * (1.0 - alpha));
fZg = zz * alpha + (fZg * (1.0 - alpha));
//Roll,Pitch & Yaw Equations
double roll = (Math.atan2(-fYg, fZg)*180.0)/3.14;
double pitch =( Math.atan2(fXg, Math.sqrt(fYg*fYg + fZg*fZg))*180.0)/3.14;
double yaw = 180 * Math.atan (fZg/Math.sqrt(fXg*fXg + fZg*fZg))/3.14;
I have 6 sensors connected to the pin A0, A1, A2, A3, A4, A5 and I am trying to get readings from each sensor. I have a analogread() function inside of a for loop and it does not work.
If I just trigger the sensor at A0, all other sensors will have the same reading as that one even if they are not triggered. I used a voltage meter to test the voltage of each pin and only got voltage at A0 when the A0 sensor is triggered. So I believe this is a coding problem.
Here is my code:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0~5:
for(int i = 0; i < 6; i++){
int sensorValue0 = analogRead(i);
delay(700);
// Convert the analog reading (which goes from 0 - 1023) to voltage range (0 - 5V);
float voltage0 = sensorValue0 * (5.0 / 1023.0);
// print out the value you read:
Serial.print(voltage0);Serial.print(" i = ");
Serial.print(i);Serial.print(" ; ");
if (i == 5) Serial.println(" ");
}
}
I just set up some voltage dividers, consisting of combination of various R1 and R2=1k and hooked them up to the analog inputs of an Arduino. Using your code, I received the following data (S0 = raw reading, V0 = calculated voltage)
R1 S0 V0
220 841 4.11
470 695 3.40
1k 511 2.50
2k2 318 1.55
4k7 179 0.87
6k8 128 0.63
This looks fine. Your code is correct. There's definitely something wrong with your wiring.
I am trying to build a small program with arduino using a temperature-sensor.
I thought I knew how to do it but I'm getting some weird outputs.
Here is my code:
int sensorPin = 0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
int reading = analogRead(sensorPin);
float voltage = reading * 5.0 / 1024;
float temperatureC = (voltage - 0.5) * 100;
Serial.print(temperatureC); Serial.print(" degrees C, ");
Serial.print(voltage); Serial.println(" volts");
delay(1000);
}
This code gives me the output:
-26.56 degrees C, 0.23 volts
-26.56 degrees C, 0.23 volts
-27.05 degrees C, 0.23 volts
-26.56 degrees C, 0.23 volts
-26.07 degrees C, 0.24 volts
-26.07 degrees C, 0.24 volts
Why is it - in degrees? and Why can I change it to any pin I want and it will still give me a similar output?
Analog input 0 is not pin 0.
You should use the defined symbols:
A0,A1,...,A7
for analog inputs.
Try
int sensorPin = A0;
and your program should work.
If you are curious about the actual values, under your Arduino IDE install look in the file
..\hardware\arduino\variants\standard\pins_arduino.h
You are reading this input correctly.
In order for you to not get negative degrees, you'll have to process it differently.
With this:
float temperatureC = (voltage - 0.5) * 100;
Any values < 0.5 result in multiplying a negative number by 100.
Try breaking this down using commutative property.
(voltage - 0.5) * 100 is the same as (voltage * 100) - (0.5 * 100).
This can be further simplified to (voltage * 100) - 50.
Still, for all values where voltage < 0.5 the temperature will be negative.
I would suggest multiplying temperatureC by -1 to make it positive and not putting the sensor near anything that is `~ >= 50 degrees Celsius.
Also, As jdr5ca pointed out here, you're not actually getting any data from the sensor yet... :(
You are probably getting noise (or garbage) from whatever pin0 is.
EDIT
It is best practice to use parentheses to make order of operations more clear.
ie:
float voltage = reading * 5.0 / 1024;
should be
float voltage = reading * (5.0 / 1024);
First, you have to use the defined symbols A0
int sensorPin = A0;
in the next
float voltage = reading * (5.0 / 1024);
There is an example in File/Examples/Basic/AnalogReadSerial