I am completely new on electronics. I bought an Arduino with a Gyroscope + accelerometer module. The gyroscope I am trying to use is the L3GD20 connected via I2C connection to my arduino.
The code I have managed to build is the following:
#include <Wire.h>
int gyroscopeAddress = 0x69; // Device address
#define X_Axis_Register_L 0x28 // Register associated to the X_L axis (as stated on the datasheet)
#define controlRegister 0x20 // Register for determining the working mode
int16_t w_x_raw; // Stores the raw 16 bit signed data after joining both registers
int X_H; // High value from the register
int X_L; // Low value from the register
float w_x; // Final result after the transformation to degrees per second
void setup() {
Wire.begin();
Serial.begin(9600);
// Enable measurement
Wire.beginTransmission(gyroscopeAddress);
Wire.write(controlRegister);
Wire.write(15); // Sets normal mode on the chip (00001111) -> the 4th bit is for normal mode, the first 3 are for the X,Y and Z data measurement.
Wire.endTransmission();
}
void loop() {
Wire.beginTransmission(gyroscopeAddress);
Wire.write(X_Axis_Register_L);
Wire.endTransmission(false);
Wire.requestFrom(gyroscopeAddress, 2, true); // Read two registers starting at X_L --> Reads X_L, X_H
X_L = Wire.read();
X_H = Wire.read();
w_x_raw = (X_H | (X_L << 8)); // x angular speed value in raw
w_x = w_x_raw * 0.00875; // Transformation to dps
Serial.println(w_x);
delay(250);
}
When I run this code, I get values that are all negative and far beyond the digital zero-rate level for the setting I am using (the default ones):
digital zero-rate level = +-10 dps
FS = +-250 dps
8.75 millidegrees per second / digit.
I attach now the values I get for the X axis rotation when the sensor is static (units degrees per second) :
That looks like normal sensor noise to me. If you read all three axes you can compare the noise levels, as each axis has an independent sensor.
For accurate readings you must calculate and subtract the offsets. Most people sum a couple of hundred readings with the sensor still, calculate the averages for each axis, and subtract those from subsequent readings.
w_x_raw = (X_H | (X_L << 8)); // x angular speed value in raw
Based on the name you chose for the X_H and X_L variables, I would have expected:
w_x_raw = (X_L | (X_H << 8)); // x angular speed value in raw
I wouldn't expect noise in the range of 100.0 degrees per second when it is sitting still.
Normally I have had to send some register write requests for setting up my inertial sensors but maybe all of the defaults are just what you need for this one.
Can you please post some images of your project?
Can you please post a copy of your circuit, a CAD jpg EXPORT, or a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, component names and pin labels.
What register writes do you usually use? I just wanted to test that I am able to turn the sensor on and obtain usable values so I left everything on default. Once I try to do something specific with the data I would consider changing the settings.
Also, I have noticed that if I wiggle a little bit the cables while its reading, the values turn positive more often. Could it be a problem with the connections? (I am using a breadboard with some male-male jump cables).
UPDATE: I have implemented the computation of the mean value for the first 500 readings and the results I get are the following:
Also, I have noticed that if I wiggle a little bit the cables while its reading, the values turn positive more often. Could it be a problem with the connections? (I am using a breadboard with some male-male jump cables).
Yes, redo all the connections and test again, without wiggling while testing. Breadboards are very unreliable.
#include <Wire.h>
int gyroscopeAddress = 0x69; // Device address
#define X_Axis_Register_L 0x28 // Register associated to the X_L axis (as stated on the datasheet)
#define controlRegister 0x20 // Register for determining the working mode
int16_t w_x_raw; // Stores the raw 16 bit signed data after joining both registers
int X_H; // High value from the register
int X_L; // Low value from the register
float w_x; // Final result after the transformation to degrees per second
float calibration[250];
int calibration_flag = 0; // flag for deciding if calibration is necessary
int calibration_counter = 0; // counter for the calibration procedure
float offset = 0; // mean of the offsets vector
void setup() {
Wire.begin();
Serial.begin(9600);
// Enable measurement
Wire.beginTransmission(gyroscopeAddress);
Wire.write(controlRegister);
Wire.write(15); // Sets normal mode on the chip (00001111) -> the 4th bit is for normal mode, the first 3 are for the X,Y and Z data measurement.
Wire.endTransmission();
}
void loop() {
Wire.beginTransmission(gyroscopeAddress);
Wire.write(X_Axis_Register_L);
Wire.endTransmission(false);
Wire.requestFrom(gyroscopeAddress, 2, true); // Read two registers starting at X_L --> Reads X_L, X_H
X_L = Wire.read();
X_H = Wire.read();
w_x_raw = (X_L | (X_H << 8)); // x angular speed value in raw
w_x = w_x_raw * 0.00875;
if (calibration_flag == 1){ // If the calibration have been already done, plot the data.
Serial.println(w_x - offset); // Apply the average offset to the data
delay(100);
} else{ // If not: compute the average
calibration[calibration_counter] = w_x;
calibration_counter++; // Calibrate using the average of 500 values
if(calibration_counter == 500){
Serial.print("Done calibrating!");
calibration_flag = 1;
for(int n = 0; n<500; n++){ // computing the average offset
offset = offset + calibration[n];
}
offset = offset / 500; // Average offset = sum(w_x)/500
Serial.print(" The offset is [dps]: ");
Serial.println(offset);
}
delay(5);
}
}
I will check the adafruit library and see if get anything useful. Regarding the connections, I only have jumping wires which have some room to wiggle when connected to the breadboard. I do not know how I would be able to solve that problem without soldering the cables directly to the gyroscope-accelerometer module.
My apologies. I copied the wrong code. This is the one computing the average. The results are listed below.
#include <Wire.h>
int gyroscopeAddress = 0x69; // Device address
#define X_Axis_Register_L 0x28 // Register associated to the X_L axis (as stated on the datasheet)
#define controlRegister 0x20 // Register for determining the working mode
int16_t w_x_raw; // Stores the raw 16 bit signed data after joining both registers
int X_H; // High value from the register
int X_L; // Low value from the register
float w_x; // Final result after the transformation to degrees per second
float calibration[300];
int calibration_flag = 0; // flag for deciding if calibration is necessary
int calibration_counter = 0; // counter for the calibration procedure
float offset = 0; // mean of the offsets vector
void setup() {
Wire.begin();
Serial.begin(9600);
// Enable measurement
Wire.beginTransmission(gyroscopeAddress);
Wire.write(controlRegister);
Wire.write(15); // Sets normal mode on the chip (00001111) -> the 4th bit is for normal mode, the first 3 are for the X,Y and Z data measurement.
Wire.endTransmission();
}
void loop() {
Wire.beginTransmission(gyroscopeAddress);
Wire.write(X_Axis_Register_L);
Wire.endTransmission(false);
Wire.requestFrom(gyroscopeAddress, 2, true); // Read two registers starting at X_L --> Reads X_L, X_H
X_L = Wire.read();
X_H = Wire.read();
w_x_raw = (X_L | (X_H << 8)); // x angular speed value in raw
w_x = w_x_raw * 0.00875;
if (calibration_flag == 1){ // If the calibration have been already done, plot the data.
Serial.println(w_x - offset); // Apply the average offset to the data
delay(100);
} else{ // If not: compute the average
calibration[calibration_counter] = w_x;
calibration_counter++; // Calibrate using the average of 500 values
if(calibration_counter == 300){
Serial.print("Done calibrating!");
calibration_flag = 1;
for(int n = 0; n<300; n++){ // computing the average offset
offset = offset + calibration[n];
}
offset = offset / 300; // Average offset = sum(w_x)/500
Serial.print(" The offset is [dps]: ");
Serial.println(offset);
}
delay(5);
}
}
I think the serial plot is the best way to see how erratic the values are. Anyways
Additionally, the Adafruit library says "No L3GD20 device was found". When I check into the library code itself, the I2C address that the library (0x6B) has for my chip differs from that given back when I run an I2C scanner on my arduino (0x69). I am really confused at this point
I have been investigating. The Adafruit library won't identify my L3GD20 because I do not know why the WHO_AM_I register gives back a -1 value (11111111), which does not corresponds to the one from the data sheet or the one in the library.
That is almost undoubtedly a counterfeit, reject or recycled part, which is a common experience with cheap resellers on sites like eBay or Aliexpress. I suspect you are just wasting your time.
The seller identifies the module as "L3G4200D", which has long been obsolete, so why do you think it is an L3GD20? The WHO_AM_I value you get is wrong for both possibilities.
If you want a genuine L3GD20 sensor, buy from a reputable supplier with a return guarantee.