adafruit / Adafruit_BNO08x

Arduino library for BNO08x
Other
37 stars 14 forks source link

Support multiple sensors #4

Closed caternuson closed 3 years ago

caternuson commented 3 years ago

Re this thread: https://forums.adafruit.com/viewtopic.php?f=19&t=172773

Should these be moved to be class members? https://github.com/adafruit/Adafruit_BNO08x/blob/77ff9269e99da869b040739678de51ab07c179cf/src/Adafruit_BNO08x.cpp#L42

ladyada commented 3 years ago

probably? havent tried it tho, a bunch of stuff is static. im not sure we could support multiple sensors

caternuson commented 3 years ago

As is, I think the variables get shared. So no way to specify different pins for each instance. Idea with moving to class would be so each instance could have its own settings. But not sure what else would be needed beyond that.

StarWitch commented 3 years ago

I'm also running into a similar issue, but with I2C instead.

My setup is two BNO085 boards hooked up through STEMMA QT connectors to a GrandCentral M4 in series. (i.e: GCM4 <-> BNO085-1 <-> BNO085-2) over I2C, using the standard D20/D21 pins. DI has been pulled high on one of them to give both sensors two addresses.

Running an I2C Scanner shows both of them showing up just fine. Additionally, I can grab data from each one individually. However, when I try to instantiate two separate objects for the two sensors, it fails. Here's an example script (barely modified from the rotation_vector example):

#include <Adafruit_BNO08x.h>

#define BNO08X_RESET1 5
#define BNO08X_RESET2 6

Adafruit_BNO08x  bno08x1(BNO08X_RESET1);
Adafruit_BNO08x  bno08x2(BNO08X_RESET2);

void setup(void) {
  Serial.begin(115200);
  while (!Serial) delay(10);  

  Serial.println("Adafruit BNO08x test!");

  if (!bno08x1.begin_I2C(0x4A)) {
    Serial.println("Failed to find BNO08x (1)");
    while (1) { delay(10); }
  }
  Serial.println("BNO08x (1) Found!");

  if (!bno08x2.begin_I2C(0x4B)) {
    Serial.println("Failed to find BNO08x (2)");
    while (1) { delay(10); }
  }
  Serial.println("BNO08x (2) Found!");

}

void loop() {
  // testing
}

Which gets the output of:

Adafruit BNO08x test!
BNO08x (1) Found!
Failed to find BNO08x (2)

In my own Serial.println() debugging adventure, the second instance gets as far as _init in Adafruit_BNO085.cpp, specifically when it calls sh2_open(), where it then fails. It does seem to be able to get the address of the second sensor, but can't do anything with it.

However, it must surely be possible to support multiple sensors somehow in the Arduino library, because doing something similar in CircuitPython gets me the result I'd expect, which is two streams of sensor data from both sensors simultaneously.

import time
import board
import busio
from adafruit_bno08x import (
    BNO_REPORT_ROTATION_VECTOR,
)
from adafruit_bno08x.i2c import BNO08X_I2C

i2c = busio.I2C(board.SCL, board.SDA, frequency=800000)
bno1 = BNO08X_I2C(i2c, None, address=0x4A)
bno2 = BNO08X_I2C(i2c, None, address=0x4B)

bno1.enable_feature(BNO_REPORT_ROTATION_VECTOR)
bno2.enable_feature(BNO_REPORT_ROTATION_VECTOR)

while True:

    time.sleep(0.2)

    print("Rotation Vector Quaternion 1:")
    quat_i, quat_j, quat_k, quat_real = bno1.quaternion  # pylint:disable=no-member
    print(
        "I: %0.6f  J: %0.6f K: %0.6f  Real: %0.6f" % (quat_i, quat_j, quat_k, quat_real)
    )
    print("")

    time.sleep(0.2)

    print("Rotation Vector Quaternion 2:")
    quat_i, quat_j, quat_k, quat_real = bno2.quaternion  # pylint:disable=no-member
    print(
        "I: %0.6f  J: %0.6f K: %0.6f  Real: %0.6f" % (quat_i, quat_j, quat_k, quat_real)
    )
    print("")

