├── examples ├── .DS_Store ├── PhysicsLabFirmware │ ├── .DS_Store │ └── PhysicsLabFirmware.ino └── Nano33BLESenseFirmware │ └── Nano33BLESenseFirmware.ino ├── library.properties ├── README.adoc ├── src ├── ArduinoScienceJournal.h ├── INA226.h └── INA226.cpp └── extras ├── BLE_spec BLE Sense Firmware.txt └── BLE_spec MKR Science Kit Firmware.txt /examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/njh/Arduino_ScienceJournal/master/examples/.DS_Store -------------------------------------------------------------------------------- /examples/PhysicsLabFirmware/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/njh/Arduino_ScienceJournal/master/examples/PhysicsLabFirmware/.DS_Store -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Arduino_ScienceJournal 2 | version=1.0.0 3 | author=Arduino 4 | maintainer=Arduino 5 | sentence=Firmware for the Physics Lab kit and the Arduino Nano 33 BLE Sense. 6 | paragraph=This library depends on the ArduinoBLE and MKRIMU libraries. 7 | category=Communication 8 | url=https://github.com/arduino-libraries/ArduinoScienceJournal 9 | architectures=samd,nrf52,mbed 10 | includes=ArduinoScienceJournal.h 11 | depends=Adafruit LSM9DS0 Library,Adafruit Zero PDM Library,Arduino_APDS9960,Arduino_HTS221,Arduino_LPS22HB,Arduino_LSM9DS1,ArduinoBLE 12 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Arduino_ScienceJournal Library for Arduino = 2 | 3 | Firmware for the Physics Lab kit and the Arduino Nano 33 BLE Sense. 4 | 5 | == License == 6 | 7 | Copyright (c) 2020 Arduino SA. All rights reserved. 8 | 9 | This library is free software; you can redistribute it and/or 10 | modify it under the terms of the GNU Lesser General Public 11 | License as published by the Free Software Foundation; either 12 | version 2.1 of the License, or (at your option) any later version. 13 | 14 | This library is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | Lesser General Public License for more details. 18 | 19 | You should have received a copy of the GNU Lesser General Public 20 | License along with this library; if not, write to the Free Software 21 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | -------------------------------------------------------------------------------- /src/ArduinoScienceJournal.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhysicsLabFirmware library. 3 | Copyright (c) 2019 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef _ARDUINO_SCIENCE_JOURNAL_H_ 21 | #define _ARDUINO_SCIENCE_JOURNAL_H_ 22 | 23 | // Nothing here. Everything is in the example sketches! 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/INA226.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhysicsLabFirmware library. 3 | Copyright (c) 2019 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef _INA226_H_ 21 | #define _INA226_H_ 22 | 23 | #include 24 | #include 25 | 26 | class INA226Class { 27 | public: 28 | INA226Class(TwoWire& wire); 29 | virtual ~INA226Class(); 30 | 31 | int begin(uint8_t address, float shuntResistance = 0.0002); 32 | void end(); 33 | 34 | float readCurrent(); 35 | float readBusVoltage(); 36 | 37 | private: 38 | long readRegister(uint8_t address); 39 | int writeRegister(uint8_t address, uint16_t value); 40 | 41 | private: 42 | TwoWire* _wire; 43 | uint8_t _i2cAddress; 44 | }; 45 | 46 | extern INA226Class INA226; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /extras/BLE_spec BLE Sense Firmware.txt: -------------------------------------------------------------------------------- 1 | BLE Sense - BLE specifications.txt 2 | ================================== 3 | 4 | GAP (Adversisement) 5 | ------------------- 6 | Local name: BLESense - 7 | Serivice UUID: 555a0002-0000-467a-9538-01f0652c74e8 8 | 9 | 10 | GATT 11 | ---- 12 | 13 | Service 14 | ~~~~~~~ 15 | UUID: 555a0002-0000-467a-9538-01f0652c74e8 16 | 17 | 18 | Version Characteristic 19 | ~~~~~~~~~~~~~~~~~~~~~~ 20 | UUID: 555a0002-0001-467a-9538-01f0652c74e8 21 | Properties: read 22 | Value size: 4 bytes 23 | Data format: 32-bit unsigned integer (little endian) 24 | Description: Version of firmware (actual version is 1) 25 | 26 | 27 | Acceleration Characteristic 28 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 29 | UUID: 555a0002-0011-467a-9538-01f0652c74e8 30 | Properties: notify 31 | Value size: 12 bytes 32 | Data format: Array of 3 x 32-bit IEEE floats (little endian) 33 | Description: X, Y, Z acceleration values in G's 34 | 35 | Gyroscope Characteristic 36 | ~~~~~~~~~~~~~~~~~~~~~~~~ 37 | UUID: 555a0002-0012-467a-9538-01f0652c74e8 38 | Properties: notify 39 | Value size: 12 bytes 40 | Data format: Array of 3 x 32-bit IEEE floats (little endian) 41 | Description: X, Y, Z gyroscope values in degrees per second 42 | 43 | 44 | Magnetic Field Characteristic 45 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 46 | UUID: 555a0002-0013-467a-9538-01f0652c74e8 47 | Properties: notify 48 | Value size: 12 bytes 49 | Data format: Array of 3 x 32-bit IEEE floats (little endian) 50 | Description: X, Y, Z magnetic fields values in uT 51 | 52 | 53 | Temperature Characteristic 54 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 55 | UUID: 555a0002-0014-467a-9538-01f0652c74e8 56 | Properties: read 57 | Value size: 4 bytes 58 | Data format: 32-bit IEEE floats (little endian) 59 | Description: Temperature sensor value Celsius 60 | 61 | 62 | Pressure Characteristic 63 | ~~~~~~~~~~~~~~~~~~~~~~~ 64 | UUID: 555a0002-0015-467a-9538-01f0652c74e8 65 | Properties: read 66 | Value size: 4 bytes 67 | Data format: 32-bit IEEE floats (little endian) 68 | Description: Pressure sensor value in kPA 69 | 70 | 71 | Humidity Characteristic 72 | ~~~~~~~~~~~~~~~~~~~~~~~ 73 | UUID: 555a0002-0016-467a-9538-01f0652c74e8 74 | Properties: read 75 | Value size: 4 bytes 76 | Data format: 32-bit IEEE floats (little endian) 77 | Description: Humidity sensor value % 78 | 79 | 80 | Proximity Characteristic 81 | ~~~~~~~~~~~~~~~~~~~~~~~~ 82 | UUID: 555a0002-0017-467a-9538-01f0652c74e8 83 | Properties: notify 84 | Value size: 4 bytes 85 | Data format: 32-bit unsigned integer (little endian) 86 | Description: Proximity sensor value, 0 => close, 255 far 87 | 88 | 89 | Color Characteristic 90 | ~~~~~~~~~~~~~~~~~~~~ 91 | UUID: 555a0002-0018-467a-9538-01f0652c74e8 92 | Properties: notify 93 | Value size: 16 bytes 94 | Data format: array of 4 x 32-bit integers (little endian) 95 | Description: RGB + Illuminance colour sensor values, range 0 - 4097 96 | -------------------------------------------------------------------------------- /src/INA226.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhysicsLabFirmware library. 3 | Copyright (c) 2019 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include "INA226.h" 21 | 22 | #define INA226_BUS_VOLTAGE_REG 0x02 23 | #define INA226_CURRENT_REG 0x04 24 | #define INA226_CALIBRATION_REG 0x05 25 | 26 | INA226Class::INA226Class(TwoWire& wire) : 27 | _wire(&wire) 28 | { 29 | } 30 | 31 | INA226Class::~INA226Class() 32 | { 33 | } 34 | 35 | int INA226Class::begin(uint8_t address, float shuntResistance) 36 | { 37 | _i2cAddress = address; 38 | 39 | // for 1 mA/bit 40 | uint16_t calibration = (0.00512 / (0.001 * shuntResistance)); 41 | 42 | _wire->begin(); 43 | 44 | // force 45 | if (!writeRegister(INA226_CALIBRATION_REG, calibration)) { 46 | end(); 47 | 48 | return 0; 49 | } 50 | 51 | return 1; 52 | } 53 | 54 | void INA226Class::end() 55 | { 56 | _wire->end(); 57 | } 58 | 59 | float INA226Class::readCurrent() 60 | { 61 | long value = readRegister(INA226_CURRENT_REG); 62 | 63 | if (value == NAN) { 64 | return -1; 65 | } 66 | 67 | return (((int16_t)value) / 1000.0); 68 | } 69 | 70 | float INA226Class::readBusVoltage() 71 | { 72 | long value = readRegister(INA226_BUS_VOLTAGE_REG); 73 | 74 | if (value == -1) { 75 | return NAN; 76 | } 77 | 78 | return (value * 0.00125); 79 | } 80 | 81 | long INA226Class::readRegister(uint8_t address) 82 | { 83 | _wire->beginTransmission(_i2cAddress); 84 | _wire->write(address); 85 | if (_wire->endTransmission() != 0) { 86 | return -1; 87 | } 88 | 89 | if (_wire->requestFrom(_i2cAddress, 2) != 2) { 90 | return -1; 91 | } 92 | 93 | return ((_wire->read() << 8) | _wire->read()); 94 | } 95 | 96 | int INA226Class::writeRegister(uint8_t address, uint16_t value) 97 | { 98 | _wire->beginTransmission(_i2cAddress); 99 | _wire->write(address); 100 | _wire->write(value >> 8); 101 | _wire->write(value & 0xff); 102 | if (_wire->endTransmission() != 0) { 103 | return 0; 104 | } 105 | 106 | return 1; 107 | } 108 | 109 | INA226Class INA226(Wire); 110 | -------------------------------------------------------------------------------- /extras/BLE_spec MKR Science Kit Firmware.txt: -------------------------------------------------------------------------------- 1 | MKR Science Kit Firmware - BLE specifications.txt 2 | ================================================= 3 | 4 | 5 | GAP (Adversisement) 6 | ------------------- 7 | Local name: MKRSci 8 | Serivice UUID: 555a0001-0000-467a-9538-01f0652c74e8 9 | 10 | 11 | GATT 12 | ---- 13 | 14 | Service 15 | ~~~~~~~ 16 | 17 | UUID: 555a0001-0000-467a-9538-01f0652c74e8 18 | 19 | 20 | Version Characteristic 21 | ~~~~~~~~~~~~~~~~~~~~~~ 22 | 23 | UUID: 555a0001-0001-467a-9538-01f0652c74e8 24 | Properties: read 25 | Value size: 4 bytes 26 | Data format: 32-bit unsigned integer (little endian) 27 | Description: Version of firmware 28 | 29 | LED Characteristic 30 | ~~~~~~~~~~~~~~~~~~ 31 | 32 | UUID: 555a0001-1001-467a-9538-01f0652c74e8 33 | Properties: read, write 34 | Value size: 1 byte 35 | Data format: 8-bit unsigned integer 36 | Description: LED brightness, 0 = off, 255 = full, 1 - 254 brightness 37 | 38 | Input 1 Characteristic 39 | ~~~~~~~~~~~~~~~~~~~~~~ 40 | 41 | UUID: 555a0001-2001-467a-9538-01f0652c74e8 42 | Properties: notify 43 | Value size: 2 bytes 44 | Data format: 16-bit unsigned integer (little endian) 45 | Description: Input 1 analog value (0 - 1023), if subscribed notification sent every 100 ms 46 | 47 | Input 2 Characteristic 48 | ~~~~~~~~~~~~~~~~~~~~~~ 49 | 50 | UUID: 555a0001-2002-467a-9538-01f0652c74e8 51 | Properties: notify 52 | Value size: 2 bytes 53 | Data format: 16-bit unsigned integer (little endian) 54 | Description: Input 2 analog value (0 - 1023), if subscribed notification sent every 100 ms 55 | 56 | Input 3 Characteristic 57 | ~~~~~~~~~~~~~~~~~~~~~~ 58 | 59 | UUID: 555a0001-2003-467a-9538-01f0652c74e8 60 | Properties: notify 61 | Value size: 2 bytes 62 | Data format: 16-bit unsigned integer (little endian) 63 | Description: Input 3 analog value (0 - 1023), if subscribed notification sent every 100 ms 64 | 65 | Output 1 Characteristic 66 | ~~~~~~~~~~~~~~~~~~~~~~~ 67 | 68 | UUID: 555a0001-3001-467a-9538-01f0652c74e8 69 | Properties: read, write 70 | Value size: 1 byte 71 | Data format: 8-bit unsigned integer 72 | Description: Analog write value of Output 1 73 | 74 | Output 2 Characteristic 75 | ~~~~~~~~~~~~~~~~~~~~~~~ 76 | 77 | UUID: 555a0001-3002-467a-9538-01f0652c74e8 78 | Properties: read, write 79 | Value size: 1 byte 80 | Data format: 8-bit unsigned integer 81 | Description: Analog write value of Output 2 82 | 83 | Voltage Characteristic 84 | ~~~~~~~~~~~~~~~~~~~~~~ 85 | 86 | UUID: 555a0001-4001-467a-9538-01f0652c74e8 87 | Properties: notify 88 | Value size: 4 bytes 89 | Data format: 32-bit IEEE float (little endian) 90 | Description: Voltage input value in volts, if subscribed notification sent every 100 ms 91 | 92 | Current Characteristic 93 | ~~~~~~~~~~~~~~~~~~~~~~ 94 | 95 | UUID: 555a0001-4002-467a-9538-01f0652c74e8 96 | Properties: notify 97 | Value size: 4 bytes 98 | Data format: 32-bit IEEE float (little endian) 99 | Description: Current input value in amps, if subscribed notification sent every 100 ms 100 | 101 | Resistance Characteristic 102 | ~~~~~~~~~~~~~~~~~~~~~~~~ 103 | 104 | UUID: 555a0001-4003-467a-9538-01f0652c74e8 105 | Properties: notify 106 | Value size: 4 bytes 107 | Data format: 32-bit IEEE float (little endian) 108 | Description: Resistance input value in ohms, if subscribed notification sent every 100 ms 109 | 110 | Acceleration Characteristic 111 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 112 | 113 | UUID: 555a0001-5001-467a-9538-01f0652c74e8 114 | Properties: notify 115 | Value size: 12 bytes 116 | Data format: Array of 3 x 32-bit IEEE floats (little endian) 117 | Description: X, Y, Z acceleration values in G's, if subscribed notification sent every 10 ms 118 | 119 | Gyroscope Characteristic 120 | ~~~~~~~~~~~~~~~~~~~~~~~~ 121 | 122 | UUID: 555a0001-5002-467a-9538-01f0652c74e8 123 | Properties: notify 124 | Value size: 12 bytes 125 | Data format: Array of 3 x 32-bit IEEE floats (little endian) 126 | Description: X, Y, Z gyroscope values in degrees per second, if subscribed notification sent every 10 ms 127 | 128 | Magnetic Field Characteristic 129 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 130 | 131 | UUID: 555a0001-5003-467a-9538-01f0652c74e8 132 | Properties: notify 133 | Value size: 12 bytes 134 | Data format: Array of 3 x 32-bit IEEE floats (little endian) 135 | Description: X, Y, Z magnetic fields values in uT, if subscribed notification sent every 10 ms 136 | -------------------------------------------------------------------------------- /examples/Nano33BLESenseFirmware/Nano33BLESenseFirmware.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | const int VERSION = 0x00000001; 12 | const float TEMPERATURE_CALIBRATION = -5.0; 13 | 14 | #define SCIENCE_KIT_UUID(val) ("555a0002-" val "-467a-9538-01f0652c74e8") 15 | 16 | //#define DEBUG 0 17 | 18 | BLEService service (SCIENCE_KIT_UUID("0000")); 19 | BLEUnsignedIntCharacteristic versionCharacteristic (SCIENCE_KIT_UUID("0001"), BLERead); 20 | BLECharacteristic accelerationCharacteristic (SCIENCE_KIT_UUID("0011"), BLENotify, 3 * sizeof(float)); 21 | BLECharacteristic gyroscopeCharacteristic (SCIENCE_KIT_UUID("0012"), BLENotify, 3 * sizeof(float)); 22 | BLECharacteristic magneticFieldCharacteristic(SCIENCE_KIT_UUID("0013"), BLENotify, 3 * sizeof(float)); 23 | BLEFloatCharacteristic temperatureCharacteristic (SCIENCE_KIT_UUID("0014"), BLENotify); 24 | BLEFloatCharacteristic pressureCharacteristic (SCIENCE_KIT_UUID("0015"), BLENotify); 25 | BLEFloatCharacteristic humidityCharacteristic (SCIENCE_KIT_UUID("0016"), BLENotify); 26 | BLEUnsignedIntCharacteristic proximityCharacteristic (SCIENCE_KIT_UUID("0017"), BLENotify); 27 | BLECharacteristic colorCharacteristic (SCIENCE_KIT_UUID("0018"), BLENotify, 4 * sizeof(int)); 28 | BLEUnsignedShortCharacteristic soundPressureCharacteristic(SCIENCE_KIT_UUID("0019"), BLENotify); 29 | 30 | short soundSampleBuffer[256]; 31 | 32 | void onPDMdata() { 33 | // query the number of bytes available 34 | int bytesAvailable = PDM.available(); 35 | 36 | // read into the sample buffer 37 | PDM.read(soundSampleBuffer, bytesAvailable); 38 | } 39 | 40 | uint16_t getSoundAverage() { 41 | uint32_t avg = 0; 42 | for (int i = 0; i < sizeof(soundSampleBuffer)/sizeof(soundSampleBuffer[0]); i++) { 43 | avg += soundSampleBuffer[i]*soundSampleBuffer[i]; 44 | } 45 | return sqrt(avg); 46 | } 47 | 48 | // String to calculate the local and device name 49 | String name; 50 | unsigned long lastNotify = 0; 51 | 52 | void printSerialMsg(const char * msg) { 53 | #ifdef DEBUG 54 | if (Serial) { 55 | Serial.println(msg); 56 | } 57 | #endif 58 | } 59 | 60 | void blinkLoop() { 61 | while (1) { 62 | digitalWrite(LED_BUILTIN, HIGH); 63 | delay(500); 64 | digitalWrite(LED_BUILTIN, LOW); 65 | delay(500); 66 | } 67 | } 68 | 69 | void setup() { 70 | #ifdef DEBUG 71 | Serial.begin(9600); 72 | while (!Serial); 73 | Serial.println("Started"); 74 | #endif 75 | 76 | delay(2000); 77 | 78 | if (!APDS.begin()) { 79 | printSerialMsg("Failed to initialized APDS!"); 80 | blinkLoop(); 81 | } 82 | 83 | if (!HTS.begin()) { 84 | printSerialMsg("Failed to initialized HTS!"); 85 | blinkLoop(); 86 | } 87 | 88 | if (!BARO.begin()) { 89 | printSerialMsg("Failed to initialized BARO!"); 90 | blinkLoop(); 91 | } 92 | 93 | if (!IMU.begin()) { 94 | printSerialMsg("Failed to initialized IMU!"); 95 | blinkLoop(); 96 | } 97 | 98 | PDM.onReceive(onPDMdata); 99 | if (!PDM.begin(1, 16000)) { 100 | printSerialMsg("Failed to start PDM!"); 101 | blinkLoop(); 102 | } 103 | 104 | if (!BLE.begin()) { 105 | printSerialMsg("Failed to initialized BLE!"); 106 | blinkLoop(); 107 | } 108 | 109 | String address = BLE.address(); 110 | #ifdef DEBUG 111 | if (Serial) { 112 | Serial.print("address = "); 113 | Serial.println(address); 114 | } 115 | #endif 116 | address.toUpperCase(); 117 | 118 | name = "BLE Sense - "; 119 | name += address[address.length() - 5]; 120 | name += address[address.length() - 4]; 121 | name += address[address.length() - 2]; 122 | name += address[address.length() - 1]; 123 | 124 | #ifdef DEBUG 125 | if (Serial) { 126 | Serial.print("name = "); 127 | Serial.println(name); 128 | } 129 | #endif 130 | 131 | BLE.setLocalName(name.c_str()); 132 | BLE.setDeviceName(name.c_str()); 133 | BLE.setAdvertisedService(service); 134 | 135 | service.addCharacteristic(versionCharacteristic); 136 | service.addCharacteristic(accelerationCharacteristic); 137 | service.addCharacteristic(gyroscopeCharacteristic); 138 | service.addCharacteristic(magneticFieldCharacteristic); 139 | service.addCharacteristic(temperatureCharacteristic); 140 | service.addCharacteristic(pressureCharacteristic); 141 | service.addCharacteristic(humidityCharacteristic); 142 | service.addCharacteristic(proximityCharacteristic); 143 | service.addCharacteristic(colorCharacteristic); 144 | service.addCharacteristic(soundPressureCharacteristic); 145 | 146 | versionCharacteristic.setValue(VERSION); 147 | 148 | BLE.addService(service); 149 | BLE.advertise(); 150 | 151 | digitalWrite(LED_BUILTIN, HIGH); 152 | } 153 | 154 | void loop() { 155 | while (BLE.connected()) { 156 | unsigned long now = millis(); 157 | if (abs((long) now - (long) lastNotify) >= 100) { 158 | updateSubscribedCharacteristics(); 159 | lastNotify = now; 160 | } 161 | } 162 | } 163 | 164 | void updateSubscribedCharacteristics() { 165 | if (accelerationCharacteristic.subscribed()) { 166 | float acceleration[3]; 167 | if (IMU.accelerationAvailable() && IMU.readAcceleration(acceleration[0], acceleration[1], acceleration[2])) { 168 | accelerationCharacteristic.writeValue((byte*)acceleration, sizeof(acceleration)); 169 | } 170 | } 171 | if (gyroscopeCharacteristic.subscribed()) { 172 | float gyroscope[3]; 173 | if (IMU.gyroscopeAvailable() && IMU.readGyroscope(gyroscope[0], gyroscope[1], gyroscope[2])) { 174 | gyroscopeCharacteristic.writeValue((byte*)gyroscope, sizeof(gyroscope)); 175 | } 176 | } 177 | 178 | if (magneticFieldCharacteristic.subscribed()) { 179 | float magneticField[3]; 180 | if (IMU.magneticFieldAvailable() && IMU.readMagneticField(magneticField[0], magneticField[1], magneticField[2])) { 181 | magneticFieldCharacteristic.writeValue((byte*)magneticField, sizeof(magneticField)); 182 | } 183 | } 184 | if (soundPressureCharacteristic.subscribed()) { 185 | uint16_t sound = getSoundAverage(); 186 | soundPressureCharacteristic.writeValue(sound); 187 | } 188 | if (proximityCharacteristic.subscribed() && APDS.proximityAvailable()) { 189 | uint32_t proximity = APDS.readProximity(); 190 | proximityCharacteristic.writeValue(proximity); 191 | } 192 | if (colorCharacteristic.subscribed() && APDS.colorAvailable()) { 193 | int color[4]; 194 | APDS.readColor(color[0], color[1], color[2], color[3]); 195 | colorCharacteristic.writeValue((byte*)color, sizeof(color)); 196 | } 197 | bool doTemperature = temperatureCharacteristic.subscribed(); 198 | bool doHumidity = humidityCharacteristic.subscribed(); 199 | if (doTemperature || doHumidity) { 200 | float temperature = HTS.readTemperature(); 201 | float temperatureCalibrated = temperature + TEMPERATURE_CALIBRATION; 202 | if (doTemperature) { 203 | temperatureCharacteristic.writeValue(temperatureCalibrated); 204 | } 205 | if (doHumidity) { 206 | float humidity = HTS.readHumidity(); 207 | float dp = temperature - ((100.0 - humidity) / 5.0); 208 | float humidityCalibrated = 100.0 - (5.0 * (temperatureCalibrated - dp)); 209 | humidityCharacteristic.writeValue(humidityCalibrated); 210 | } 211 | } 212 | if (pressureCharacteristic.subscribed()) { 213 | float pressure = BARO.readPressure(); 214 | pressureCharacteristic.writeValue(pressure); 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /examples/PhysicsLabFirmware/PhysicsLabFirmware.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the PhysicsLabFirmware library. 3 | Copyright (c) 2019 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include // click here to install the library: http://librarymanager#ArduinoBLE 21 | #include // click here to install the library: http://librarymanager#Adafruit&LSM9DS1 22 | #include // click here to install the library: http://librarymanager#Adafruit&unified&Sensor&abstraction 23 | 24 | #include "INA226.h" 25 | 26 | #define SCIENCE_KIT_UUID(val) ("555a0001-" val "-467a-9538-01f0652c74e8") 27 | 28 | BLEService service (SCIENCE_KIT_UUID("0000")); 29 | BLEUnsignedIntCharacteristic versionCharacteristic (SCIENCE_KIT_UUID("0001"), BLERead); 30 | BLEByteCharacteristic ledCharacteristic (SCIENCE_KIT_UUID("1001"), BLERead | BLEWrite); 31 | BLEUnsignedShortCharacteristic input1Characteristic (SCIENCE_KIT_UUID("2001"), BLENotify); 32 | BLEUnsignedShortCharacteristic input2Characteristic (SCIENCE_KIT_UUID("2002"), BLENotify); 33 | BLEUnsignedShortCharacteristic input3Characteristic (SCIENCE_KIT_UUID("2003"), BLENotify); 34 | BLEByteCharacteristic ouput1Characteristic (SCIENCE_KIT_UUID("3001"), BLERead | BLEWrite); 35 | BLEByteCharacteristic ouput2Characteristic (SCIENCE_KIT_UUID("3002"), BLERead | BLEWrite); 36 | BLEFloatCharacteristic voltageCharacteristic (SCIENCE_KIT_UUID("4001"), BLENotify); 37 | BLEFloatCharacteristic currentCharacteristic (SCIENCE_KIT_UUID("4002"), BLENotify); 38 | BLEFloatCharacteristic resistanceCharacteristic (SCIENCE_KIT_UUID("4003"), BLENotify); 39 | BLECharacteristic accelerationCharacteristic (SCIENCE_KIT_UUID("5001"), BLENotify, 3 * sizeof(float)); 40 | BLECharacteristic gyroscopeCharacteristic (SCIENCE_KIT_UUID("5002"), BLENotify, 3 * sizeof(float)); 41 | BLECharacteristic magneticFieldCharacteristic(SCIENCE_KIT_UUID("5003"), BLENotify, 3 * sizeof(float)); 42 | 43 | const int LED_PIN = 0; 44 | const int INPUT1_PIN = A3; 45 | const int INPUT2_PIN = A1; 46 | const int INPUT3_PIN = A0; 47 | const int OUTPUT1_PIN = 5; 48 | const int OUTPUT2_PIN = 1; 49 | const int RESISTANCE_PIN = A2; 50 | const int RESISTANCE_AUX_PIN = 8; 51 | 52 | String name; 53 | unsigned long lastNotify = 0; 54 | 55 | unsigned long imuTime; 56 | 57 | #define RESISTOR_AUX_LOW 47000.0 58 | #define RESISTOR_AUX_HIGH 979.16 // 47k in parallel with 1k = 979.16 Ohm 59 | 60 | #define IMU_UPDATE_TIME 50 61 | 62 | //#define DEBUG //uncomment to debug the code :) 63 | 64 | Adafruit_LSM9DS1 imu = Adafruit_LSM9DS1(); 65 | 66 | void setup() { 67 | Serial.begin(9600); 68 | #ifdef DEBUG 69 | while (!Serial); 70 | Serial.println("Started"); 71 | #endif 72 | 73 | pinMode(LED_PIN, OUTPUT); 74 | pinMode(INPUT1_PIN, INPUT); 75 | pinMode(INPUT2_PIN, INPUT); 76 | pinMode(INPUT3_PIN, INPUT); 77 | pinMode(OUTPUT1_PIN, OUTPUT); 78 | pinMode(OUTPUT2_PIN, OUTPUT); 79 | pinMode(RESISTANCE_AUX_PIN, OUTPUT); 80 | 81 | digitalWrite(RESISTANCE_AUX_PIN, LOW); 82 | 83 | if (!INA226.begin(0x45)) { 84 | Serial.println("Failled to initialized INA226!"); 85 | 86 | while (1); 87 | } 88 | 89 | if (!imu.begin()) { 90 | Serial.println("Failled to initialized IMU!"); 91 | 92 | while (1); 93 | } 94 | 95 | imu.setupAccel(imu.LSM9DS1_ACCELRANGE_2G); 96 | imu.setupMag(imu.LSM9DS1_MAGGAIN_4GAUSS); 97 | imu.setupGyro(imu.LSM9DS1_GYROSCALE_245DPS); 98 | 99 | if (!BLE.begin()) { 100 | Serial.println("Failled to initialized BLE!"); 101 | 102 | while (1); 103 | } 104 | 105 | String address = BLE.address(); 106 | 107 | address.toUpperCase(); 108 | 109 | name = "MKRSci"; 110 | name += address[address.length() - 5]; 111 | name += address[address.length() - 4]; 112 | name += address[address.length() - 2]; 113 | name += address[address.length() - 1]; 114 | 115 | BLE.setLocalName(name.c_str()); 116 | BLE.setDeviceName(name.c_str()); 117 | BLE.setAdvertisedService(service); 118 | 119 | service.addCharacteristic(versionCharacteristic); 120 | service.addCharacteristic(ledCharacteristic); 121 | service.addCharacteristic(input1Characteristic); 122 | service.addCharacteristic(input2Characteristic); 123 | service.addCharacteristic(input3Characteristic); 124 | service.addCharacteristic(ouput1Characteristic); 125 | service.addCharacteristic(ouput2Characteristic); 126 | service.addCharacteristic(voltageCharacteristic); 127 | service.addCharacteristic(currentCharacteristic); 128 | service.addCharacteristic(resistanceCharacteristic); 129 | service.addCharacteristic(accelerationCharacteristic); 130 | service.addCharacteristic(gyroscopeCharacteristic); 131 | service.addCharacteristic(magneticFieldCharacteristic); 132 | 133 | BLE.addService(service); 134 | 135 | BLE.advertise(); 136 | imuTime = millis(); 137 | } 138 | 139 | void loop() { 140 | lastNotify = 0; 141 | 142 | while (BLE.connected()) { 143 | if (ledCharacteristic.written()) { 144 | analogWrite(LED_PIN, ledCharacteristic.value()); 145 | } 146 | 147 | if (ouput1Characteristic.written()) { 148 | analogWrite(OUTPUT1_PIN, ouput1Characteristic.value()); 149 | } 150 | 151 | if (ouput2Characteristic.written()) { 152 | analogWrite(OUTPUT2_PIN, ouput2Characteristic.value()); 153 | } 154 | 155 | unsigned long now = millis(); 156 | 157 | if (abs((long)now - (long)lastNotify) >= 100) { 158 | lastNotify = now; 159 | 160 | // every 100ms update subscribed characteristics 161 | updateSubscribedCharacteristics(); 162 | } 163 | 164 | updateSubscribedIMUCharacteristics(); 165 | } 166 | } 167 | 168 | void updateSubscribedCharacteristics() { 169 | if (input1Characteristic.subscribed()) { 170 | input1Characteristic.writeValue(analogReadAverage(INPUT1_PIN, 30)); 171 | } 172 | 173 | if (input2Characteristic.subscribed()) { 174 | input2Characteristic.writeValue(analogReadAverage(INPUT2_PIN, 30)); 175 | } 176 | 177 | if (input3Characteristic.subscribed()) { 178 | input3Characteristic.writeValue(analogReadAverage(INPUT3_PIN, 30)); 179 | } 180 | 181 | if (voltageCharacteristic.subscribed()) { 182 | float voltage = INA226.readBusVoltage(); 183 | 184 | voltageCharacteristic.writeValue(voltage); 185 | } 186 | 187 | if (currentCharacteristic.subscribed()) { 188 | float current = INA226.readCurrent(); 189 | 190 | currentCharacteristic.writeValue(current); 191 | } 192 | 193 | if (resistanceCharacteristic.subscribed()) { 194 | float Vout = 0; 195 | float resistanceAuxLow = INFINITY; 196 | float resistanceAuxHigh = INFINITY; 197 | float resistanceAvg = INFINITY; //open circuit as default 198 | 199 | digitalWrite(RESISTANCE_AUX_PIN, LOW); 200 | Vout = getVoutAverage(); 201 | if ((Vout >= 0.1) && (Vout <= 3.0)) { 202 | resistanceAuxLow = RESISTOR_AUX_LOW * ((3.3 / Vout) - 1); 203 | } 204 | 205 | digitalWrite(RESISTANCE_AUX_PIN, HIGH); 206 | Vout = getVoutAverage(); 207 | if (Vout >= 0.1) { 208 | resistanceAuxHigh = RESISTOR_AUX_HIGH * ((3.3 / Vout) - 1); 209 | } 210 | 211 | #ifdef DEBUG 212 | Serial.print("Resistance (HIGH): "); 213 | Serial.print(resistanceAuxHigh); 214 | Serial.println(" Ohm"); 215 | 216 | Serial.print("Resistance (LOW): "); 217 | Serial.print(resistanceAuxLow); 218 | Serial.println(" Ohm"); 219 | #endif 220 | 221 | if ((resistanceAuxHigh != INFINITY) && (resistanceAuxLow != INFINITY)) { 222 | resistanceAvg = (resistanceAuxHigh + resistanceAuxLow) / 2; 223 | } else if ((resistanceAuxHigh != INFINITY) && (resistanceAuxLow == INFINITY)) { 224 | resistanceAvg = resistanceAuxHigh; 225 | } else if ((resistanceAuxHigh == INFINITY) && (resistanceAuxLow != INFINITY)) { 226 | resistanceAvg = resistanceAuxLow; 227 | } 228 | resistanceAvg += 0.025 * resistanceAvg; 229 | 230 | #ifdef DEBUG 231 | Serial.print("Resistance (AVG): "); 232 | Serial.print(resistanceAvg); 233 | Serial.println(" Ohm"); 234 | #endif 235 | resistanceCharacteristic.writeValue(resistanceAvg); 236 | } 237 | } 238 | 239 | float getVoutAverage() { 240 | float Vout = 0; 241 | for (int i = 0; i < 30; i++) { 242 | Vout += (analogRead(RESISTANCE_PIN) * 3.30) / 1023.0; 243 | } 244 | Vout /= 30; 245 | 246 | #ifdef DEBUG 247 | Serial.print("Vout: "); 248 | Serial.print(Vout); 249 | Serial.println("V"); 250 | #endif 251 | return Vout; 252 | } 253 | 254 | int analogReadAverage(int pin, int numberOfSamples) { 255 | int averageValue = 0; 256 | for (int i = 0; i < numberOfSamples; i++) { 257 | averageValue += analogRead(pin); 258 | } 259 | 260 | return (averageValue / numberOfSamples); 261 | } 262 | 263 | void updateSubscribedIMUCharacteristics() { 264 | if (millis() - imuTime > IMU_UPDATE_TIME) { 265 | imuTime = millis(); 266 | imu.read(); 267 | sensors_event_t a, m, g, temp; 268 | imu.getEvent(&a, &m, &g, &temp); 269 | 270 | if (accelerationCharacteristic.subscribed()) { 271 | float acceleration[3]; 272 | 273 | acceleration[0] = a.acceleration.x; 274 | acceleration[1] = a.acceleration.y; 275 | acceleration[2] = a.acceleration.z/10; 276 | accelerationCharacteristic.writeValue((byte*)acceleration, sizeof(acceleration)); 277 | } 278 | 279 | if (gyroscopeCharacteristic.subscribed()) { 280 | float gyroscope[3]; 281 | 282 | gyroscope[0] = g.gyro.x; 283 | gyroscope[1] = g.gyro.y; 284 | gyroscope[2] = g.gyro.z; 285 | gyroscopeCharacteristic.writeValue((byte*)gyroscope, sizeof(gyroscope)); 286 | } 287 | 288 | if (magneticFieldCharacteristic.subscribed()) { 289 | float magneticField[3]; 290 | 291 | magneticField[0] = m.magnetic.x; 292 | magneticField[1] = m.magnetic.y; 293 | magneticField[2] = m.magnetic.z; 294 | magneticFieldCharacteristic.writeValue((byte*)magneticField, sizeof(magneticField)); 295 | } 296 | } 297 | } 298 | --------------------------------------------------------------------------------