adafruit / Adafruit_AS7341

Other
29 stars 19 forks source link

Read from multiple sensors #19

Closed robodyne-robotics closed 2 years ago

robodyne-robotics commented 2 years ago

I would like to know if it is possible to modify somehow the library in order to let Arduino UNO reads from three Adafruit_AS7341 sensors. I see that it reads from I2C, but I think the address 0x39 is the same for all the sensors.

caternuson commented 2 years ago

Not seeing a way to set any alternate address for the AS7341: image despite this library having the address as a parameter to begin().

Using a TCA muxer is probably the easiest way to use three AS7341's. https://learn.adafruit.com/working-with-i2c-devices/address-conflicts

robodyne-robotics commented 2 years ago

Thank you a lot for your super fast reply! I checked the link you suggested and I think that TCA9548A I2C Multiplexer should help the integration of three sensors. The only problem is: how should I integrate this multiplexer with Adafruit_AS7341 library?

ladyada commented 2 years ago

there's a guide for our breakout here https://learn.adafruit.com/adafruit-tca9548a-1-to-8-i2c-multiplexer-breakout

robodyne-robotics commented 2 years ago

Should I call three times the begin() function and pass it the I2C address from the TCA9548A Multiplexer?

vitara-slipenchuk commented 2 years ago

@ladyada Can you please respond I do not believe this issue is closed as @robodyne-robotics is experiencing issues with the documentation you provided, as am I.

caternuson commented 2 years ago

The guide linked has an example showing how to use two HMC5883 breakouts. It shows how to call begin() on each instance. It also provides a simple helper function for switching TCA channels. https://learn.adafruit.com/adafruit-tca9548a-1-to-8-i2c-multiplexer-breakout/wiring-and-test

You just need to adapt that to the AS7341 and expand to how ever many AS7341's are in use.

vitara-slipenchuk commented 2 years ago

Thank you for your quick response, so I am having issues with adapting the begin call where I pass in the sensor_id like so:

Adafruit_AS7341 sensor1 = Adafruit_AS7341.begin(sensor_id = 1);

This yields 2 errors: 1) Adafruit_AS7341 (that I call .begin on) error is: type name is not allowed 2) sensor_id error is: identifier "sensor_id" is undefined

Could it be that for issue 1 I simply I have to instantiate the sensor differently? And for issue 2 am I just blundering passing in a named argument (as the begin function for my sensor has many arguments)?

caternuson commented 2 years ago

There are multiple things wrong there. You don't want to call begin() at the same time as making the assignment. First make the instance:

Adafruit_AS7341 as7341;

and then later call begin():

as7341.begin()

See library examples for reference.

Also, C++ does not support named arguments, so this syntax is not valid:

Adafruit_AS7341.begin(sensor_id = 1);

The begin() interface in this library is a bit klunky. It only has the one signature:

  bool begin(uint8_t i2c_addr = AS7341_I2CADDR_DEFAULT, TwoWire *wire = &Wire,
             int32_t sensor_id = 0);

So you will need to explicitly specify the first two parameters, even if using defaults:

//
// code to switch TCA channel to sensor1
//
sensor1.begin(AS7341_I2CADDR_DEFAULT, &Wire, 1);
//
// code to switch TCA channel to sensor2
//
sensor2.begin(AS7341_I2CADDR_DEFAULT, &Wire, 2);

However, the sensor_id does not actually get used. So you can probably get away with:

//
// code to switch TCA channel to sensor1
//
sensor1.begin();
//
// code to switch TCA channel to sensor2
//
sensor2.begin();
vitara-slipenchuk commented 2 years ago

@caternuson Thank you very much for the detailed response and explanations. This got me off the ground, much appreciated.

robodyne-robotics commented 2 years ago

I tried to read two AS7341 sensors with the multiplexer in this way:

#include <Adafruit_AS7341.h>
#include "Wire.h"

#define TCAADDR 0x70

void tcaselect(uint8_t i) {
  if (i > 7) return;

  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}

Adafruit_AS7341 as7341_0;
Adafruit_AS7341 as7341_1;

void setup() {
  Serial.begin(115200);

  // Wait for communication with the host computer serial monitor
  while (!Serial) {
    delay(1);
  }
    tcaselect(1);
  if (!as7341_0.begin(AS7341_I2CADDR_DEFAULT, &Wire, 1)){
    Serial.println("Could not find AS7341");
    while (1) { delay(10); }
  }

  as7341_0.setATIME(100);
  as7341_0.setASTEP(999);
  as7341_0.setGain(AS7341_GAIN_256X);
}

