guild icon
Toit
#MPU 6050 help!!
Thread channel in help
danielsam7960
danielsam7960 03/14/2023 03:32 AM
I am trying to write code to get the acceleration values from MPU 6050, the code in arduino for this is:
#include<Wire.h> const int MPU = 0x68; float AccX, AccY, AccZ; void setup() { Serial.begin(9600); Wire.begin(); Wire.beginTransmission(MPU); Wire.write(0x6B); Wire.write(0); Wire.endTransmission(true); Wire.beginTransmission(MPU); Wire.write(0x1C); Wire.write(0b00011000); //scale factor +/-16g Wire.endTransmission(); } loop(){ Wire.beginTransmission(MPU); Wire.write(0x3B); Wire.endTransmission(false); Wire.requestFrom(MPU, 14, true); // Solicita os dados ao sensor AccX = Wire.read() << 8 | Wire.read(); //0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) AccY = Wire.read() << 8 | Wire.read(); //0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) AccZ = Wire.read() << 8 | Wire.read(); //0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) Serial.print(AccX / 2048); Serial.print(" "); Serial.print(AccY / 2048); Serial.print(" "); Serial.println(AccZ / 2048); }

i have already started making the porting to toit, and i am stuck in this:
import gpio import i2c MPU9250_ADDRESS := 0x68 ACCEL_CONFIG_REG := 0x1C main: bus := i2c.Bus --sda=gpio.Pin 21 --scl=gpio.Pin 22 device := bus.device MPU9250_ADDRESS