Example output:

Rotation Vector Quaternion 1:
I: 0.886047  J: -0.334045 K: -0.115601  Real: 0.299866

Rotation Vector Quaternion 2:
I: -0.152466  J: 0.941833 K: -0.277405  Real: 0.112854

I'm unsure what specifically is missing in the C library to cause it to fail like this, but it seems to affect both I2C and SPI.

EDIT: As a follow-up, I went ahead and tried to link up all 6 of my IMUs through CircuitPython with multiple busses using SERCOMs (2 IMUs per bus) at the same time, and it worked without any issue.

caternuson commented 3 years ago

@StarWitch Yes, it's the same issue. The same thing will happen with any interface (I2C/SPI/UART) due to the current library layout. All interfaces are using a single global device instead of their own instance.

Here's another one that is I2C related and took me way too long to remember this issue existed: https://forums.adafruit.com/viewtopic.php?f=25&t=175744

caternuson commented 3 years ago

Closing for now. Supporting multiple sensors will require a fair amount of library re-work.

Abadyza commented 3 years ago

I'm also running into a similar issue, but with I2C instead.

My setup is two BNO085 boards hooked up through STEMMA QT connectors to a GrandCentral M4 in series. (i.e: GCM4 <-> BNO085-1 <-> BNO085-2) over I2C, using the standard D20/D21 pins. DI has been pulled high on one of them to give both sensors two addresses.

Running an I2C Scanner shows both of them showing up just fine. Additionally, I can grab data from each one individually. However, when I try to instantiate two separate objects for the two sensors, it fails. Here's an example script (barely modified from the rotation_vector example):

#include <Adafruit_BNO08x.h>

#define BNO08X_RESET1 5
#define BNO08X_RESET2 6

Adafruit_BNO08x  bno08x1(BNO08X_RESET1);
Adafruit_BNO08x  bno08x2(BNO08X_RESET2);

void setup(void) {
  Serial.begin(115200);
  while (!Serial) delay(10);  

  Serial.println("Adafruit BNO08x test!");

  if (!bno08x1.begin_I2C(0x4A)) {
    Serial.println("Failed to find BNO08x (1)");
    while (1) { delay(10); }
  }
  Serial.println("BNO08x (1) Found!");

  if (!bno08x2.begin_I2C(0x4B)) {
    Serial.println("Failed to find BNO08x (2)");
    while (1) { delay(10); }
  }
  Serial.println("BNO08x (2) Found!");

}

void loop() {
  // testing
}

Which gets the output of:

Adafruit BNO08x test!
BNO08x (1) Found!
Failed to find BNO08x (2)

In my own Serial.println() debugging adventure, the second instance gets as far as _init in Adafruit_BNO085.cpp, specifically when it calls sh2_open(), where it then fails. It does seem to be able to get the address of the second sensor, but can't do anything with it.

However, it must surely be possible to support multiple sensors somehow in the Arduino library, because doing something similar in CircuitPython gets me the result I'd expect, which is two streams of sensor data from both sensors simultaneously.

import time
import board
import busio
from adafruit_bno08x import (
    BNO_REPORT_ROTATION_VECTOR,
)
from adafruit_bno08x.i2c import BNO08X_I2C

i2c = busio.I2C(board.SCL, board.SDA, frequency=800000)
bno1 = BNO08X_I2C(i2c, None, address=0x4A)
bno2 = BNO08X_I2C(i2c, None, address=0x4B)

bno1.enable_feature(BNO_REPORT_ROTATION_VECTOR)
bno2.enable_feature(BNO_REPORT_ROTATION_VECTOR)