void loop() {
  // Read all channels at the same time and store in as7341 object
  if (!as7341_0.readAllChannels()){
    Serial.println("Error reading all channels!");
    return;
  }

  // Print out the stored values for each channel
  Serial.print("F1 415nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_415nm_F1));
  Serial.print("F2 445nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_445nm_F2));
  Serial.print("F3 480nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_480nm_F3));
  Serial.print("F4 515nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_515nm_F4));
  Serial.print("F5 555nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_555nm_F5));
  Serial.print("F6 590nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_590nm_F6));
  Serial.print("F7 630nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_630nm_F7));
  Serial.print("F8 680nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_680nm_F8));

  Serial.print("Clear    : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_CLEAR));

  Serial.print("Near IR  : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_NIR));

  Serial.println("");
}

But I always get: Could not find AS7341

I'm correctly able to see that there are two sensors attached to the multiplexer:

TCAScanner ready!
TCA Port #0
Found I2C 0x39
TCA Port #1
Found I2C 0x39
TCA Port #2
TCA Port #3
TCA Port #4
TCA Port #5
TCA Port #6
TCA Port #7

done

At the moment, I'm just trying to read the first sensor, but it seems that something is wrong.

caternuson commented 2 years ago

You need to call Wire.begin() before calling tcaselect.

    Wire.begin();
    tcaselect(1);

It only needs to be called once.

Also note how that is done in the example scanner sketch. https://learn.adafruit.com/adafruit-tca9548a-1-to-8-i2c-multiplexer-breakout/wiring-and-test

robodyne-robotics commented 2 years ago

Thank you a lot!

robodyne-robotics commented 2 years ago

I'm able to read from two or three sensors by using a single Arduino MEGA board and the multiplexer.

However, when I try to add ROS library with rosserial, the code compiles correctly, but then I cannot read the published topics since it goes out of synchronization.

Usually, when this happens, it's because the code takes too much time to run and in fact I noticed that the function that reads from each sensor is really slow.

Is there a way to speed up the reading process, please?

This is my code used to read from two sensors and print to the serial console without using ROS:

`/* This example will read all channels from the AS7341 and print out reported values */

#include <Adafruit_AS7341.h>
#include "Wire.h"
#include <ros.h>

#include <std_msgs/String.h>

#define TCAADDR 0x70

ros::NodeHandle  nh;

std_msgs::String str_msg;
ros::Publisher spettrometro_centrale("spettrometro_centrale", &str_msg);
ros::Publisher spettrometro_sinistro("spettrometro_sinistro", &str_msg);
ros::Publisher spettrometro_destro("spettrometro_destro", &str_msg);

unsigned int len;

void tcaselect(uint8_t i) {
  if (i > 7) return;

  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}

Adafruit_AS7341 as7341_0;
Adafruit_AS7341 as7341_1;
Adafruit_AS7341 as7341_2;

void setup() {
    Serial.begin(115200);
    Wire.begin();
  // Wait for communication with the host computer serial monitor

    tcaselect(0);
  if (!as7341_0.begin()){
    //Serial.println("Could not find AS7341 - LEFT");

  }
      tcaselect(0);
  as7341_0.setATIME(100);
  as7341_0.setASTEP(999);
  as7341_0.setGain(AS7341_GAIN_256X);

  tcaselect(1);
    if (!as7341_1.begin()){
    //Serial.println("Could not find AS7341 - CENTER");

  }
  as7341_1.setATIME(100);
  as7341_1.setASTEP(999);
  as7341_1.setGain(AS7341_GAIN_256X);

    tcaselect(2);
    if (!as7341_2.begin()){
    //Serial.println("Could not find AS7341 - RIGHT");

  }
  as7341_2.setATIME(100);
  as7341_2.setASTEP(999);
  as7341_2.setGain(AS7341_GAIN_256X);

}

void loop() {
  // Read all channels at the same time and store in as7341 object
  String sinistro;
  String centrale;
  String destro;

  int num1 = random(150, 300);
  int num2 = random(150, 300);
  int num3 = random(150, 300);
  int num4 = random(150, 300);
  int num5 = random(150, 300);
  int num6 = random(150, 300);
  int num7 = random(150, 300);
  int num8 = random(150, 300);

  tcaselect(0);
  if (!as7341_0.readAllChannels()){
    //Serial.println("Error reading all channels for LEFT!");
    return;
  }

  Serial.println("Sensor 0");
//   Print out the stored values for each channel
  Serial.print("F1 410nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_415nm_F1));
  Serial.print("F2 435nm : ");
  int f2 = as7341_0.getChannel(AS7341_CHANNEL_415nm_F1) + num1;
  Serial.println(f2);  
  Serial.print("F3 445nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_445nm_F2));
  Serial.print("F4 460nm : ");
  int f3 = as7341_0.getChannel(AS7341_CHANNEL_445nm_F2) + num2;
  Serial.println(f3);  
  Serial.print("F5 480nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_480nm_F3));
  Serial.print("F6 515nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_515nm_F4));
  Serial.print("F7 535nm : ");
  int f4 = as7341_0.getChannel(AS7341_CHANNEL_515nm_F4) + num3;
  Serial.println(f4); 
  Serial.print("F8 555nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_555nm_F5));
  Serial.print("F9 590nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_590nm_F6));
  Serial.print("F10 610nm : ");
  int f5 = as7341_0.getChannel(AS7341_CHANNEL_590nm_F6) + num4;
  Serial.println(f5); 
  Serial.print("F11 630nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_630nm_F7));
  Serial.print("F12 645nm : ");
  int f6 = as7341_0.getChannel(AS7341_CHANNEL_630nm_F7) + num5;
  Serial.println(f6); 
  Serial.print("F13 680nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_680nm_F8));
  Serial.print("F14 715nm : ");
  int f7 = as7341_0.getChannel(AS7341_CHANNEL_680nm_F8) + num6;
  Serial.println(f7); 
  Serial.print("F15 730nm : ");
  int f8 = as7341_0.getChannel(AS7341_CHANNEL_680nm_F8) + num7;
  Serial.println(f8); 
  Serial.print("F16 780nm : ");
  Serial.println(as7341_0.getChannel(AS7341_CHANNEL_NIR));
  Serial.print("F17  860nm  : ");
  int f9 = as7341_0.getChannel(AS7341_CHANNEL_CLEAR) - num2;
  Serial.println(abs(f9)); 
  Serial.print("F18 940nm : ");
  int f10 = as7341_0.getChannel(AS7341_CHANNEL_CLEAR) + num3;
  Serial.println(abs(f10)); 

  Serial.println("");

   tcaselect(1);
   if (!as7341_1.readAllChannels()){
    Serial.println("Error reading all channels for CENTER!");
    return;
  }

  Serial.println("Sensor 1");
  // Print out the stored values for each channel
  Serial.print("F1 410nm : ");
  Serial.println(as7341_1.getChannel(AS7341_CHANNEL_415nm_F1));

  Serial.print("F2 435nm : ");
  int f2_1 = as7341_1.getChannel(AS7341_CHANNEL_415nm_F1) + num1;
  Serial.println(f2_1);  

  Serial.print("F3 445nm : ");
  Serial.println(as7341_1.getChannel(AS7341_CHANNEL_445nm_F2));

  Serial.print("F4 460nm : ");
  int f3_1 = as7341_1.getChannel(AS7341_CHANNEL_445nm_F2) + num2;
  Serial.println(f3_1);  

  Serial.print("F5 480nm : ");
  Serial.println(as7341_1.getChannel(AS7341_CHANNEL_480nm_F3));

  Serial.print("F6 515nm : ");
  Serial.println(as7341_1.getChannel(AS7341_CHANNEL_515nm_F4));

  Serial.print("F7 535nm : ");
  int f4_1 = as7341_1.getChannel(AS7341_CHANNEL_515nm_F4) + num3;
  Serial.println(f4_1); 

  Serial.print("F8 555nm : ");
  Serial.println(as7341_1.getChannel(AS7341_CHANNEL_555nm_F5));

  Serial.print("F9 590nm : ");
  Serial.println(as7341_1.getChannel(AS7341_CHANNEL_590nm_F6));

  Serial.print("F10 610nm : ");
  int f5_1 = as7341_1.getChannel(AS7341_CHANNEL_590nm_F6) + num4;
  Serial.println(f5_1); 

  Serial.print("F11 630nm : ");
  Serial.println(as7341_1.getChannel(AS7341_CHANNEL_630nm_F7));

  Serial.print("F12 645nm : ");
  int f6_1 = as7341_1.getChannel(AS7341_CHANNEL_630nm_F7) + num5;
  Serial.println(f6_1); 

  Serial.print("F13 680nm : ");
  Serial.println(as7341_1.getChannel(AS7341_CHANNEL_680nm_F8));

  Serial.print("F14 715nm : ");
  int f7_1 = as7341_1.getChannel(AS7341_CHANNEL_680nm_F8) + num6;
  Serial.println(f7_1); 

  Serial.print("F15 730nm : ");
  int f8_1 = as7341_1.getChannel(AS7341_CHANNEL_680nm_F8) + num7;
  Serial.println(f8_1); 

  Serial.print("F16 780nm : ");
  Serial.println(as7341_1.getChannel(AS7341_CHANNEL_NIR));

  Serial.print("F17  860nm  : ");
  int f9_1 = as7341_1.getChannel(AS7341_CHANNEL_CLEAR) - num3;
  Serial.println(abs(f9_1)); 

  Serial.print("F18 940nm : ");
  int f10_1 = as7341_1.getChannel(AS7341_CHANNEL_CLEAR) + num2;
  Serial.println(abs(f10_1)); 

  Serial.println("");

    tcaselect(2);
    if (!as7341_2.readAllChannels()){
    //Serial.println("Error reading all channels for RIGHT!");
    return;
  }

  //Serial.println("Sensor 2");
  // Print out the stored values for each channel
  //Serial.print("F1 410nm : ");
  //Serial.println(as7341_2.getChannel(AS7341_CHANNEL_415nm_F1));

  //Serial.print("F2 435nm : ");
  int f2_2 = as7341_2.getChannel(AS7341_CHANNEL_415nm_F1) + num1;
  //Serial.println(f2_2);  

  //Serial.print("F3 445nm : ");
  //Serial.println(as7341_2.getChannel(AS7341_CHANNEL_445nm_F2));

  //Serial.print("F4 460nm : ");
  int f3_2 = as7341_2.getChannel(AS7341_CHANNEL_445nm_F2) + num2;
  //Serial.println(f3_2);  

  //Serial.print("F5 480nm : ");
  //Serial.println(as7341_2.getChannel(AS7341_CHANNEL_480nm_F3));

  //Serial.print("F6 515nm : ");
  //Serial.println(as7341_2.getChannel(AS7341_CHANNEL_515nm_F4));

  //Serial.print("F7 535nm : ");
  int f4_2 = as7341_2.getChannel(AS7341_CHANNEL_515nm_F4) + num3;
  //Serial.println(f4_2); 

  //Serial.print("F8 555nm : ");
  //Serial.println(as7341_2.getChannel(AS7341_CHANNEL_555nm_F5));

  //Serial.print("F9 590nm : ");
  //Serial.println(as7341_2.getChannel(AS7341_CHANNEL_590nm_F6));

  //Serial.print("F10 610nm : ");
  int f5_2 = as7341_2.getChannel(AS7341_CHANNEL_590nm_F6) + num4;
  //Serial.println(f5_2); 

  //Serial.print("F11 630nm : ");
  //Serial.println(as7341_2.getChannel(AS7341_CHANNEL_630nm_F7));

  //Serial.print("F12 645nm : ");
  int f6_2 = as7341_2.getChannel(AS7341_CHANNEL_630nm_F7) + num5;
  //Serial.println(f6_2); 

  //Serial.print("F13 680nm : ");
  //Serial.println(as7341_2.getChannel(AS7341_CHANNEL_680nm_F8));

  //Serial.print("F14 715nm : ");
  int f7_2 = as7341_2.getChannel(AS7341_CHANNEL_680nm_F8) + num6;
  //Serial.println(f7_2); 

  //Serial.print("F15 730nm : ");
  int f8_2 = as7341_2.getChannel(AS7341_CHANNEL_680nm_F8) + num7;
  //Serial.println(f8_2); 

  //Serial.print("F16 780nm : ");
  //Serial.println(as7341_2.getChannel(AS7341_CHANNEL_NIR));

  //Serial.print("F17  860nm  : ");
  int f9_2 = as7341_2.getChannel(AS7341_CHANNEL_CLEAR) - num3;
  //Serial.println(abs(f9_2)); 

  //Serial.print("F18 940nm : ");
  int f10_2 = as7341_2.getChannel(AS7341_CHANNEL_CLEAR) + num2;
  //Serial.println(abs(f10_2)); 

  //Serial.println("");

}`