can any one help me to finish this code in toit?
danielsam7960OPdanielsam7960
I am trying to write code to get the acceleration values from MPU 6050, the code in arduino for this is: ``` #include<Wire.h> const int MPU = 0x68; float AccX, AccY, AccZ; void se...
floitsch
floitsch 03/14/2023 03:22 PM
Off-topic: prefer to indent your code with two spaces (the bus := and device :=). This will make the syntax highlighter happier.
The --sda= can then be intended by 4.

Small warning: I haven't tested any of the code I posted here. Let me know if something doesn't seem correct or doesn't work.

The first thing the code does is to set the 0x1C register.
If you look at the register map (which, for some reason, is not in the data sheet) you can see that 0x1C is the ACCEL_CONFIG register (as you correctly stated with your constant): https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf
(Side-note: for constants, like MPU9250_ADDRESS and ACCEL_CONFIG_REG, prefer ::= instead of :=. That just means that the variables are final and can't be changed).

It sets the value 0b00011000. According to the register map, this means that AFS_SEL is set to 0b11. On page 15 (Register 28), it explains that this means that the accelerometer reads values in the whole 16g range. This means that it might be a bit less precise, but can handle stronger accelerations. You could change it to 0b00000000 for more precise measurements. In that case you will need to change the constant to go from raw value to acceleration value later in the code, though.

To write to an i2c register you would use the following code:
registers := device.registers registers.write_u8 ACCEL_CONFIG_REG 0b00011000
(edited)
floitsch
floitsch 03/14/2023 03:22 PM
For reading the actual values you have 2 options:
- read all 6 bytes (2 for each axis) in one go, or
- read two bytes each.
The first is a bit more efficient, but the latter is easier to write.

Here are the constants you need:
ACCEL_XOUT_H ::= 0x3B ACCEL_XOUT_L ::= 0x3C ACCEL_YOUT_H ::= 0x3D ACCEL_YOUT_L ::= 0x3E ACCEL_ZOUT_H ::= 0x3F ACCEL_ZOUT_L ::= 0x40

// Read 6 bytes in one go: accel_data := registers.read_bytes ACCEL_XOUT_H 6 accel_x := accel_data[0] << 8 | accel_data[1] accel_y := accel_data[2] << 8 | accel_data[3] accel_z := accel_data[4] << 8 | accel_data[5]
or
// Read each value independently: accel_x := registers.read_i16_be ACCEL_XOUT_H_ accel_y := registers.read_i16_be ACCEL_YOUT_H_ accel_z := registers.read_i16_be ACCEL_ZOUT_H_
Note that we use read_i16_be which basically means: "read an integer with 16 bits, in big-endian format". And "big-endian" means that the big part (that is, most significant, or high part) is first.

If you look at the description of these registers (page 29) you can see that the obtained value's meaning depends ot the AFS_SEL that we set in the configuration. With the highest precision (when setting the config-register to 0), the value must be divided by 16384. With the lowest accuracy (but highest range), it must be divided by 2048 (as you do in your code).

You can then start a loop:
while true: accel_x := registers.read_i16_be ACCEL_XOUT_H_ accel_y := registers.read_i16_be ACCEL_YOUT_H_ accel_z := registers.read_i16_be ACCEL_ZOUT_H_ print "x: $(accel_x / 2048)" print "y: $(accel_y / 2048)" print "z: $(accel_z / 2048)" sleep --ms=1_000
floitsch
floitsch 03/14/2023 03:23 PM
Also of interest: there is already a package for the mpu6886: https://pkg.toit.io/package/github.com%2Fimliubo%[email protected]
floitsch
floitsch 03/14/2023 03:23 PM
MPU6886 package for TOIT. Contribute to imliubo/mpu6886-toit development by creating an account on GitHub.
floitsch
floitsch 03/14/2023 03:23 PM
Even the I2C_ADDRESS seems to be the same.
floitsch
floitsch 03/14/2023 03:24 PM
I wouldn't be surprised if that package works directly with your MPU 6050.
danielsam7960
danielsam7960 03/14/2023 03:42 PM
Thank you very much for the detailed reply. I appreciate your advice and I will definitely test the code as well as the mpu6886 lib. If everything goes smoothly, I will reply here
๐Ÿ‘1
danielsam7960
danielsam7960 03/17/2023 01:41 PM
everything work good, thanks a lot for your support, i opted to use the package of the mpu6886, with a little change i have make work on mpu 6050, for thus who will use MPU6050, the little change was:
constructor dev/serial.Device: reg_ = dev.registers tries := 5 while whoami != 0x71: // Here was the change, on MPU6886 was expected 0x19, but on MPU6050 is 0x71 tries-- print whoami if tries == 0: throw "INVALID_CHIP" sleep --ms=1
danielsam7960OPdanielsam7960
everything work good, thanks a lot for your support, i opted to use the package of the mpu6886, with a little change i have make work on mpu 6050, for thus who will use MPU6050, t...
floitsch
floitsch 03/17/2023 01:42 PM
nice.
We should probably make an mpu6xxx package that knows about these differences.
danielsam7960
danielsam7960 03/17/2023 01:46 PM
I'll later posted on my github and linkedin, the project that i'm made using Toit for my thesis defense, that is a fall detection project: detecting object falls in real-time using mpu6050. really thanks for your help.
floitsch
floitsch 03/17/2023 02:06 PM
Thanks!
floitsch
floitsch 03/17/2023 02:10 PM
Fyi: one of the lsm303 drivers we have has free-fall detection.
๐Ÿ‘1
floitsch
floitsch 03/17/2023 02:14 PM
Actually. It was the LIS3DH one.
floitsch
floitsch 03/17/2023 02:27 PM
Couldn't resist and had a look at the datasheet.
The one I linked earlier doesn't mention free-fall detection.
However, this page mentions that bit two bits in the interrupt register are reserved for free-fall detection: https://community.element14.com/technologies/sensor-technology/b/blog/posts/one-step-closer-to-create-own-fall-detector-with-mpu6050
danielsam7960
danielsam7960 03/17/2023 03:09 PM
It appears to me that the implementation at the register level is quite similar to the one I made. To determine if the sensor is falling or not, you just need to calculate the total force it's experiencing using the formula sqrt(ax2 + ay2 +ax**2). When the sensor is falling, the total force is almost zero.
danielsam7960
danielsam7960 03/17/2023 03:10 PM
So, the sensitivity that you can adjust is simply how close to zero you want the condition to be.
floitsch
floitsch 03/17/2023 04:27 PM
The advantage of using the sensor is that you can just wait for the interrupt. No need to continuously poll
danielsam7960
danielsam7960 03/17/2023 05:12 PM
sure
19 messages in total