while True:

    time.sleep(0.2)

    print("Rotation Vector Quaternion 1:")
    quat_i, quat_j, quat_k, quat_real = bno1.quaternion  # pylint:disable=no-member
    print(
        "I: %0.6f  J: %0.6f K: %0.6f  Real: %0.6f" % (quat_i, quat_j, quat_k, quat_real)
    )
    print("")

    time.sleep(0.2)

    print("Rotation Vector Quaternion 2:")
    quat_i, quat_j, quat_k, quat_real = bno2.quaternion  # pylint:disable=no-member
    print(
        "I: %0.6f  J: %0.6f K: %0.6f  Real: %0.6f" % (quat_i, quat_j, quat_k, quat_real)
    )
    print("")

Example output:

Rotation Vector Quaternion 1:
I: 0.886047  J: -0.334045 K: -0.115601  Real: 0.299866

Rotation Vector Quaternion 2:
I: -0.152466  J: 0.941833 K: -0.277405  Real: 0.112854

I'm unsure what specifically is missing in the C library to cause it to fail like this, but it seems to affect both I2C and SPI.

EDIT: As a follow-up, I went ahead and tried to link up all 6 of my IMUs through CircuitPython with multiple busses using SERCOMs (2 IMUs per bus) at the same time, and it worked without any issue.

@StarWitch

Could u please provide the entire code that you used to make the 6 IMU sensors work.

Thank you

VGSchaack commented 1 year ago

Has the issue been fixed yet?

ras-marques commented 1 year ago

I am also interested in this.

ntaylor562 commented 1 year ago

Still encountering this issue using I2C. Is this being worked on?

JacksonVanderkooy commented 7 months ago

This seems like a pretty large oversight considering the BNO08x has such a simple way to switch the i2c address. Is this being worked on?

tconzem commented 7 months ago

I worked on a project where I had to use multiple of the BNO086 to calculate the angles between them. It took me a while but I got it working now. Since the pins are passed in the low level sh2 write and read functions, they cannot be normal class members. I got around this by making them static class members and setting the "active" sensor (changing the member pins) each time before getting an event, setting reports, etc. If anyone is interested I could clean up the code and post it sometime next week.

JacksonVanderkooy commented 7 months ago

@tconzem If you could that would be amazing! I bought several of these for my capstone project assuming the I2C meant I could use multiple and I don't have the time to change the plan or learn how to do the low-level stuff.

ntaylor562 commented 7 months ago

The sparkfun bno080 library seems to work for me

tconzem commented 7 months ago

Unfortunately, I didn't have the time to clean it up, but this may help. I was using SPI on an RP2040 microcontroller, so you won't be able to use the code directly, but if you take a look at that example main, it should help you understand how you can implement it yourself. The most important part would be the setActiveSensor function. Let me know if you have any further questions and I'll try to get back to you! bno086_code.zip

Meko12345 commented 7 months ago

Hello Team I have Arduino mega with 2 BNO08X. Is there a library I can download to run both of them together please? Thanks

akshrajput2001 commented 6 months ago

Hi, I am still struggling with the same issue. The first IMU works fine but not the second one. As pointed out by someone in this thread that it may be due to the library layout. Has anyone found a workaround to this?

aidanm247 commented 5 months ago

I am also having this same exact issue, my scanner can detect both devices but I can't initialize both of them using I2C. Has anyone found a solution to this?

akshrajput2001 commented 5 months ago

I did it using different libraries. For the first I used BNO08x.h and for other I used the SparkfunBNO085 library, and it worked fine.

aidanm247 commented 5 months ago

I did it using different libraries. For the first I used BNO08x.h and for other I used the SparkfunBNO085 library, and it worked fine.

Could you post the code that you used? Thanks

VICLER commented 2 months ago

The sparkfun bno080 library seems to work for me

Just tried the sparkfun library and hoped it will work for two bno085 sensors with different i2c adresses. But it behaves the same as adafruit one. Looked in code and they also using static variables for adress and etc. That is very sad that there is no library for this sensor which can manage more than one sensor.

update: just edited a sparkfun library a bit like so now I am able to manage 4x bno085 sensors over i2c using two different adresses and two i2c ports on esp32S3. @tconzem thanks for inspiration!