12-07-2021 09:47 AM
I am trying to get this basic tutorial working for the Nicla and Portenta H7 connected over ESLOV (I2C connection). The bug in the example code is that it only works for a little over half an hour before crashing.
I modified his code for debugging purposes:
arduino-libraries/Arduino_BHY2Host/examples/Accelerometer/Accelerometer_copy.ino:
#include "Arduino.h"
#include "Arduino_BHY2Host.h"
#include <LandoRGBLedPortenta.h>
SensorXYZ accel(SENSOR_ID_ACC);
LandoRGBLedPortenta portentaLeds;
const int MAX_DUPLICATE_READINGS = 10;
String colorToToggle = "white";
int duplicateReadings = 0;
static unsigned long printTime = 0;
static unsigned long startTime = 0;
static String timeToCrash = "";
static String lastAccelReading = "";
void setup()
{
Serial.begin(115200);
while(!Serial);
Serial.println("Serial started!");
portentaLeds.setColor("red");
BHY2Host.begin(false, NICLA_VIA_ESLOV);
Serial.println("BHY2HostSuccess!");
portentaLeds.setColor("green");
accel.begin();
Serial.println("Leaving setup!");
portentaLeds.setColor("blue");
printTime = millis();
startTime = printTime;
}
void loop()
{
BHY2Host.update();
if (millis() - printTime >= 1000) {
printTime = millis();
String accelReading = accel.toString();
if(accelReading == lastAccelReading) {
duplicateReadings++;
if(duplicateReadings == MAX_DUPLICATE_READINGS) {
timeToCrash = " " + String(printTime - startTime) + " ms";
colorToToggle = "red";
}
}
else {
duplicateReadings = 0;
}
Serial.println(String("Acceleration values: ") + String(accelReading) + String(timeToCrash));
portentaLeds.toggleColor(colorToToggle);
lastAccelReading = accelReading;
}
}
arduino-libraries/Arduino_BHY2/examples/App/App_copy.ino:
#include "Nicla_System.h"
#include "Arduino.h"
#include "Arduino_BHY2.h"
void colorCycle(int loops) {
for(int i = 0; i < loops; i++) {
nicla::leds.setColor(red);
delay(1000);
nicla::leds.setColor(green);
delay(1000);
nicla::leds.setColor(blue);
delay(1000);
}
nicla::leds.setColor(off);
}
void setup(){
BHY2.begin(NICLA_I2C, NICLA_VIA_ESLOV);
nicla::leds.begin();
colorCycle(5);
}
void loop(){
// Update and then sleep
nicla::leds.setColor(blue);
BHY2.update(500);
nicla::leds.setColor(off);
}
After 1,881,243–2,398,485 ms, the Nicla stops updating…
If I reset just the Portenta and relaunch the serial printer, the Portenta halts at the accel.begin(); line in the setup...
12-13-2021 12:44 AM - edited 12-13-2021 01:07 AM
hi @Lsi8
Let me give you some more info of the Nicla Sense Board.
The Nicla Sense board has two processors: one is the main MCU (nRF52832) and the other is the BHI260AP (an effiect processor dedicated to sensor data processing like sensor fusion), and the two MCUs are connected via high speed SPI, and all the sensors are connected to the BHI260AP.
The IMU sensor (on the BHI260AP) does support high rates (1600Hz max for accel) and (6400Hz max for the gyro).
When you are using the Nicla Sense board, you don't have direct access to the raw sensor data, which needs to be streamed over the SPI bus between the two MCUs. And the sensor data can be transferred to the external world using different interfaces of the main MCU: ESLOV (I2C), SPI, BLE, UART etc
Actually, a typical use case for Nicla board is: instead of sending high rate physical sensor data to a host or cloud for processing, the data could be processed locally on the BHI260AP and only meaningful / human interpretable results (such as orientation, motion events, IAQ levels) usually of much lower rate need to be sent out to host or cloud. One reason is BHI260AP is very efficient / low power for the sensor processing, and also this saves your tons of efforts doing tricky sensor fusion running on the host (9 DoF fusion or BSEC etc). E.g.: instead of streaming 400hz of accel and gyro raw data and feeding them to a senor fusion software to get quaternions, you could read the quaternions directly (at 20hz for example) from BHI260AP which does the heavy lift for you.
With that being said, it's still possible to stream the raw sensor data even at high rate from Nicla. Here are some hints:
In your particular project, you want to stream sensor data at @100hz
If you want to use the ESLOV to transfer the data to another board, ESLOV under the hood is I2C, so in theory it should be able to support 100hz data rate, because I2C can run at 400Kbps.
However, there are some limits rendered by the current software library (Arduino_BHY2Host) which operates the ESLOV interface. e.g.:
#define ESLOV_DELAY (10)
void EslovHandler::writeStateChange(EslovState state)
{
delay(ESLOV_DELAY);
while(!digitalRead(_eslovIntPin)) {}
uint8_t packet[2] = {ESLOV_SENSOR_STATE_OPCODE, state};
Wire.beginTransmission(ESLOV_DEFAULT_ADDRESS);
Wire.write((uint8_t*)packet, sizeof(packet));
Wire.endTransmission();
delay(ESLOV_DELAY);
_eslovState = state;
}
the delay in this function alone is 20ms, rendering a rate smaller than 50hz, not to mention other delays.
My understanding is that: the ESLOV is (currently) designed for tranfer of low rate sensor data (such as events rather than continous high rate data).
In theory, it (the library) could be redesigned / optimized to accomodate high rate (> 100hz) because it's I2C under the hood but it requires custom software changes, you could post a question on Arduino forum or github if you want to get deep in this.
The other options are to use other interfaces of the main MCU such as SPI (requires you to write your own code) or Serial (UART).
E.g.:
example sketch on Nicla Sense (tested):
/*
* This sketch shows how nicla can be used in standalone mode.
* Without the need for an host, nicla can run sketches that
* are able to configure the bhi sensors and are able to read all
* the bhi sensors data.
*/
#include "Arduino.h"
#include "Arduino_BHY2.h"
SensorXYZ accel(SENSOR_ID_ACC);
SensorXYZ gyro(SENSOR_ID_GYRO);
Sensor temp(SENSOR_ID_TEMP);
Sensor humid(SENSOR_ID_HUM);
Sensor gas(SENSOR_ID_GAS);
SensorQuaternion rotation(SENSOR_ID_RV);
#define BAUD_RATE_SERIAL_DATA (115200 * 8)
void setup()
{
Serial.begin(BAUD_RATE_SERIAL_DATA);
while(!Serial);
BHY2.begin();
accel.begin(100);
gyro.begin(100);
temp.begin(1);
humid.begin(1);
gas.begin();
//rotation.begin();
}
void loop()
{
static auto printTime = millis();
// Update function should be continuously polled
BHY2.update();
if (millis() - printTime >= 1) {
printTime = millis();
//note: this is just an example, there would be alot of duplicated print below because some sensors are low rate
//users could do changes to the code to optimize (ideally print should be done in setData() of each class)
Serial.println(String("acceleration: ") + accel.toString());
Serial.println(String("gyroscope: ") + gyro.toString());
Serial.println(String("temperature: ") + String(temp.value(),3));
Serial.println(String("gas: ") + String(gas.value(),3));
//Serial.println(String("quaternion: ") + rotation.toString());
}
}
Sketch on the MKR or Portenta side:
/*
* This sketch allows to control nicla from a PC.
* Upload this sketch on an arduino board connected to nicla
* through the eslov connector. Then connect the same arduino board
* to your PC.
* Now you can use the arduino-bhy tool, written in golang,
* to control nicla from either the PC command line or from a web page.
*
* NOTE: if Nicla is used as a Shield on top of a MKR board,
* please use BHY2Host.begin(true, NICLA_AS_SHIELD)
*/
#include "Arduino.h"
#define BAUD_RATE_SERIAL_DEBUG (115200 * 8)
#define BAUD_RATE_SERIAL_DATA (115200 * 8)
void setup()
{
Serial.begin(115200); //this is the USB debug port of the MKR or Portenta board
Serial1.begin(BAUD_RATE_SERIAL_DATA); //Serial1 is the TX/RX on the MKR or Portenta header
}
void loop()
{
if (Serial1.available()) {
Serial.write(Serial1.read());
}
}
to use the code above, you simply use the Nicla board as a shield on the MKR or Portenta board.
The above code sends the data using text format and has a lot of room for further improvement. But since the serial runs at ~1mbps, it's definitely would be able to support your use case..