From f8067e29deaaf3dbb3cb2c2b6e8f61f9406f8105 Mon Sep 17 00:00:00 2001 From: zg guo Date: Thu, 20 Oct 2022 23:13:55 -0700 Subject: [PATCH 1/4] sampling of accel+gyro at 1600hz over usb serial --- ...seME-nobsx-1600hz-IMU-passthrough-flash.fw | Bin 0 -> 109820 bytes .../SyncAndCollectIMUData.ino | 188 ++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 Arduino_BHY2/examples/SyncAndCollectIMUData/NiclaSenseME-nobsx-1600hz-IMU-passthrough-flash.fw create mode 100644 Arduino_BHY2/examples/SyncAndCollectIMUData/SyncAndCollectIMUData.ino diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/NiclaSenseME-nobsx-1600hz-IMU-passthrough-flash.fw b/Arduino_BHY2/examples/SyncAndCollectIMUData/NiclaSenseME-nobsx-1600hz-IMU-passthrough-flash.fw new file mode 100644 index 0000000000000000000000000000000000000000..6f9db77e2bab3d048e0672b83b5c9cd07c1c5353 GIT binary patch literal 109820 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
W&b(%21)Kn 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 Xj1SU>)Rs4N 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 TV5ux8-h0?;JaqN{-u8b1J9QeY literal 0 HcmV?d00001 diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/SyncAndCollectIMUData.ino b/Arduino_BHY2/examples/SyncAndCollectIMUData/SyncAndCollectIMUData.ino new file mode 100644 index 00000000..61a2e789 --- /dev/null +++ b/Arduino_BHY2/examples/SyncAndCollectIMUData/SyncAndCollectIMUData.ino @@ -0,0 +1,188 @@ +/* + * 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" + +class IMUDataSyncer; +class SensorMotion; + +#define DEBUG 0 + +#if DEBUG +#include "MbedQDebug.h" +#else +void *nicla_dbg_info_ptr; +#endif + +class IMUDataSyncer { + public: + IMUDataSyncer() { + int i; + for (i = 0; i < sizeof(_seq)/sizeof(_seq[0]); i++) { + _seq[i] = -1; + _data[i] = NULL; + } + } + + virtual bool begin(int accelSampleRate, int gyroSampleRate) { + int sampleRate = accelSampleRate > gyroSampleRate ? accelSampleRate : gyroSampleRate; + + if ((accelSampleRate > 0) && (gyroSampleRate > 0)) { + + if (accelSampleRate != gyroSampleRate) { + _logId = 'u'; //data cannot be synced + return false; + } else { + _logId = 'i'; + } + } else if (accelSampleRate > 0) { + _logId = 'a'; + } else if (gyroSampleRate > 0){ + _logId = 'g'; + } else { + _logId = 'n'; + } + + return true; + } + + void onSensorDataUpdate(DataXYZ &data, int id) { + _data[id] = &data; + + if ('i' == _logId) { + //we assume id is always 0 (for accel) or 1 (for gyro) + //when _seq[1 - id] is less than 0, it means the other sensor has not received any value yet + if (_seq[1 - id] >= 0) { + _seq[id] = (_seq[id]+1) % 10; + } else { + _seq[id] = 0; //wait for another sensor to generate the 1st sample + } + + if (_seq[id] == _seq[1 - id]) { + //data synced well and ready for sending out + #if DEBUG + mbq_dbg_1(1); + #endif + + #if 0 + //enable this if you want to send the sequence number in each line, + //for highest ODR, we ignore this to save bandwidth + Serial.print(_logId); + Serial.print((char)(_seq[id]+'0')); Serial.print(','); + #endif + //accel data fields + Serial.print(_data[0]->x); Serial.print(','); + Serial.print(_data[0]->y); Serial.print(','); + Serial.print(_data[0]->z); Serial.print(','); + //gyro data fields + Serial.print(_data[1]->x); Serial.print(','); + Serial.print(_data[1]->y); Serial.print(','); + Serial.print(_data[1]->z); Serial.println(); + + #if DEBUG + mbq_dbg_1(0); + #endif + } + } else { + _seq[id] = (_seq[id]+1) % 10; + Serial.print(_logId); + Serial.print(_seq[id]); Serial.print(','); + Serial.print(_data[id]->x); Serial.print(','); + Serial.print(_data[id]->y); Serial.print(','); + Serial.print(_data[id]->z); Serial.println(); + } + } + + protected: + char _logId; + int8_t _seq[2]; + DataXYZ *_data[2]; +}; + +class SensorMotion : public SensorClass { + public: + SensorMotion(uint8_t id) : SensorClass(id) { + _id = (id / 10); //accel: 0, gyro: 1, mag: 2 + _dataSyncer = NULL; + } + + void setDataSyncer(IMUDataSyncer &dataSyncer) { + _dataSyncer = &dataSyncer; + } + + void setData(SensorDataPacket &data) { + DataParser::parse3DVector(data, _data); + _dataSyncer->onSensorDataUpdate(_data, _id); + } + + void setData(SensorLongDataPacket &data) {} + + String toString() { + return _data.toString(); + } + + protected: + DataXYZ _data; + uint8_t _id; + IMUDataSyncer *_dataSyncer; +}; + + +SensorMotion accel(1); //sensor id 1: accel raw data passthrough +SensorMotion gyro(10); //sensor id 10: gyro raw data passthrough +IMUDataSyncer imuDataSyncer; + +#define IMU_DATA_RATE 1600 + + + +void testSerial() +{ + while (0) { + Serial.print('*'); + //Serial.println(); + + delay(1000); + } +} + +void setup() +{ + //Serial.begin(115200); + Serial.begin(1000000); //max br: 1Mbps for nRF52 + while(!Serial); + + BHY2.begin(NICLA_STANDALONE); + + testSerial(); + + SensorConfig cfg = accel.getConfiguration(); + Serial.println(String("range of accel: +/-") + cfg.range + String("g")); + accel.setRange(8); //this sets the range of accel to +/-8g, + cfg = accel.getConfiguration(); + Serial.println(String("range of accel: +/-") + cfg.range + String("g")); + + imuDataSyncer.begin(IMU_DATA_RATE, IMU_DATA_RATE); + accel.setDataSyncer(imuDataSyncer); + gyro.setDataSyncer(imuDataSyncer); + accel.begin(IMU_DATA_RATE); + gyro.begin(IMU_DATA_RATE); +} + +void loop() +{ + #if DEBUG + mbq_dbg_0(1); + #endif + + BHY2.update(); + + #if DEBUG + mbq_dbg_0(0); + #endif +} From 60e3bcbe24ce4a7b9979227840819cf74c2e8b0f Mon Sep 17 00:00:00 2001 From: zg guo Date: Sat, 22 Oct 2022 22:51:27 -0700 Subject: [PATCH 2/4] add support for output in base64 encoding for more reliability --- .../SyncAndCollectIMUData/.reuse/dep5 | 9 + .../SyncAndCollectIMUData/LICENSES/MIT.txt | 21 + .../SyncAndCollectIMUData.ino | 361 +++++++++++------- .../examples/SyncAndCollectIMUData/base64.hpp | 221 +++++++++++ 4 files changed, 467 insertions(+), 145 deletions(-) create mode 100644 Arduino_BHY2/examples/SyncAndCollectIMUData/.reuse/dep5 create mode 100644 Arduino_BHY2/examples/SyncAndCollectIMUData/LICENSES/MIT.txt create mode 100644 Arduino_BHY2/examples/SyncAndCollectIMUData/base64.hpp diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/.reuse/dep5 b/Arduino_BHY2/examples/SyncAndCollectIMUData/.reuse/dep5 new file mode 100644 index 00000000..ac0b60f2 --- /dev/null +++ b/Arduino_BHY2/examples/SyncAndCollectIMUData/.reuse/dep5 @@ -0,0 +1,9 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ + +Upstream-Name: SyncAndCollectIMUData.ino +Upstream-Contact: Lucas Guo +Source: + +Files: base64.hpp +Copyright: Copyright (c) 2016 Densauge +License: MIT diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/LICENSES/MIT.txt b/Arduino_BHY2/examples/SyncAndCollectIMUData/LICENSES/MIT.txt new file mode 100644 index 00000000..1cef10b5 --- /dev/null +++ b/Arduino_BHY2/examples/SyncAndCollectIMUData/LICENSES/MIT.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Densaugeo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/SyncAndCollectIMUData.ino b/Arduino_BHY2/examples/SyncAndCollectIMUData/SyncAndCollectIMUData.ino index 61a2e789..59ad6329 100644 --- a/Arduino_BHY2/examples/SyncAndCollectIMUData/SyncAndCollectIMUData.ino +++ b/Arduino_BHY2/examples/SyncAndCollectIMUData/SyncAndCollectIMUData.ino @@ -3,133 +3,199 @@ * 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" -class IMUDataSyncer; -class SensorMotion; +#include "base64.hpp" //remember to include the library "base64 by Densaugeo" from Library manager -#define DEBUG 0 +#define PDEBUG 0 -#if DEBUG +#if PDEBUG #include "MbedQDebug.h" #else void *nicla_dbg_info_ptr; #endif + +class IMUDataSyncer; +class SensorMotion; + +enum { + IMU_SENSOR_ID_ACC = 0, + IMU_SENSOR_ID_GYR, +}; + class IMUDataSyncer { - public: - IMUDataSyncer() { - int i; - for (i = 0; i < sizeof(_seq)/sizeof(_seq[0]); i++) { - _seq[i] = -1; - _data[i] = NULL; - } - } - - virtual bool begin(int accelSampleRate, int gyroSampleRate) { - int sampleRate = accelSampleRate > gyroSampleRate ? accelSampleRate : gyroSampleRate; - - if ((accelSampleRate > 0) && (gyroSampleRate > 0)) { - - if (accelSampleRate != gyroSampleRate) { - _logId = 'u'; //data cannot be synced - return false; - } else { - _logId = 'i'; + public: + IMUDataSyncer() { + uint8_t i; + for (i = 0; i < sizeof(_seq)/sizeof(_seq[0]); i++) { + _seq[i] = -1; + } } - } else if (accelSampleRate > 0) { - _logId = 'a'; - } else if (gyroSampleRate > 0){ - _logId = 'g'; - } else { - _logId = 'n'; - } - return true; - } - - void onSensorDataUpdate(DataXYZ &data, int id) { - _data[id] = &data; - - if ('i' == _logId) { - //we assume id is always 0 (for accel) or 1 (for gyro) - //when _seq[1 - id] is less than 0, it means the other sensor has not received any value yet - if (_seq[1 - id] >= 0) { - _seq[id] = (_seq[id]+1) % 10; - } else { - _seq[id] = 0; //wait for another sensor to generate the 1st sample - } - - if (_seq[id] == _seq[1 - id]) { - //data synced well and ready for sending out - #if DEBUG - mbq_dbg_1(1); - #endif - - #if 0 - //enable this if you want to send the sequence number in each line, - //for highest ODR, we ignore this to save bandwidth - Serial.print(_logId); - Serial.print((char)(_seq[id]+'0')); Serial.print(','); - #endif - //accel data fields - Serial.print(_data[0]->x); Serial.print(','); - Serial.print(_data[0]->y); Serial.print(','); - Serial.print(_data[0]->z); Serial.print(','); - //gyro data fields - Serial.print(_data[1]->x); Serial.print(','); - Serial.print(_data[1]->y); Serial.print(','); - Serial.print(_data[1]->z); Serial.println(); - - #if DEBUG - mbq_dbg_1(0); - #endif - } - } else { - _seq[id] = (_seq[id]+1) % 10; - Serial.print(_logId); - Serial.print(_seq[id]); Serial.print(','); - Serial.print(_data[id]->x); Serial.print(','); - Serial.print(_data[id]->y); Serial.print(','); - Serial.print(_data[id]->z); Serial.println(); - } - } - - protected: - char _logId; - int8_t _seq[2]; - DataXYZ *_data[2]; + //@param outputMetaInfo enable this if you want to send the sequence number in each line of output, + //when outputInBase64 is false, for highest ODR like 1600hz, ignore this to save bandwidth + virtual bool begin(int accelSampleRate, int gyroSampleRate, bool outputInBase64 = false, bool outputMetaInfo = true) { + //int sampleRate = accelSampleRate > gyroSampleRate ? accelSampleRate : gyroSampleRate; + _outputInBase64 = outputInBase64; + _outputMetaInfo = outputMetaInfo; + if ((accelSampleRate > 0) && (gyroSampleRate > 0)) { + if (accelSampleRate != gyroSampleRate) { + //'u' means unaliged data rate + _logId = 'u'; //for simplicity, we do not sync acc and gyro data when the rates are not the same + return false; + } else { + _logId = 'i'; + } + } else if (accelSampleRate > 0) { + _logId = 'a'; + } else if (gyroSampleRate > 0){ + _logId = 'g'; + } else { + _logId = 'n'; //null + } + + return true; + } + + virtual void end() { + } + + void onSensorDataUpdate(SensorDataPacket &data, uint8_t id) { + const uint8_t IDS_ALL = (1<= 0) { + _seq[id] = (_seq[id]+1) % 10; + } else { + _seq[id] = 0; //this is to wait for another sensor to generate the 1st sample + } + + if (_seq[id] == _seq[1 - id]) { + //data synced well and ready for sending out + outputData(IDS_ALL); + } + } else { + //we are only collecting data for a single sensor + _seq[id] = (_seq[id]+1) % 10; + outputData(1<onSensorDataUpdate(_data, _id); - } - - void setData(SensorLongDataPacket &data) {} - - String toString() { - return _data.toString(); - } - - protected: - DataXYZ _data; - uint8_t _id; - IMUDataSyncer *_dataSyncer; + public: + SensorMotion(uint8_t id) : SensorClass(id) { + _id = (id / 10); //accel: 0, gyro: 1, mag: 2 + _dataSyncer = NULL; + } + + void setDataSyncer(IMUDataSyncer &dataSyncer) { + _dataSyncer = &dataSyncer; + } + + void setData(SensorDataPacket &data) { + //DataParser::parse3DVector(data, _data); + _dataSyncer->onSensorDataUpdate(data, _id); + } + + void setData(SensorLongDataPacket &data) {} + + String toString() { + //we are delegating the data parsing to the _dataSyncer + return (""); + } + + protected: + //DataXYZ _data; + uint8_t _id; + IMUDataSyncer *_dataSyncer; }; @@ -137,52 +203,57 @@ SensorMotion accel(1); //sensor id 1: accel raw data passthrough SensorMotion gyro(10); //sensor id 10: gyro raw data passthrough IMUDataSyncer imuDataSyncer; -#define IMU_DATA_RATE 1600 +#define DATA_RATE_ACC 1600 +#define DATA_RATE_GYR 1600 void testSerial() { - while (0) { - Serial.print('*'); - //Serial.println(); - - delay(1000); - } +#if PDEBUG + while (0) { + mbq_dbg_1(1); + Serial.println("0123456789"); + mbq_dbg_1(0); + delay(10); + } +#endif } void setup() { - //Serial.begin(115200); - Serial.begin(1000000); //max br: 1Mbps for nRF52 - while(!Serial); - - BHY2.begin(NICLA_STANDALONE); - - testSerial(); - - SensorConfig cfg = accel.getConfiguration(); - Serial.println(String("range of accel: +/-") + cfg.range + String("g")); - accel.setRange(8); //this sets the range of accel to +/-8g, - cfg = accel.getConfiguration(); - Serial.println(String("range of accel: +/-") + cfg.range + String("g")); - - imuDataSyncer.begin(IMU_DATA_RATE, IMU_DATA_RATE); - accel.setDataSyncer(imuDataSyncer); - gyro.setDataSyncer(imuDataSyncer); - accel.begin(IMU_DATA_RATE); - gyro.begin(IMU_DATA_RATE); + //Serial.begin(115200); + Serial.begin(1000000); //max br: 1Mbps for nRF52 + while(!Serial); + + BHY2.begin(NICLA_STANDALONE); + + testSerial(); + + SensorConfig cfg = accel.getConfiguration(); + Serial.println(String("range of accel: +/-") + cfg.range + String("g")); + accel.setRange(8); //this sets the range of accel to +/-8g, + cfg = accel.getConfiguration(); + Serial.println(String("range of accel: +/-") + cfg.range + String("g")); + + + //imuDataSyncer.begin(DATA_RATE_ACC, DATA_RATE_GYR, false); + imuDataSyncer.begin(DATA_RATE_ACC, DATA_RATE_GYR, true); + accel.setDataSyncer(imuDataSyncer); + gyro.setDataSyncer(imuDataSyncer); + accel.begin(DATA_RATE_ACC); + gyro.begin(DATA_RATE_GYR); } void loop() { - #if DEBUG - mbq_dbg_0(1); - #endif - - BHY2.update(); - - #if DEBUG - mbq_dbg_0(0); - #endif +#if PDEBUG + mbq_dbg_0(1); +#endif + + BHY2.update(); + +#if PDEBUG + mbq_dbg_0(0); +#endif } diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/base64.hpp b/Arduino_BHY2/examples/SyncAndCollectIMUData/base64.hpp new file mode 100644 index 00000000..60b2f9ff --- /dev/null +++ b/Arduino_BHY2/examples/SyncAndCollectIMUData/base64.hpp @@ -0,0 +1,221 @@ +/** + * Base64 encoding and decoding of strings. Uses '+' for 62, '/' for 63, '=' for padding + */ + +#ifndef BASE64_H_INCLUDED +#define BASE64_H_INCLUDED + +/* binary_to_base64: + * Description: + * Converts a single byte from a binary value to the corresponding base64 character + * Parameters: + * v - Byte to convert + * Returns: + * ascii code of base64 character. If byte is >= 64, then there is not corresponding base64 character + * and 255 is returned + */ +unsigned char binary_to_base64(unsigned char v); + +/* base64_to_binary: + * Description: + * Converts a single byte from a base64 character to the corresponding binary value + * Parameters: + * c - Base64 character (as ascii code) + * Returns: + * 6-bit binary value + */ +unsigned char base64_to_binary(unsigned char c); + +/* encode_base64_length: + * Description: + * Calculates length of base64 string needed for a given number of binary bytes + * Parameters: + * input_length - Amount of binary data in bytes + * Returns: + * Number of base64 characters needed to encode input_length bytes of binary data + */ +unsigned int encode_base64_length(unsigned int input_length); + +/* decode_base64_length: + * Description: + * Calculates number of bytes of binary data in a base64 string + * Variant that does not use input_length no longer used within library, retained for API compatibility + * Parameters: + * input - Base64-encoded null-terminated string + * input_length (optional) - Number of bytes to read from input pointer + * Returns: + * Number of bytes of binary data in input + */ +unsigned int decode_base64_length(unsigned char input[]); +unsigned int decode_base64_length(unsigned char input[], unsigned int input_length); + +/* encode_base64: + * Description: + * Converts an array of bytes to a base64 null-terminated string + * Parameters: + * input - Pointer to input data + * input_length - Number of bytes to read from input pointer + * output - Pointer to output string. Null terminator will be added automatically + * Returns: + * Length of encoded string in bytes (not including null terminator) + */ +unsigned int encode_base64(unsigned char input[], unsigned int input_length, unsigned char output[]); + +/* decode_base64: + * Description: + * Converts a base64 null-terminated string to an array of bytes + * Parameters: + * input - Pointer to input string + * input_length (optional) - Number of bytes to read from input pointer + * output - Pointer to output array + * Returns: + * Number of bytes in the decoded binary + */ +unsigned int decode_base64(unsigned char input[], unsigned char output[]); +unsigned int decode_base64(unsigned char input[], unsigned int input_length, unsigned char output[]); + +unsigned char binary_to_base64(unsigned char v) { + // Capital letters - 'A' is ascii 65 and base64 0 + if(v < 26) return v + 'A'; + + // Lowercase letters - 'a' is ascii 97 and base64 26 + if(v < 52) return v + 71; + + // Digits - '0' is ascii 48 and base64 52 + if(v < 62) return v - 4; + + #ifdef BASE64_URL + // '-' is ascii 45 and base64 62 + if(v == 62) return '-'; + #else + // '+' is ascii 43 and base64 62 + if(v == 62) return '+'; + #endif + + #ifdef BASE64_URL + // '_' is ascii 95 and base64 62 + if(v == 63) return '_'; + #else + // '/' is ascii 47 and base64 63 + if(v == 63) return '/'; + #endif + + return 64; +} + +unsigned char base64_to_binary(unsigned char c) { + // Capital letters - 'A' is ascii 65 and base64 0 + if('A' <= c && c <= 'Z') return c - 'A'; + + // Lowercase letters - 'a' is ascii 97 and base64 26 + if('a' <= c && c <= 'z') return c - 71; + + // Digits - '0' is ascii 48 and base64 52 + if('0' <= c && c <= '9') return c + 4; + + #ifdef BASE64_URL + // '-' is ascii 45 and base64 62 + if(c == '-') return 62; + #else + // '+' is ascii 43 and base64 62 + if(c == '+') return 62; + #endif + + #ifdef BASE64_URL + // '_' is ascii 95 and base64 62 + if(c == '_') return 63; + #else + // '/' is ascii 47 and base64 63 + if(c == '/') return 63; + #endif + + return 255; +} + +unsigned int encode_base64_length(unsigned int input_length) { + return (input_length + 2)/3*4; +} + +unsigned int decode_base64_length(unsigned char input[]) { + return decode_base64_length(input, -1); +} + +unsigned int decode_base64_length(unsigned char input[], unsigned int input_length) { + unsigned char *start = input; + + while(base64_to_binary(input[0]) < 64 && (unsigned int) (input - start) < input_length) { + ++input; + } + + input_length = (unsigned int) (input - start); + return input_length/4*3 + (input_length % 4 ? input_length % 4 - 1 : 0); +} + +unsigned int encode_base64(unsigned char input[], unsigned int input_length, unsigned char output[]) { + unsigned int full_sets = input_length/3; + + // While there are still full sets of 24 bits... + for(unsigned int i = 0; i < full_sets; ++i) { + output[0] = binary_to_base64( input[0] >> 2); + output[1] = binary_to_base64((input[0] & 0x03) << 4 | input[1] >> 4); + output[2] = binary_to_base64((input[1] & 0x0F) << 2 | input[2] >> 6); + output[3] = binary_to_base64( input[2] & 0x3F); + + input += 3; + output += 4; + } + + switch(input_length % 3) { + case 0: + output[0] = '\0'; + break; + case 1: + output[0] = binary_to_base64( input[0] >> 2); + output[1] = binary_to_base64((input[0] & 0x03) << 4); + output[2] = '='; + output[3] = '='; + output[4] = '\0'; + break; + case 2: + output[0] = binary_to_base64( input[0] >> 2); + output[1] = binary_to_base64((input[0] & 0x03) << 4 | input[1] >> 4); + output[2] = binary_to_base64((input[1] & 0x0F) << 2); + output[3] = '='; + output[4] = '\0'; + break; + } + + return encode_base64_length(input_length); +} + +unsigned int decode_base64(unsigned char input[], unsigned char output[]) { + return decode_base64(input, -1, output); +} + +unsigned int decode_base64(unsigned char input[], unsigned int input_length, unsigned char output[]) { + unsigned int output_length = decode_base64_length(input, input_length); + + // While there are still full sets of 24 bits... + for(unsigned int i = 2; i < output_length; i += 3) { + output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4; + output[1] = base64_to_binary(input[1]) << 4 | base64_to_binary(input[2]) >> 2; + output[2] = base64_to_binary(input[2]) << 6 | base64_to_binary(input[3]); + + input += 4; + output += 3; + } + + switch(output_length % 3) { + case 1: + output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4; + break; + case 2: + output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4; + output[1] = base64_to_binary(input[1]) << 4 | base64_to_binary(input[2]) >> 2; + break; + } + + return output_length; +} + +#endif // ifndef From 5ed938afd79a596fd63a26d2d4f08a4553d13d35 Mon Sep 17 00:00:00 2001 From: zg guo Date: Sat, 22 Oct 2022 22:35:05 -0700 Subject: [PATCH 3/4] add tools which could help with pre-processing of the data collected over USB serial --- .../SyncAndCollectIMUData/tools/README.md | 31 ++++++ .../tools/check_for_data_loss.py | 73 +++++++++++++ .../tools/check_for_data_loss.sh | 63 +++++++++++ .../tools/process_nicla_bhy2_log_base64.py | 102 ++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 Arduino_BHY2/examples/SyncAndCollectIMUData/tools/README.md create mode 100755 Arduino_BHY2/examples/SyncAndCollectIMUData/tools/check_for_data_loss.py create mode 100755 Arduino_BHY2/examples/SyncAndCollectIMUData/tools/check_for_data_loss.sh create mode 100755 Arduino_BHY2/examples/SyncAndCollectIMUData/tools/process_nicla_bhy2_log_base64.py diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/README.md b/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/README.md new file mode 100644 index 00000000..13b5e3a5 --- /dev/null +++ b/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/README.md @@ -0,0 +1,31 @@ +# process_nicla_bhy2_log_base64.py +This script is used to convert the log encoded in base64 to ascii +## Usage +``` +./process_nicla_bhy2_log_base64.py [log_file_name] +``` +## Example +./process_nicla_bhy2_log_base64.py log_nicla_bhy2.txt + + +# check_for_data_loss.sh +This script is used to check for any potential data loss during the transfer, +and it reports some errors if it does find any data loss + +## Usage +``` +./check_for_data_loss.sh [OPTION] [log_file_name] +``` + +## Example +- Example 1 + ``` + ./check_for_data_loss.sh -b ./minicom.log + ``` + The above command check for the data loss using the log "./minicom.log" which is base on base64 encoding +- Example 2 + ``` + ./check_for_data_loss.sh -a ./minicom.log + ``` + The above command check for the data loss using the log "./minicom.log" which is base on ascii encoding + diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/check_for_data_loss.py b/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/check_for_data_loss.py new file mode 100755 index 00000000..982d2dd9 --- /dev/null +++ b/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/check_for_data_loss.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +# this script resamples the data from the log to 1/60hz + +import sys +import time +import datetime +import pandas as pd +import math + + +#DEBUG = True +DEBUG = False +SEP_COLUMN = ',' + +LINE_TO_SKIP = 500 + +DOWNSAMPLE_FACTOR=1 + +def PDBG(*args): + if DEBUG: + print("DEBUG:", *args, file=sys.stderr) + + +PDBG('Number of arguments:', len(sys.argv)) + +if (len(sys.argv) < 2): + raise BaseException("missing argument") + +filename_in = sys.argv[1] +file_out = None + +if (len(sys.argv) > 2): + filename_out = sys.argv[2] + file_out = open(filename_out, 'w') + sys.stdout = file_out + + +line_cnt = 1 #first row is the header +df_in = pd.read_csv(filename_in, sep=SEP_COLUMN) + +seq_last = None + + +for index, row in df_in.iterrows(): + line_cnt += 1 + if (line_cnt <= LINE_TO_SKIP): + continue + + seq = row['seq'] + if (seq_last is not None): + try: + delta = seq - seq_last + if (seq < seq_last): + delta += 10 + if (delta != 1): + if (line_cnt < len(df_in.index)): + print("error: line: ", line_cnt, " has data missing, delta:", delta, "seq:", seq) + else: + PDBG("last line: ignored") + seq_last = seq + except: + if (line_cnt < len(df_in.index)): + print("error: line: ", line_cnt, " has data missing") + else: + PDBG("last line: ignored") + pass + else: + PDBG("first row") + seq_last = seq + + +if file_out is not None: + file_out.close() diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/check_for_data_loss.sh b/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/check_for_data_loss.sh new file mode 100755 index 00000000..c313492a --- /dev/null +++ b/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/check_for_data_loss.sh @@ -0,0 +1,63 @@ +#!/bin/sh + + +log_encoding_is_base64=false + +if [ ":""$1" = ":-b" ] ; then + log_encoding_is_base64=true + echo "log is using base64 encoding" +elif [ ":""$1" = ":-a" ] ; then + log_encoding_is_base64=false + echo "log is using ascii encoding" +else + echo "usage: ./check_for_data_loss.sh [OPTION] [log_filename] [info_included_in_data]" + echo "\t[OPTION]:" + echo "\t\t" "-a" + echo "\t\t" "\t:log use ascii encoding" + echo "\t\t" "-b" + echo "\t\t" "\t:log use base64 encoding" + echo "\t[info_included_in_data]:" + echo "\t\t" '"accel" or "accel+meta"' + echo "\t\t" '"gyro" or "gyro+meta"' + echo "\t\t" '"accel+gyro" or "accel+gyro+meta"' + + + echo "\texample: ./check_for_data_loss.sh -b minicom.cap accel+gyro+meta" + return +fi + +if [ ":""$2" = ":" ] ; then + log_file="./minicom.cap" +else + log_file="$2" +fi + +if [ ":""$3" = ":" ] ; then + info_included_in_data="accel+gyro+meta" +else + info_included_in_data="$3" +fi + + +tmp_file="./tmp.csv" +log_file_cp="${log_file}.cp" +log_file_in="${log_file_cp}.tmp" + +echo "log_file:$log_file" + + +if [ $log_encoding_is_base64 = true ] ; then + cp $log_file $log_file_cp + ./process_nicla_bhy2_log_base64.py $log_file_cp $info_included_in_data > $log_file_in +else + cp $log_file $log_file_in +fi + +echo "log_id,seq,ax,ay,az,gx,gy,gz" > $tmp_file + +sed 's/.*\([a-zA-Z]\)\([0-9]\)/\1,\2/g' $log_file_in >> $tmp_file +./check_for_data_loss.py $tmp_file + +rm -f $tmp_file +rm -f $log_file_cp +rm -f $log_file_in diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/process_nicla_bhy2_log_base64.py b/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/process_nicla_bhy2_log_base64.py new file mode 100755 index 00000000..26c1bf1f --- /dev/null +++ b/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/process_nicla_bhy2_log_base64.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +import math +import base64 +import struct +import sys + +#configurations +#DEBUG = True +DEBUG = False +lines_to_ignore = 500 + +# the following should be set according to the fimrware settings on the Nicla Senes ME firmware/sketch +data_include_acc = False +data_include_gyr = False +data_include_meta_info = False + + +if (len(sys.argv) > 1): + log_file_name = sys.argv[1] +else: + log_file_name = 'log_nicla_bhy2.txt' + +if (len(sys.argv) > 2): + info_included_in_data = sys.argv[2] + if "accel" in info_included_in_data: + data_include_acc = True + if DEBUG: + print("accel data included") + if "gyro" in info_included_in_data: + data_include_gyr = True + if DEBUG: + print("gyro data included") + if "meta" in info_included_in_data: + data_include_meta_info= True + if DEBUG: + print("meta data included") + +#working variables +file_log = open(log_file_name, 'r') +lines = file_log.readlines() + +lineCnt = 0 +record_len = 0 +record_len_before_encoding = 0 + +if data_include_meta_info: + record_len_before_encoding += 2 + +if data_include_acc: + record_len_before_encoding += 6 + +if data_include_gyr: + record_len_before_encoding += 6 + + +record_len = int(math.ceil(record_len_before_encoding / 3)) * 4 +if DEBUG: + print("record_len:", record_len) + + +DEBUG = False +# Strips the newline character +for line in lines: + lineCnt += 1 + + if (lineCnt <= lines_to_ignore): + continue + + line = line.strip() + len_line = len(line) + + if (len_line < record_len) or (line[len_line - 1] != '='): + if (lineCnt < len(lines)): + print("line:", lineCnt, " skipped") + else: + if DEBUG: + print("last line:", lineCnt, " skipped") + continue + + line = line[-record_len:] + try: + data_imu = base64.b64decode(line) + if DEBUG: + print(data_imu) + print(len(data_imu)) + + try: + if (data_include_acc and data_include_gyr): + (log_id, seq, ax,ay,az,gx,gy,gz) = struct.unpack(" Date: Mon, 14 Nov 2022 23:35:04 -0800 Subject: [PATCH 4/4] improved documentation README for the sketch and the tools --- .../examples/SyncAndCollectIMUData/README.md | 19 ++++++++++++++ .../SyncAndCollectIMUData/tools/README.md | 26 +++++++++++++------ 2 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 Arduino_BHY2/examples/SyncAndCollectIMUData/README.md diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/README.md b/Arduino_BHY2/examples/SyncAndCollectIMUData/README.md new file mode 100644 index 00000000..59320d1f --- /dev/null +++ b/Arduino_BHY2/examples/SyncAndCollectIMUData/README.md @@ -0,0 +1,19 @@ +# Overview +This example shows how to stream sensor data with very high data rate (up to 1600hz for both accel and gyro) through the USB Serial interface to the host (PC) + +#prerequisite +## Host Side +To stream both accel and gyro data at high frequency (e.g.: 800hz or above), +the host PC needs to be able to support USB serial baud rate of 1Mbps or at least 921600bps which are widely available for regular PCs, +however, it is observed that on Mac OS based devices, the baud rate seems to be capped at 230400bps. + +If only one sensor needs to be streamed, the clock rate on the host side could be relaxed by about a half. + +## Device Side +The default device FW for the BHI260AP device supports sensor data output rate of up to 400hz, to support higher rates, the firmware needs to be updated, +and for the convenience of the users, a stock firmware ("NiclaSenseME-nobsx-1600hz-IMU-passthrough-flash.fw") for this purpose has been provided at the same +folder with this README, please refer to the example sketch BHYFirmwareUpdate within the Arduino_BHY2 library for the steps of updating the BHI260AP firmware. + +# The "tools" Folder +For reliable data transfer at high data rates, the data is encoded in base64 format, and to help convert the data (captured at the host side) back to its original format, some helper tools have been provided for the users' convenience. +Please refer to the README.md under the "tools" folder for more details. diff --git a/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/README.md b/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/README.md index 13b5e3a5..d2cd8245 100644 --- a/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/README.md +++ b/Arduino_BHY2/examples/SyncAndCollectIMUData/tools/README.md @@ -1,23 +1,33 @@ -# process_nicla_bhy2_log_base64.py +# Usage of the scripts +## process_nicla_bhy2_log_base64.py This script is used to convert the log encoded in base64 to ascii -## Usage +### Usage ``` -./process_nicla_bhy2_log_base64.py [log_file_name] +./process_nicla_bhy2_log_base64.py [log_file_name] [options] ``` -## Example -./process_nicla_bhy2_log_base64.py log_nicla_bhy2.txt +The [log_file_name] is the log captured on the host side from the USB serial port. +[options] tells what kind of data is embedded in the base64-encoded data. +possible options are: + - "accel" + - "gyro" + - "meta" + - "accel+meta" + - "gyro+meta" + - "accel+gyro+meta" +### Example +./process_nicla_bhy2_log_base64.py log_nicla_bhy2.txt "accel+gyro+meta" -# check_for_data_loss.sh +## check_for_data_loss.sh This script is used to check for any potential data loss during the transfer, and it reports some errors if it does find any data loss -## Usage +### Usage ``` ./check_for_data_loss.sh [OPTION] [log_file_name] ``` -## Example +### Example - Example 1 ``` ./check_for_data_loss.sh -b ./minicom.log