Upload folder using huggingface_hub
Browse files- .DS_Store +0 -0
- .gitattributes +14 -0
- .gitignore +1 -0
- Data_Collection_Scripts/README.md +3 -0
- Data_Collection_Scripts/arduino_master.ino +130 -0
- Data_Collection_Scripts/arduino_slave.ino +118 -0
- Data_Collection_Scripts/left.py +56 -0
- Data_Collection_Scripts/requirements.txt +1 -0
- Data_Collection_Scripts/right.py +57 -0
- Data_Collection_Scripts/run_legs.py +24 -0
- NewAccelMaster/NewAccelMaster.ino +90 -0
- NewAccelerometer/NewAccelerometer.ino +70 -0
- README.md +1 -0
- SimpleAccelMaster/SimpleAccelMaster.ino +78 -0
- SimpleAccelerometer/SimpleAccelerometer.ino +74 -0
- data/.DS_Store +0 -0
- data/processed/.DS_Store +0 -0
- data/processed/striding/features.csv +0 -0
- data/processed/striding/labels.csv +0 -0
- data/processed/walking/features.csv +0 -0
- data/processed/walking/labels.csv +0 -0
- data/unprocessed/StraightWalking/COM10.log +0 -0
- data/unprocessed/StraightWalking/COM3.log +0 -0
- data/unprocessed/StraightWalking/COM4.log +0 -0
- data/unprocessed/StraightWalking/COM5.log +0 -0
- data/unprocessed/SwerveWalking/COM10.log +0 -0
- data/unprocessed/SwerveWalking/COM3.log +0 -0
- data/unprocessed/SwerveWalking/COM4.log +0 -0
- data/unprocessed/SwerveWalking/COM5.log +0 -0
- data/unprocessed/WideStride/COM10.log +0 -0
- data/unprocessed/WideStride/COM3.log +0 -0
- data/unprocessed/WideStride/COM4.log +0 -0
- data/unprocessed/WideStride/COM5.log +0 -0
- data/unprocessed/striding/back_striding.txt +0 -0
- data/unprocessed/striding/front_striding.txt +0 -0
- data/unprocessed/walking/back_walking.txt +0 -0
- data/unprocessed/walking/front_walking.txt +0 -0
- model/.DS_Store +0 -0
- model/lstm/model.py +15 -0
- model/preprocess/preprocess.py +65 -0
- model/preprocess/run.sh +2 -0
- model/train/model.py +48 -0
- model/train/test.py +120 -0
- model/train/tran.py +208 -0
- sensor_calibration_data +38 -0
.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
.gitattributes
CHANGED
|
@@ -33,3 +33,17 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
*.DS_Store filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
*.gitignore filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
*.md filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
*.ino filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
*.py filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
*.txt filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
*.csv filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
*.log filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
*.pyc filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
*.sh filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
/sensor_calibration_data filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
*.yaml filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
*.json filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
*.wandb filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
.idea/
|
Data_Collection_Scripts/README.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Each leg requires one Arduino to be flashed as master, and one as slave.
|
| 2 |
+
|
| 3 |
+
The master Arduino should be connected to the Jetson.
|
Data_Collection_Scripts/arduino_master.ino
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <Wire.h>
|
| 2 |
+
extern TwoWire Wire1; // Declare Wire1 for secondary I²C bus
|
| 3 |
+
#include <SPI.h>
|
| 4 |
+
#include <Adafruit_LSM6DSOX.h>
|
| 5 |
+
|
| 6 |
+
#define CS_PIN 10 // Chip select pin for SPI
|
| 7 |
+
|
| 8 |
+
#define BUFFER_SIZE 48 // 12 floats * 4 bytes per float
|
| 9 |
+
|
| 10 |
+
// Sensor instances and addresses
|
| 11 |
+
Adafruit_LSM6DSOX sensor1;
|
| 12 |
+
uint8_t sensor1_addr = 0x6A; // Sensor 1 I2C address
|
| 13 |
+
Adafruit_LSM6DSOX sensor2;
|
| 14 |
+
uint8_t sensor2_addr = 0x6B; // Sensor 2 I2C address
|
| 15 |
+
|
| 16 |
+
// Arrays to hold sensor data
|
| 17 |
+
float masterData[12]; // Master's sensor data
|
| 18 |
+
float slaveData[12]; // Slave's sensor data
|
| 19 |
+
|
| 20 |
+
uint8_t slaveStorage[BUFFER_SIZE]; // Buffer to hold incoming data from slave
|
| 21 |
+
|
| 22 |
+
// Buffer to hold combined data for I2C transmission
|
| 23 |
+
#define TOTAL_DATA_SIZE 96 // 24 floats * 4 bytes per float
|
| 24 |
+
uint8_t i2cData[TOTAL_DATA_SIZE]; // Holds both masterData and slaveData
|
| 25 |
+
|
| 26 |
+
// Variables for I2C chunked transmission
|
| 27 |
+
volatile uint8_t requestedChunk = 0; // Chunk index requested by the master
|
| 28 |
+
#define CHUNK_SIZE 32 // Number of bytes per I2C chunk
|
| 29 |
+
#define TOTAL_CHUNKS ((TOTAL_DATA_SIZE + CHUNK_SIZE - 1) / CHUNK_SIZE) // Total number of chunks
|
| 30 |
+
|
| 31 |
+
void setup()
|
| 32 |
+
{
|
| 33 |
+
Serial.begin(115200); // Initialize Serial for debugging
|
| 34 |
+
|
| 35 |
+
// Initialize SPI communication
|
| 36 |
+
pinMode(CS_PIN, OUTPUT);
|
| 37 |
+
digitalWrite(CS_PIN, HIGH); // Deselect the slave
|
| 38 |
+
SPI.begin();
|
| 39 |
+
SPI.beginTransaction(SPISettings(21000000, MSBFIRST, SPI_MODE0));
|
| 40 |
+
|
| 41 |
+
// Initialize sensors on default I2C bus (Wire)
|
| 42 |
+
Wire.begin(); // Initialize default I2C bus as master
|
| 43 |
+
while (!sensor1.begin_I2C(sensor1_addr, &Wire))
|
| 44 |
+
{
|
| 45 |
+
Serial.println("Failed to initialize sensor1!");
|
| 46 |
+
delay(10);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
while (!sensor2.begin_I2C(sensor2_addr, &Wire))
|
| 50 |
+
{
|
| 51 |
+
Serial.println("Failed to initialize sensor2!");
|
| 52 |
+
delay(10);
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
sensor1.setAccelDataRate(LSM6DS_RATE_416_HZ);
|
| 56 |
+
sensor2.setAccelDataRate(LSM6DS_RATE_416_HZ);
|
| 57 |
+
|
| 58 |
+
// Initialize I2C as a slave on the secondary I2C bus (Wire1)
|
| 59 |
+
Wire1.begin(0x08); // Join the I2C bus with address #8
|
| 60 |
+
Wire1.onReceive(receiveEvent); // Register the receive event handler
|
| 61 |
+
Wire1.onRequest(requestEvent); // Register the request event handler
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
void loop()
|
| 65 |
+
{
|
| 66 |
+
// Read master's sensor data
|
| 67 |
+
updateMasterSensorData();
|
| 68 |
+
|
| 69 |
+
// Transfer data byte by byte (sending dummy data)
|
| 70 |
+
digitalWrite(CS_PIN, LOW); // Select the slave
|
| 71 |
+
for (size_t i = 0; i < BUFFER_SIZE; i++)
|
| 72 |
+
{
|
| 73 |
+
slaveStorage[i] = SPI.transfer(0x00); // Send dummy byte and receive data
|
| 74 |
+
}
|
| 75 |
+
digitalWrite(CS_PIN, HIGH); // Deselect the slave
|
| 76 |
+
|
| 77 |
+
// Reconstruct floats received from slave
|
| 78 |
+
memcpy(slaveData, slaveStorage, sizeof(slaveData));
|
| 79 |
+
|
| 80 |
+
// Prepare data for I2C transmission
|
| 81 |
+
|
| 82 |
+
Serial.println(slaveData[0]);
|
| 83 |
+
prepareI2CData();
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
// Function to read master's sensor data
|
| 87 |
+
void updateMasterSensorData()
|
| 88 |
+
{
|
| 89 |
+
|
| 90 |
+
// Read sensor1 data
|
| 91 |
+
sensor1.readAcceleration(masterData[0], masterData[1], masterData[2]);
|
| 92 |
+
sensor1.readGyroscope(masterData[3], masterData[4], masterData[5]);
|
| 93 |
+
|
| 94 |
+
// Read sensor2 data
|
| 95 |
+
sensor2.readAcceleration(masterData[6], masterData[7], masterData[8]);
|
| 96 |
+
sensor2.readGyroscope(masterData[9], masterData[10], masterData[11]);
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
// Function to prepare data for I2C transmission
|
| 100 |
+
void prepareI2CData()
|
| 101 |
+
{
|
| 102 |
+
// Combine masterData and slaveData into i2cData buffer
|
| 103 |
+
memcpy(i2cData, masterData, sizeof(masterData)); // Copy masterData
|
| 104 |
+
memcpy(i2cData + sizeof(masterData), slaveData, sizeof(slaveData)); // Copy slaveData
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
// I2C receive event handler
|
| 108 |
+
void receiveEvent(int numBytes)
|
| 109 |
+
{
|
| 110 |
+
if (numBytes >= 1)
|
| 111 |
+
{
|
| 112 |
+
requestedChunk = Wire1.read(); // Read the requested chunk index
|
| 113 |
+
// Read additional bytes if needed (not in this case)
|
| 114 |
+
}
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
// I2C request event handler
|
| 118 |
+
void requestEvent()
|
| 119 |
+
{
|
| 120 |
+
// Send data in chunks of CHUNK_SIZE bytes based on requestedChunk
|
| 121 |
+
uint16_t offset = requestedChunk * CHUNK_SIZE;
|
| 122 |
+
uint8_t bytesToSend = CHUNK_SIZE;
|
| 123 |
+
|
| 124 |
+
if (offset + CHUNK_SIZE > TOTAL_DATA_SIZE)
|
| 125 |
+
{
|
| 126 |
+
bytesToSend = TOTAL_DATA_SIZE - offset;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
Wire1.write(i2cData + offset, bytesToSend);
|
| 130 |
+
}
|
Data_Collection_Scripts/arduino_slave.ino
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <SPI.h>
|
| 2 |
+
#include <Adafruit_LSM6DSOX.h>
|
| 3 |
+
#include <stdint.h>
|
| 4 |
+
|
| 5 |
+
#define BUFFER_SIZE 48 // 12 floats * 4 bytes per float
|
| 6 |
+
#define SS_PIN 10
|
| 7 |
+
|
| 8 |
+
// Sensor instances and addresses
|
| 9 |
+
Adafruit_LSM6DSOX sensor1;
|
| 10 |
+
uint8_t sensor1_addr = 0x6A;
|
| 11 |
+
Adafruit_LSM6DSOX sensor2;
|
| 12 |
+
uint8_t sensor2_addr = 0x6B;
|
| 13 |
+
|
| 14 |
+
// Variables to hold sensor data
|
| 15 |
+
float sensorData[12]; // Array to hold sensor data
|
| 16 |
+
|
| 17 |
+
volatile uint8_t pos = 0;
|
| 18 |
+
volatile bool dataReady = false;
|
| 19 |
+
volatile bool transferComplete = false;
|
| 20 |
+
|
| 21 |
+
uint8_t sendStorage[BUFFER_SIZE]; // Buffer to store bytes to send to master
|
| 22 |
+
|
| 23 |
+
// SPI interrupt number for the SAM3X8E chip:
|
| 24 |
+
#define SPI0_INTERRUPT_NUMBER (IRQn_Type)24
|
| 25 |
+
|
| 26 |
+
void setup() {
|
| 27 |
+
Serial.begin(115200);
|
| 28 |
+
slaveBegin(SS_PIN); // Initialize SPI as slave on pin 10
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
void loop() {
|
| 32 |
+
if (transferComplete) {
|
| 33 |
+
transferComplete = false; // Reset flag
|
| 34 |
+
|
| 35 |
+
// Update sensor data
|
| 36 |
+
updateSensorData();
|
| 37 |
+
|
| 38 |
+
// Prepare data to send in next SPI transaction
|
| 39 |
+
memcpy(sendStorage, sensorData, sizeof(sensorData));
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
// Serial.println(sensorData[11]);
|
| 43 |
+
// Preload TDR with the first byte to send
|
| 44 |
+
REG_SPI0_TDR = sendStorage[0];
|
| 45 |
+
pos = 1; // Reset position for next transfer
|
| 46 |
+
}
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
void slaveBegin(uint8_t _pin) {
|
| 50 |
+
// Setup the SPI Interrupt registers
|
| 51 |
+
NVIC_ClearPendingIRQ(SPI0_INTERRUPT_NUMBER);
|
| 52 |
+
NVIC_EnableIRQ(SPI0_INTERRUPT_NUMBER);
|
| 53 |
+
|
| 54 |
+
// Initialize the SPI device with Arduino default values
|
| 55 |
+
SPI.begin(_pin);
|
| 56 |
+
REG_SPI0_CR = SPI_CR_SWRST; // Reset SPI
|
| 57 |
+
|
| 58 |
+
// Setup interrupt
|
| 59 |
+
REG_SPI0_IDR = SPI_IDR_TDRE | SPI_IDR_MODF | SPI_IDR_OVRES |
|
| 60 |
+
SPI_IDR_NSSR | SPI_IDR_TXEMPTY | SPI_IDR_UNDES;
|
| 61 |
+
REG_SPI0_IER = SPI_IER_RDRF;
|
| 62 |
+
|
| 63 |
+
// Setup the SPI registers
|
| 64 |
+
REG_SPI0_CR = SPI_CR_SPIEN; // Enable SPI
|
| 65 |
+
REG_SPI0_MR = SPI_MR_MODFDIS; // Slave and no modefault
|
| 66 |
+
REG_SPI0_CSR = SPI_MODE0; // DLYBCT=0, DLYBS=0, SCBR=0, 8-bit transfer
|
| 67 |
+
|
| 68 |
+
// Initialize sensors
|
| 69 |
+
while (!sensor1.begin_I2C(sensor1_addr)) {
|
| 70 |
+
Serial.println("Failed to initialize sensor1!");
|
| 71 |
+
delay(10);
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
while (!sensor2.begin_I2C(sensor2_addr)) {
|
| 75 |
+
Serial.println("Failed to initialize sensor2!");
|
| 76 |
+
delay(10);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
sensor1.setAccelDataRate(LSM6DS_RATE_416_HZ);
|
| 80 |
+
sensor2.setAccelDataRate(LSM6DS_RATE_416_HZ);
|
| 81 |
+
|
| 82 |
+
// Update sensor data for the first transfer
|
| 83 |
+
updateSensorData();
|
| 84 |
+
memcpy(sendStorage, sensorData, sizeof(sensorData));
|
| 85 |
+
|
| 86 |
+
// Preload TDR with the first byte to send
|
| 87 |
+
REG_SPI0_TDR = sendStorage[0];
|
| 88 |
+
pos = 1; // Start position at 1 since first byte is already loaded
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
void updateSensorData() {
|
| 92 |
+
// Read sensor1 data
|
| 93 |
+
sensor1.readAcceleration(sensorData[0], sensorData[1], sensorData[2]);
|
| 94 |
+
sensor1.readGyroscope(sensorData[3], sensorData[4], sensorData[5]);
|
| 95 |
+
|
| 96 |
+
// Read sensor2 data
|
| 97 |
+
sensor2.readAcceleration(sensorData[6], sensorData[7], sensorData[8]);
|
| 98 |
+
sensor2.readGyroscope(sensorData[9], sensorData[10], sensorData[11]);
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
void SPI0_Handler(void) {
|
| 102 |
+
uint32_t status = REG_SPI0_SR;
|
| 103 |
+
|
| 104 |
+
// Check if data has been received
|
| 105 |
+
if (status & SPI_SR_RDRF) {
|
| 106 |
+
// Read byte from SPI data register
|
| 107 |
+
uint8_t received_byte = REG_SPI0_RDR & 0xFF;
|
| 108 |
+
|
| 109 |
+
// Load next byte to transmit
|
| 110 |
+
if (pos < BUFFER_SIZE) {
|
| 111 |
+
REG_SPI0_TDR = sendStorage[pos++];
|
| 112 |
+
} else {
|
| 113 |
+
// All bytes have been sent
|
| 114 |
+
transferComplete = true;
|
| 115 |
+
pos = 0; // Reset position for the next transfer
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
}
|
Data_Collection_Scripts/left.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from smbus2 import SMBus
|
| 2 |
+
import time
|
| 3 |
+
import struct
|
| 4 |
+
|
| 5 |
+
I2C_BUS_NUMBER = 1
|
| 6 |
+
|
| 7 |
+
# I2C address of the Arduino
|
| 8 |
+
ARDUINO_I2C_ADDRESS = 0x08
|
| 9 |
+
|
| 10 |
+
# Total number of bytes to read (24 floats * 4 bytes per float)
|
| 11 |
+
TOTAL_BYTES = 96
|
| 12 |
+
|
| 13 |
+
# Maximum bytes per I2C transaction (due to limitations)
|
| 14 |
+
CHUNK_SIZE = 32
|
| 15 |
+
|
| 16 |
+
OUTPUT_FILE = "left_data.txt"
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def read_i2c_data(bus, addr, total_bytes, chunk_size):
|
| 20 |
+
data = []
|
| 21 |
+
chunks = (total_bytes + chunk_size - 1) // chunk_size
|
| 22 |
+
for chunk_index in range(chunks):
|
| 23 |
+
# Use read_i2c_block_data which sends a command byte before reading data
|
| 24 |
+
to_read = min(chunk_size, total_bytes - (chunk_index * chunk_size))
|
| 25 |
+
chunk_data = bus.read_i2c_block_data(addr, chunk_index, to_read)
|
| 26 |
+
data.extend(chunk_data)
|
| 27 |
+
return data
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
with SMBus(I2C_BUS_NUMBER) as bus, open(OUTPUT_FILE,'w') as f: # Use the correct I2C bus number
|
| 32 |
+
while True:
|
| 33 |
+
try:
|
| 34 |
+
# Read data in chunks
|
| 35 |
+
data = read_i2c_data(bus, ARDUINO_I2C_ADDRESS, TOTAL_BYTES, CHUNK_SIZE)
|
| 36 |
+
|
| 37 |
+
# Convert byte data to floats
|
| 38 |
+
floats = []
|
| 39 |
+
for i in range(0, TOTAL_BYTES, 4):
|
| 40 |
+
# Combine 4 bytes into a float
|
| 41 |
+
float_bytes = bytes(data[i:i+4])
|
| 42 |
+
value = struct.unpack('<f', float_bytes)[0] # '<f' for little-endian float
|
| 43 |
+
floats.append(value)
|
| 44 |
+
|
| 45 |
+
# Split into master and slave data
|
| 46 |
+
masterData = floats[:12]
|
| 47 |
+
slaveData = floats[12:]
|
| 48 |
+
|
| 49 |
+
# Print the data
|
| 50 |
+
f.write(f"{time.time()}\nM: {masterData}\nS:{slaveData}")
|
| 51 |
+
# print(f"{time.time()}\nM: {masterData}\nS:{slaveData}")
|
| 52 |
+
|
| 53 |
+
except Exception as e:
|
| 54 |
+
f.write(f"Error: {e}")
|
| 55 |
+
# print((f"Error: {e}"))
|
| 56 |
+
|
Data_Collection_Scripts/requirements.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
smbus2==0.5.0
|
Data_Collection_Scripts/right.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from smbus2 import SMBus
|
| 2 |
+
import time
|
| 3 |
+
import struct
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
I2C_BUS_NUMBER = 7
|
| 7 |
+
|
| 8 |
+
# I2C address of the Arduino
|
| 9 |
+
ARDUINO_I2C_ADDRESS = 0x08
|
| 10 |
+
|
| 11 |
+
# Total number of bytes to read (24 floats * 4 bytes per float)
|
| 12 |
+
TOTAL_BYTES = 96
|
| 13 |
+
|
| 14 |
+
# Maximum bytes per I2C transaction (due to limitations)
|
| 15 |
+
CHUNK_SIZE = 32
|
| 16 |
+
|
| 17 |
+
OUTPUT_FILE = "right_data.txt"
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def read_i2c_data(bus, addr, total_bytes, chunk_size):
|
| 21 |
+
data = []
|
| 22 |
+
chunks = (total_bytes + chunk_size - 1) // chunk_size
|
| 23 |
+
for chunk_index in range(chunks):
|
| 24 |
+
# Use read_i2c_block_data which sends a command byte before reading data
|
| 25 |
+
to_read = min(chunk_size, total_bytes - (chunk_index * chunk_size))
|
| 26 |
+
chunk_data = bus.read_i2c_block_data(addr, chunk_index, to_read)
|
| 27 |
+
data.extend(chunk_data)
|
| 28 |
+
return data
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
with SMBus(I2C_BUS_NUMBER) as bus, open(OUTPUT_FILE,'w') as f: # Use the correct I2C bus number
|
| 33 |
+
while True:
|
| 34 |
+
try:
|
| 35 |
+
# Read data in chunks
|
| 36 |
+
data = read_i2c_data(bus, ARDUINO_I2C_ADDRESS, TOTAL_BYTES, CHUNK_SIZE)
|
| 37 |
+
|
| 38 |
+
# Convert byte data to floats
|
| 39 |
+
floats = []
|
| 40 |
+
for i in range(0, TOTAL_BYTES, 4):
|
| 41 |
+
# Combine 4 bytes into a float
|
| 42 |
+
float_bytes = bytes(data[i:i+4])
|
| 43 |
+
value = struct.unpack('<f', float_bytes)[0] # '<f' for little-endian float
|
| 44 |
+
floats.append(value)
|
| 45 |
+
|
| 46 |
+
# Split into master and slave data
|
| 47 |
+
masterData = floats[:12]
|
| 48 |
+
slaveData = floats[12:]
|
| 49 |
+
|
| 50 |
+
# Print the data
|
| 51 |
+
f.write(f"{time.time()}\nM: {masterData}\nS:{slaveData}")
|
| 52 |
+
# print(f"{time.time()}\nM: {masterData}\nS:{slaveData}")
|
| 53 |
+
|
| 54 |
+
except Exception as e:
|
| 55 |
+
f.write(f"Error: {e}")
|
| 56 |
+
# print((f"Error: {e}"))
|
| 57 |
+
|
Data_Collection_Scripts/run_legs.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
""""
|
| 2 |
+
This file just runs both leg collections at once.
|
| 3 |
+
The 3 second delay between scripts is because we experienced some I2C errors when trying to
|
| 4 |
+
instantaneously access both I2C busses on the Jetson.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import subprocess
|
| 8 |
+
import time
|
| 9 |
+
|
| 10 |
+
DELAY_SECONDS = 3
|
| 11 |
+
|
| 12 |
+
right = 'right.py'
|
| 13 |
+
left = 'left.py'
|
| 14 |
+
|
| 15 |
+
print(f"Running {right}")
|
| 16 |
+
subprocess.run(["python",right])
|
| 17 |
+
|
| 18 |
+
print(f"Waiting {DELAY_SECONDS} seconds...")
|
| 19 |
+
time.sleep(DELAY_SECONDS)
|
| 20 |
+
|
| 21 |
+
print(f"Running {left}")
|
| 22 |
+
subprocess.run(["python",left])
|
| 23 |
+
|
| 24 |
+
print("Run complete.")
|
NewAccelMaster/NewAccelMaster.ino
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Arduino LSM6DSOX - Simple Accelerometer
|
| 3 |
+
|
| 4 |
+
This example reads the acceleration values from the LSM6DSOX
|
| 5 |
+
sensor and continuously prints them to the Serial Monitor
|
| 6 |
+
or Serial Plotter.
|
| 7 |
+
|
| 8 |
+
The circuit:
|
| 9 |
+
- Arduino Nano RP2040 Connect
|
| 10 |
+
|
| 11 |
+
created 10 May 2021
|
| 12 |
+
by Arturo Guadalupi
|
| 13 |
+
|
| 14 |
+
This example code is in the public domain.
|
| 15 |
+
*/
|
| 16 |
+
|
| 17 |
+
#include <Adafruit_LSM6DSOX.h>
|
| 18 |
+
#include <string>
|
| 19 |
+
#include <TimeLib.h>
|
| 20 |
+
Adafruit_LSM6DSOX sensor1;
|
| 21 |
+
uint8_t sensor1_addr = 0x6A;
|
| 22 |
+
Adafruit_LSM6DSOX sensor2;
|
| 23 |
+
uint8_t sensor2_addr = 0x6B;
|
| 24 |
+
String comma = ",";
|
| 25 |
+
String colon = ":";
|
| 26 |
+
float ax1, ay1, az1, ax2, gx1, gy1, gz1, ay2, az2, gx2, gy2, gz2;
|
| 27 |
+
uint32_t count;
|
| 28 |
+
|
| 29 |
+
void setup() {
|
| 30 |
+
pinMode(2, OUTPUT);
|
| 31 |
+
pinMode(3, OUTPUT);
|
| 32 |
+
pinMode(4, OUTPUT);
|
| 33 |
+
|
| 34 |
+
Serial.begin(115200);
|
| 35 |
+
while (!Serial);
|
| 36 |
+
|
| 37 |
+
while (!sensor1.begin_I2C(sensor1_addr)) {
|
| 38 |
+
Serial.println("Failed to initialize 0x6A!");
|
| 39 |
+
delay(10);
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
sensor1.setAccelDataRate(LSM6DS_RATE_6_66K_HZ);
|
| 43 |
+
Serial.print("Accelerometer sample rate = ");
|
| 44 |
+
Serial.print(sensor1.accelerationSampleRate());
|
| 45 |
+
Serial.println(" Hz");
|
| 46 |
+
Serial.println();
|
| 47 |
+
Serial.println("Acceleration in g's");
|
| 48 |
+
Serial.println("X\tY\tZ");
|
| 49 |
+
|
| 50 |
+
while (!sensor2.begin_I2C(sensor2_addr)) {
|
| 51 |
+
Serial.println("Failed to initialize 0x6B!");
|
| 52 |
+
delay(10);
|
| 53 |
+
}
|
| 54 |
+
sensor2.setAccelDataRate(LSM6DS_RATE_6_66K_HZ);
|
| 55 |
+
|
| 56 |
+
count = 0;
|
| 57 |
+
|
| 58 |
+
while(!Serial.available()); // Wait for serial input
|
| 59 |
+
|
| 60 |
+
digitalWrite(2, HIGH);
|
| 61 |
+
digitalWrite(2, LOW);
|
| 62 |
+
|
| 63 |
+
digitalWrite(3, HIGH); // Send signal pulse to others to sync counts
|
| 64 |
+
digitalWrite(3, LOW);
|
| 65 |
+
|
| 66 |
+
digitalWrite(4, HIGH);
|
| 67 |
+
digitalWrite(4, LOW);
|
| 68 |
+
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
void loop() {
|
| 72 |
+
|
| 73 |
+
digitalWrite(2, HIGH);
|
| 74 |
+
digitalWrite(2, LOW);
|
| 75 |
+
|
| 76 |
+
digitalWrite(3, HIGH); // Send signal pulse to others to process
|
| 77 |
+
digitalWrite(3, LOW);
|
| 78 |
+
|
| 79 |
+
digitalWrite(4, HIGH);
|
| 80 |
+
digitalWrite(4, LOW);
|
| 81 |
+
|
| 82 |
+
sensor1.readAcceleration(ax1, ay1, az1);
|
| 83 |
+
sensor1.readGyroscope(gx1, gy1, gz1);
|
| 84 |
+
sensor2.readAcceleration(ax2, ay2, az2); // Read in sensor data
|
| 85 |
+
sensor2.readGyroscope(gx2, gy2, gz2);
|
| 86 |
+
|
| 87 |
+
Serial.print(count++ + colon + ax1 + comma + ay1 + comma + az1 + comma + ax2 + comma + ay2 + comma + az2 + comma);
|
| 88 |
+
Serial.println(gx1 + comma + gy1 + comma + gz1 + comma + gx2 + comma + gy2 + comma + gz2);
|
| 89 |
+
|
| 90 |
+
}
|
NewAccelerometer/NewAccelerometer.ino
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Arduino LSM6DSOX - Simple Accelerometer
|
| 3 |
+
|
| 4 |
+
This example reads the acceleration values from the LSM6DSOX
|
| 5 |
+
sensor and continuously prints them to the Serial Monitor
|
| 6 |
+
or Serial Plotter.
|
| 7 |
+
|
| 8 |
+
The circuit:
|
| 9 |
+
- Arduino Nano RP2040 Connect
|
| 10 |
+
|
| 11 |
+
created 10 May 2021
|
| 12 |
+
by Arturo Guadalupi
|
| 13 |
+
|
| 14 |
+
This example code is in the public domain.
|
| 15 |
+
*/
|
| 16 |
+
|
| 17 |
+
#include <Adafruit_LSM6DSOX.h>
|
| 18 |
+
#include <string>
|
| 19 |
+
#include <TimeLib.h>
|
| 20 |
+
Adafruit_LSM6DSOX sensor1;
|
| 21 |
+
uint8_t sensor1_addr = 0x6A;
|
| 22 |
+
Adafruit_LSM6DSOX sensor2;
|
| 23 |
+
uint8_t sensor2_addr = 0x6B;
|
| 24 |
+
String comma = ",";
|
| 25 |
+
String colon = ":";
|
| 26 |
+
float ax1, ay1, az1, ax2, gx1, gy1, gz1, ay2, az2, gx2, gy2, gz2;
|
| 27 |
+
uint32_t count;
|
| 28 |
+
|
| 29 |
+
void setup() {
|
| 30 |
+
pinMode(2, INPUT);
|
| 31 |
+
|
| 32 |
+
Serial.begin(115200);
|
| 33 |
+
while (!Serial);
|
| 34 |
+
|
| 35 |
+
while (!sensor1.begin_I2C(sensor1_addr)) {
|
| 36 |
+
Serial.println("Failed to initialize 0x6A!");
|
| 37 |
+
delay(10);
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
sensor1.setAccelDataRate(LSM6DS_RATE_6_66K_HZ);
|
| 41 |
+
Serial.print("Accelerometer sample rate = ");
|
| 42 |
+
Serial.print(sensor1.accelerationSampleRate());
|
| 43 |
+
Serial.println(" Hz");
|
| 44 |
+
Serial.println();
|
| 45 |
+
Serial.println("Acceleration in g's");
|
| 46 |
+
Serial.println("X\tY\tZ");
|
| 47 |
+
|
| 48 |
+
while (!sensor2.begin_I2C(sensor2_addr)) {
|
| 49 |
+
Serial.println("Failed to initialize 0x6B!");
|
| 50 |
+
delay(10);
|
| 51 |
+
}
|
| 52 |
+
sensor2.setAccelDataRate(LSM6DS_RATE_6_66K_HZ);
|
| 53 |
+
|
| 54 |
+
while(!digitalRead(2)); // Wait for signal to start
|
| 55 |
+
count = 0;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
void loop() {
|
| 59 |
+
|
| 60 |
+
while(!digitalRead(2)); // Wait for signal to proceed
|
| 61 |
+
|
| 62 |
+
sensor1.readAcceleration(ax1, ay1, az1);
|
| 63 |
+
sensor1.readGyroscope(gx1, gy1, gz1);
|
| 64 |
+
sensor2.readAcceleration(ax2, ay2, az2); // Read in sensor data
|
| 65 |
+
sensor2.readGyroscope(gx2, gy2, gz2);
|
| 66 |
+
|
| 67 |
+
Serial.print(count++ + colon + ax1 + comma + ay1 + comma + az1 + comma + gx1 + comma + gy1 + comma + gz1);
|
| 68 |
+
Serial.println(ax2 + comma + ay2 + comma + az2 + comma + gx2 + comma + gy2 + comma + gz2);
|
| 69 |
+
|
| 70 |
+
}
|
README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
#starx
|
SimpleAccelMaster/SimpleAccelMaster.ino
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Arduino LSM6DSOX - Simple Accelerometer
|
| 3 |
+
|
| 4 |
+
This example reads the acceleration values from the LSM6DSOX
|
| 5 |
+
sensor and continuously prints them to the Serial Monitor
|
| 6 |
+
or Serial Plotter.
|
| 7 |
+
|
| 8 |
+
The circuit:
|
| 9 |
+
- Arduino Nano RP2040 Connect
|
| 10 |
+
|
| 11 |
+
created 10 May 2021
|
| 12 |
+
by Arturo Guadalupi
|
| 13 |
+
|
| 14 |
+
This example code is in the public domain.
|
| 15 |
+
*/
|
| 16 |
+
|
| 17 |
+
#include <Adafruit_LSM6DSOX.h>
|
| 18 |
+
#include <string>
|
| 19 |
+
#include <TimeLib.h>
|
| 20 |
+
Adafruit_LSM6DSOX sensor1;
|
| 21 |
+
uint8_t sensor1_addr = 0x6A;
|
| 22 |
+
Adafruit_LSM6DSOX sensor2;
|
| 23 |
+
uint8_t sensor2_addr = 0x6B;
|
| 24 |
+
String comma = ",";
|
| 25 |
+
float ax1, ay1, az1, ax2, gx1, gy1, gz1, ay2, az2, gx2, gy2, gz2;
|
| 26 |
+
uint32_t time_start;
|
| 27 |
+
|
| 28 |
+
void setup() {
|
| 29 |
+
pinMode(2, OUTPUT);
|
| 30 |
+
pinMode(3, OUTPUT);
|
| 31 |
+
pinMode(4, OUTPUT);
|
| 32 |
+
|
| 33 |
+
Serial.begin(115200);
|
| 34 |
+
while (!Serial);
|
| 35 |
+
|
| 36 |
+
while (!sensor1.begin_I2C(sensor1_addr)) {
|
| 37 |
+
Serial.println("Failed to initialize 0x6A!");
|
| 38 |
+
delay(10);
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
sensor1.setAccelDataRate(LSM6DS_RATE_416_HZ);
|
| 42 |
+
Serial.print("Accelerometer sample rate = ");
|
| 43 |
+
Serial.print(sensor1.accelerationSampleRate());
|
| 44 |
+
Serial.println(" Hz");
|
| 45 |
+
Serial.println();
|
| 46 |
+
Serial.println("Acceleration in g's");
|
| 47 |
+
Serial.println("X\tY\tZ");
|
| 48 |
+
|
| 49 |
+
while (!sensor2.begin_I2C(sensor2_addr)) {
|
| 50 |
+
Serial.println("Failed to initialize 0x6B!");
|
| 51 |
+
delay(10);
|
| 52 |
+
}
|
| 53 |
+
sensor2.setAccelDataRate(LSM6DS_RATE_416_HZ);
|
| 54 |
+
|
| 55 |
+
digitalWrite(2, HIGH);
|
| 56 |
+
digitalWrite(3, HIGH);
|
| 57 |
+
digitalWrite(4, HIGH);
|
| 58 |
+
|
| 59 |
+
time_start = millis();
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
void loop() {
|
| 63 |
+
if (sensor1.accelerationAvailable())
|
| 64 |
+
sensor1.readAcceleration(ax1, ay1, az1);
|
| 65 |
+
|
| 66 |
+
if (sensor1.gyroscopeAvailable())
|
| 67 |
+
sensor1.readGyroscope(gx1, gy1, gz1);
|
| 68 |
+
|
| 69 |
+
if (sensor2.accelerationAvailable())
|
| 70 |
+
sensor2.readAcceleration(ax2, ay2, az2);
|
| 71 |
+
|
| 72 |
+
if (sensor2.gyroscopeAvailable())
|
| 73 |
+
sensor2.readGyroscope(gx2, gy2, gz2);
|
| 74 |
+
|
| 75 |
+
Serial.print((millis() - time_start) + comma + ax1 + comma + ay1 + comma + az1 + comma + ax2 + comma + ay2 + comma + az2 + comma);
|
| 76 |
+
Serial.println(gx1 + comma + gy1 + comma + gz1 + comma + gx2 + comma + gy2 + comma + gz2);
|
| 77 |
+
|
| 78 |
+
}
|
SimpleAccelerometer/SimpleAccelerometer.ino
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Arduino LSM6DSOX - Simple Accelerometer
|
| 3 |
+
|
| 4 |
+
This example reads the acceleration values from the LSM6DSOX
|
| 5 |
+
sensor and continuously prints them to the Serial Monitor
|
| 6 |
+
or Serial Plotter.
|
| 7 |
+
|
| 8 |
+
The circuit:
|
| 9 |
+
- Arduino Nano RP2040 Connect
|
| 10 |
+
|
| 11 |
+
created 10 May 2021
|
| 12 |
+
by Arturo Guadalupi
|
| 13 |
+
|
| 14 |
+
This example code is in the public domain.
|
| 15 |
+
*/
|
| 16 |
+
|
| 17 |
+
#include <Adafruit_LSM6DSOX.h>
|
| 18 |
+
#include <string>
|
| 19 |
+
#include <TimeLib.h>
|
| 20 |
+
Adafruit_LSM6DSOX sensor1;
|
| 21 |
+
uint8_t sensor1_addr = 0x6A;
|
| 22 |
+
Adafruit_LSM6DSOX sensor2;
|
| 23 |
+
uint8_t sensor2_addr = 0x6B;
|
| 24 |
+
String comma = ",";
|
| 25 |
+
float ax1, ay1, az1, ax2, gx1, gy1, gz1, ay2, az2, gx2, gy2, gz2;
|
| 26 |
+
uint32_t time_start;
|
| 27 |
+
|
| 28 |
+
void setup() {
|
| 29 |
+
pinMode(2, INPUT);
|
| 30 |
+
|
| 31 |
+
Serial.begin(115200);
|
| 32 |
+
while (!Serial);
|
| 33 |
+
|
| 34 |
+
while (!sensor1.begin_I2C(sensor1_addr)) {
|
| 35 |
+
Serial.println("Failed to initialize 0x6A!");
|
| 36 |
+
delay(10);
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
sensor1.setAccelDataRate(LSM6DS_RATE_416_HZ);
|
| 40 |
+
Serial.print("Accelerometer sample rate = ");
|
| 41 |
+
Serial.print(sensor1.accelerationSampleRate());
|
| 42 |
+
Serial.println(" Hz");
|
| 43 |
+
Serial.println();
|
| 44 |
+
Serial.println("Acceleration in g's");
|
| 45 |
+
Serial.println("X\tY\tZ");
|
| 46 |
+
|
| 47 |
+
while (!sensor2.begin_I2C(sensor2_addr)) {
|
| 48 |
+
Serial.println("Failed to initialize 0x6B!");
|
| 49 |
+
delay(10);
|
| 50 |
+
}
|
| 51 |
+
sensor2.setAccelDataRate(LSM6DS_RATE_416_HZ);
|
| 52 |
+
|
| 53 |
+
while(!digitalRead(2));
|
| 54 |
+
|
| 55 |
+
time_start = millis();
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
void loop() {
|
| 59 |
+
|
| 60 |
+
if (sensor1.accelerationAvailable())
|
| 61 |
+
sensor1.readAcceleration(ax1, ay1, az1);
|
| 62 |
+
|
| 63 |
+
if (sensor1.gyroscopeAvailable())
|
| 64 |
+
sensor1.readGyroscope(gx1, gy1, gz1);
|
| 65 |
+
|
| 66 |
+
if (sensor2.accelerationAvailable())
|
| 67 |
+
sensor2.readAcceleration(ax2, ay2, az2);
|
| 68 |
+
|
| 69 |
+
if (sensor2.gyroscopeAvailable())
|
| 70 |
+
sensor2.readGyroscope(gx2, gy2, gz2);
|
| 71 |
+
|
| 72 |
+
Serial.print((millis() - time_start) + comma + ax1 + comma + ay1 + comma + az1 + comma + gx1 + comma + gy1 + comma + gz1);
|
| 73 |
+
Serial.println(ax2 + comma + ay2 + comma + az2 + comma + gx2 + comma + gy2 + comma + gz2);
|
| 74 |
+
}
|
data/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
data/processed/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
data/processed/striding/features.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/processed/striding/labels.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/processed/walking/features.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/processed/walking/labels.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/StraightWalking/COM10.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/StraightWalking/COM3.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/StraightWalking/COM4.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/StraightWalking/COM5.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/SwerveWalking/COM10.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/SwerveWalking/COM3.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/SwerveWalking/COM4.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/SwerveWalking/COM5.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/WideStride/COM10.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/WideStride/COM3.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/WideStride/COM4.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/WideStride/COM5.log
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/striding/back_striding.txt
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/striding/front_striding.txt
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/walking/back_walking.txt
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/unprocessed/walking/front_walking.txt
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
model/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
model/lstm/model.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch.nn as nn
|
| 2 |
+
|
| 3 |
+
class LSTMModel(nn.Module):
|
| 4 |
+
def __init__(self, input_size=12, hidden_size=100, output_size=12, num_layers=2):
|
| 5 |
+
super(LSTMModel, self).__init__()
|
| 6 |
+
self.lstm = nn.LSTM(input_size=input_size,
|
| 7 |
+
hidden_size=hidden_size,
|
| 8 |
+
num_layers=num_layers,
|
| 9 |
+
batch_first=True)
|
| 10 |
+
self.fc = nn.Linear(hidden_size, output_size)
|
| 11 |
+
|
| 12 |
+
def forward(self, x):
|
| 13 |
+
out, _ = self.lstm(x)
|
| 14 |
+
out = self.fc(out)
|
| 15 |
+
return out
|
model/preprocess/preprocess.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import torch
|
| 4 |
+
import sys
|
| 5 |
+
import os
|
| 6 |
+
from sklearn.preprocessing import StandardScaler,MinMaxScaler
|
| 7 |
+
np.set_printoptions(suppress=True)
|
| 8 |
+
|
| 9 |
+
ss,mm = StandardScaler(), StandardScaler()
|
| 10 |
+
thigh = pd.read_csv(f"../../data/unprocessed/{sys.argv[1]}/front_{sys.argv[1]}.txt",delimiter=',',usecols =[i for i in range(13) if i != 0])
|
| 11 |
+
shin = pd.read_csv(f"../../data/unprocessed/{sys.argv[1]}/back_{sys.argv[1]}.txt",delimiter=',',usecols =[i for i in range(13) if i != 0])
|
| 12 |
+
thigh,shin = thigh.dropna(),shin.dropna()
|
| 13 |
+
delta = len(thigh) - len(shin)
|
| 14 |
+
|
| 15 |
+
thigh = thigh[delta:]
|
| 16 |
+
thigh.reset_index(inplace=True)
|
| 17 |
+
thigh,shin = thigh[:55000],shin[:55000]
|
| 18 |
+
|
| 19 |
+
for col in thigh.columns:
|
| 20 |
+
thigh.rename(columns={col:col+"_th"},inplace=True)
|
| 21 |
+
shin.rename(columns={col:col+"_sh"},inplace=True)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
p_columns_th = [col for col in thigh.columns if col.startswith('p')]
|
| 25 |
+
s_columns_th = [col for col in thigh.columns if col.startswith('s')]
|
| 26 |
+
p_columns_sh = [col for col in shin.columns if col.startswith('p')]
|
| 27 |
+
s_columns_sh = [col for col in shin.columns if col.startswith('s')]
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
features = thigh[p_columns_th]
|
| 32 |
+
features = pd.concat([features,shin[p_columns_sh]],axis=1)
|
| 33 |
+
|
| 34 |
+
labels = thigh[s_columns_th]
|
| 35 |
+
labels = pd.concat([labels,shin[s_columns_sh]],axis=1)
|
| 36 |
+
|
| 37 |
+
features_scaled = pd.DataFrame(ss.fit_transform(features), columns=features.columns)
|
| 38 |
+
labels_scaled = pd.DataFrame(mm.fit_transform(labels), columns=labels.columns)
|
| 39 |
+
|
| 40 |
+
os.makedirs(f"../../data/processed/{sys.argv[1]}",exist_ok=True)
|
| 41 |
+
features.to_csv(f"../../data/processed/{sys.argv[1]}/features.csv")
|
| 42 |
+
labels.to_csv(f"../../data/processed/{sys.argv[1]}/labels.csv")
|
| 43 |
+
|
| 44 |
+
def preprocess_data(features_df, labels_df, lookback_window, predict_window, output_file):
|
| 45 |
+
lookback_window *= 150
|
| 46 |
+
predict_window *= 150
|
| 47 |
+
|
| 48 |
+
total_samples = len(features_df) - lookback_window - predict_window
|
| 49 |
+
|
| 50 |
+
x_data = torch.zeros((total_samples, lookback_window, features_df.shape[1]))
|
| 51 |
+
y_data = torch.zeros((total_samples, predict_window, labels_df.shape[1]))
|
| 52 |
+
|
| 53 |
+
for idx, i in enumerate(range(lookback_window, len(features_df) - predict_window)):
|
| 54 |
+
if idx % 1000 == 0:
|
| 55 |
+
print(f"Processing sample {idx}/{total_samples}...")
|
| 56 |
+
|
| 57 |
+
x_data[idx] = torch.tensor(features_df.iloc[i - lookback_window:i].values, dtype=torch.float32)
|
| 58 |
+
y_data[idx] = torch.tensor(labels_df.iloc[i:i + predict_window].values, dtype=torch.float32)
|
| 59 |
+
|
| 60 |
+
torch.save({"x": x_data, "y": y_data}, output_file)
|
| 61 |
+
print(f"Preprocessed data saved to {output_file}")
|
| 62 |
+
|
| 63 |
+
preprocess_data(features,labels,3,3,f"../../data/processed/{sys.argv[1]}/data.pt")
|
| 64 |
+
|
| 65 |
+
|
model/preprocess/run.sh
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
python preprocess.py striding
|
| 2 |
+
python preprocess.py walking
|
model/train/model.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch.nn as nn
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class LSTMModel(nn.Module):
|
| 5 |
+
def __init__(self, input_size=12, hidden_size=64, output_size=12, num_layers=2):
|
| 6 |
+
super(LSTMModel, self).__init__()
|
| 7 |
+
self.lstm = nn.LSTM(input_size=input_size,
|
| 8 |
+
hidden_size=hidden_size,
|
| 9 |
+
num_layers=num_layers,
|
| 10 |
+
batch_first=True)
|
| 11 |
+
self.fc = nn.Linear(hidden_size, output_size)
|
| 12 |
+
|
| 13 |
+
def forward(self, x):
|
| 14 |
+
out, _ = self.lstm(x)
|
| 15 |
+
out = self.fc(out)
|
| 16 |
+
return out
|
| 17 |
+
|
| 18 |
+
from transformers import PreTrainedModel, PretrainedConfig
|
| 19 |
+
import torch.nn as nn
|
| 20 |
+
|
| 21 |
+
# Define a custom configuration class
|
| 22 |
+
class LSTMConfig(PretrainedConfig):
|
| 23 |
+
model_type = "lstm_model"
|
| 24 |
+
|
| 25 |
+
def __init__(self, input_size=12, hidden_size=100, output_size=12, num_layers=2, **kwargs):
|
| 26 |
+
super().__init__(**kwargs)
|
| 27 |
+
self.input_size = input_size
|
| 28 |
+
self.hidden_size = hidden_size
|
| 29 |
+
self.output_size = output_size
|
| 30 |
+
self.num_layers = num_layers
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
# Define the Hugging Face-compatible model
|
| 34 |
+
class HuggingFaceLSTM(PreTrainedModel):
|
| 35 |
+
config_class = LSTMConfig
|
| 36 |
+
|
| 37 |
+
def __init__(self, config):
|
| 38 |
+
super().__init__(config)
|
| 39 |
+
self.lstm_model = LSTMModel(
|
| 40 |
+
input_size=config.input_size,
|
| 41 |
+
hidden_size=config.hidden_size,
|
| 42 |
+
output_size=config.output_size,
|
| 43 |
+
num_layers=config.num_layers,
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
def forward(self, x, **kwargs):
|
| 47 |
+
return self.lstm_model(x)
|
| 48 |
+
|
model/train/test.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import numpy as np
|
| 3 |
+
import random
|
| 4 |
+
import os
|
| 5 |
+
from torch.utils.data import DataLoader, TensorDataset
|
| 6 |
+
from torch.utils.data.dataloader import default_collate
|
| 7 |
+
import torch.optim.lr_scheduler as lr_scheduler
|
| 8 |
+
|
| 9 |
+
from tqdm import tqdm
|
| 10 |
+
import matplotlib.pyplot as plt
|
| 11 |
+
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
|
| 12 |
+
|
| 13 |
+
def set_seed(seed):
|
| 14 |
+
np.random.seed(seed)
|
| 15 |
+
random.seed(seed)
|
| 16 |
+
torch.manual_seed(seed)
|
| 17 |
+
torch.cuda.manual_seed_all(seed)
|
| 18 |
+
torch.backends.cudnn.deterministic = True
|
| 19 |
+
torch.backends.cudnn.benchmark = False
|
| 20 |
+
|
| 21 |
+
set_seed(42)
|
| 22 |
+
|
| 23 |
+
from model import HuggingFaceLSTM
|
| 24 |
+
from model import LSTMConfig
|
| 25 |
+
|
| 26 |
+
def setup_model(device):
|
| 27 |
+
config = LSTMConfig(
|
| 28 |
+
input_size=12,
|
| 29 |
+
hidden_size=100,
|
| 30 |
+
output_size=12,
|
| 31 |
+
num_layers=2
|
| 32 |
+
)
|
| 33 |
+
|
| 34 |
+
model = HuggingFaceLSTM(config)
|
| 35 |
+
|
| 36 |
+
model.to(device)
|
| 37 |
+
|
| 38 |
+
return model
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def setup_data(data,batch_size):
|
| 42 |
+
train_split = int(0.85 * 54100)
|
| 43 |
+
X = data['x']
|
| 44 |
+
y = data['y']
|
| 45 |
+
|
| 46 |
+
X_train = X[:train_split]
|
| 47 |
+
y_train = y[:train_split]
|
| 48 |
+
|
| 49 |
+
def normalize_dataset(data):
|
| 50 |
+
data_min = data.amin(dim=(0, 1), keepdim=True)
|
| 51 |
+
data_max = data.amax(dim=(0, 1), keepdim=True)
|
| 52 |
+
normalized_data = (data - data_min) / (data_max - data_min + 1e-8)
|
| 53 |
+
return normalized_data
|
| 54 |
+
|
| 55 |
+
X_norm = normalize_dataset(X_train)
|
| 56 |
+
y_norm = normalize_dataset(y_train)
|
| 57 |
+
|
| 58 |
+
train_dataset = TensorDataset(X_norm,y_norm)
|
| 59 |
+
train_loader = DataLoader(
|
| 60 |
+
train_dataset,
|
| 61 |
+
batch_size=batch_size,
|
| 62 |
+
shuffle=True,
|
| 63 |
+
collate_fn=lambda x: tuple(x_.to(device) for x_ in default_collate(x))
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
return train_loader
|
| 67 |
+
|
| 68 |
+
def train(n_epochs, model, opt,scheduler, loss_fn, batched_data):
|
| 69 |
+
model.train()
|
| 70 |
+
for epoch in range(n_epochs):
|
| 71 |
+
epoch_loss = 0.0
|
| 72 |
+
n_batch = len(batched_data)
|
| 73 |
+
|
| 74 |
+
with tqdm(total=n_batch, desc=f"Epoch {epoch+1}/{n_epochs}", unit="batch") as bar:
|
| 75 |
+
for i, (inputs, targets) in enumerate(batched_data):
|
| 76 |
+
|
| 77 |
+
outputs = model(inputs)
|
| 78 |
+
loss = loss_fn(outputs, targets)
|
| 79 |
+
opt.zero_grad()
|
| 80 |
+
loss.backward()
|
| 81 |
+
opt.step()
|
| 82 |
+
|
| 83 |
+
epoch_loss += loss.item()
|
| 84 |
+
if epoch % 1 == 0:
|
| 85 |
+
plt.plot(outputs[0,:,0].detach().squeeze().cpu(),label="Prediction")
|
| 86 |
+
plt.plot(targets[0,:,0].detach().squeeze().cpu(),label="Actual")
|
| 87 |
+
plt.title("s_a_x_th")
|
| 88 |
+
plt.legend()
|
| 89 |
+
plt.savefig(f"im_{epoch}.png")
|
| 90 |
+
plt.clf()
|
| 91 |
+
scheduler.step()
|
| 92 |
+
bar.set_description(f"Epoch {epoch+1}/{n_epochs} | Loss: {epoch_loss / (i+1):.6f}")
|
| 93 |
+
bar.update(1)
|
| 94 |
+
|
| 95 |
+
print(f"Epoch {epoch+1}/{n_epochs} completed. Average Loss: {epoch_loss / n_batch:.6f}")
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
if __name__ == "__main__":
|
| 100 |
+
|
| 101 |
+
device = torch.device('cuda:1')
|
| 102 |
+
raw_data = torch.load('../../data/processed/striding/data.pt')
|
| 103 |
+
model = setup_model(device)
|
| 104 |
+
train_data = setup_data(data=raw_data,batch_size=2048)
|
| 105 |
+
try:
|
| 106 |
+
lr = 0.001
|
| 107 |
+
adam = torch.optim.Adam(model.parameters(),lr=lr)
|
| 108 |
+
linear_scheduler = lr_scheduler.LinearLR(adam, start_factor=1.0, end_factor=0.5, total_iters=30)
|
| 109 |
+
train(
|
| 110 |
+
n_epochs=1000,
|
| 111 |
+
model=model,
|
| 112 |
+
opt=adam,
|
| 113 |
+
scheduler=linear_scheduler,
|
| 114 |
+
loss_fn=torch.nn.HuberLoss(),
|
| 115 |
+
batched_data=train_data
|
| 116 |
+
)
|
| 117 |
+
except Exception as e:
|
| 118 |
+
print(e)
|
| 119 |
+
model.save_pretrained("./lstm_model_with_lr")
|
| 120 |
+
model.save_pretrained("./lstm_model_with_lr")
|
model/train/tran.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch.nn as nn
|
| 2 |
+
import torch
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
from tqdm import tqdm
|
| 5 |
+
from torch.utils.data import DataLoader,TensorDataset,default_collate
|
| 6 |
+
device = torch.device('cuda:1')
|
| 7 |
+
from torch.optim import lr_scheduler
|
| 8 |
+
class TransformerModel(nn.Module):
|
| 9 |
+
def __init__(self, input_size=12, hidden_size=64, output_size=12, num_layers=2, nhead=4, seq_length=450):
|
| 10 |
+
super(TransformerModel, self).__init__()
|
| 11 |
+
self.input_size = input_size
|
| 12 |
+
self.hidden_size = hidden_size
|
| 13 |
+
self.output_size = output_size
|
| 14 |
+
self.seq_length = seq_length
|
| 15 |
+
|
| 16 |
+
# Input embedding layer to project input to hidden size
|
| 17 |
+
self.embedding = nn.Linear(input_size, hidden_size)
|
| 18 |
+
|
| 19 |
+
# Positional encoding for sequence information
|
| 20 |
+
self.positional_encoding = nn.Parameter(torch.zeros(1, seq_length, hidden_size))
|
| 21 |
+
|
| 22 |
+
# Transformer encoder
|
| 23 |
+
encoder_layer = nn.TransformerEncoderLayer(d_model=hidden_size, nhead=nhead,dropout=0.3)
|
| 24 |
+
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
|
| 25 |
+
|
| 26 |
+
# Output projection layer
|
| 27 |
+
self.fc = nn.Linear(hidden_size, output_size)
|
| 28 |
+
|
| 29 |
+
def forward(self, x):
|
| 30 |
+
# x: (batch_size, seq_length, input_size)
|
| 31 |
+
|
| 32 |
+
# Apply input embedding
|
| 33 |
+
x = self.embedding(x) # (batch_size, seq_length, hidden_size)
|
| 34 |
+
|
| 35 |
+
# Add positional encoding
|
| 36 |
+
x = x + self.positional_encoding # (batch_size, seq_length, hidden_size)
|
| 37 |
+
|
| 38 |
+
# Pass through transformer
|
| 39 |
+
x = self.transformer(x.permute(1, 0, 2)) # Transformer expects (seq_length, batch_size, hidden_size)
|
| 40 |
+
|
| 41 |
+
# Project back to output size
|
| 42 |
+
x = self.fc(x.permute(1, 0, 2)) # (batch_size, seq_length, output_size)
|
| 43 |
+
return x
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
from transformers import PreTrainedModel, PretrainedConfig
|
| 47 |
+
|
| 48 |
+
class TransformerConfig(PretrainedConfig):
|
| 49 |
+
model_type = "transformer_model"
|
| 50 |
+
|
| 51 |
+
def __init__(self, input_size=12, hidden_size=64, output_size=12, num_layers=2, nhead=4, seq_length=450, **kwargs):
|
| 52 |
+
super().__init__(**kwargs)
|
| 53 |
+
self.input_size = input_size
|
| 54 |
+
self.hidden_size = hidden_size
|
| 55 |
+
self.output_size = output_size
|
| 56 |
+
self.num_layers = num_layers
|
| 57 |
+
self.nhead = nhead
|
| 58 |
+
self.seq_length = seq_length
|
| 59 |
+
|
| 60 |
+
class HuggingFaceTransformer(PreTrainedModel):
|
| 61 |
+
config_class = TransformerConfig
|
| 62 |
+
|
| 63 |
+
def __init__(self, config):
|
| 64 |
+
super().__init__(config)
|
| 65 |
+
self.transformer_model = TransformerModel(
|
| 66 |
+
input_size=config.input_size,
|
| 67 |
+
hidden_size=config.hidden_size,
|
| 68 |
+
output_size=config.output_size,
|
| 69 |
+
num_layers=config.num_layers,
|
| 70 |
+
nhead=config.nhead,
|
| 71 |
+
seq_length=config.seq_length,
|
| 72 |
+
)
|
| 73 |
+
|
| 74 |
+
def forward(self, x, **kwargs):
|
| 75 |
+
return self.transformer_model(x)
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
config = TransformerConfig(
|
| 79 |
+
input_size=12,
|
| 80 |
+
hidden_size=64,
|
| 81 |
+
output_size=12,
|
| 82 |
+
num_layers=2,
|
| 83 |
+
nhead=4,
|
| 84 |
+
seq_length=450,
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
model = HuggingFaceTransformer(config)
|
| 88 |
+
|
| 89 |
+
def train(
|
| 90 |
+
n_epochs,
|
| 91 |
+
model,
|
| 92 |
+
opt,
|
| 93 |
+
scheduler,
|
| 94 |
+
loss_fn,
|
| 95 |
+
train_loader,
|
| 96 |
+
save_path="./model_checkpoint.pt"
|
| 97 |
+
):
|
| 98 |
+
best_val_loss = float("inf")
|
| 99 |
+
training_history = {"train_loss": [], "val_loss": []}
|
| 100 |
+
|
| 101 |
+
for epoch in range(n_epochs):
|
| 102 |
+
model.train() # Set model to training mode
|
| 103 |
+
train_loss = 0.0
|
| 104 |
+
n_train_batch = len(train_loader)
|
| 105 |
+
|
| 106 |
+
# Training Loop
|
| 107 |
+
with tqdm(total=n_train_batch, desc=f"Epoch {epoch+1}/{n_epochs}", unit="batch") as bar:
|
| 108 |
+
for i, (inputs, targets) in enumerate(train_loader):
|
| 109 |
+
inputs, targets = inputs.to(next(model.parameters()).device), targets.to(next(model.parameters()).device)
|
| 110 |
+
|
| 111 |
+
# Forward pass
|
| 112 |
+
outputs = model(inputs)
|
| 113 |
+
loss = loss_fn(outputs, targets)
|
| 114 |
+
|
| 115 |
+
# Backward pass
|
| 116 |
+
opt.zero_grad()
|
| 117 |
+
loss.backward()
|
| 118 |
+
opt.step()
|
| 119 |
+
|
| 120 |
+
train_loss += loss.item()
|
| 121 |
+
|
| 122 |
+
# Update the progress bar
|
| 123 |
+
avg_train_loss = train_loss / (i + 1)
|
| 124 |
+
bar.set_postfix({"Train Loss": avg_train_loss})
|
| 125 |
+
bar.update(1)
|
| 126 |
+
|
| 127 |
+
# Step the scheduler after the epoch
|
| 128 |
+
scheduler.step()
|
| 129 |
+
|
| 130 |
+
# Log training loss
|
| 131 |
+
training_history["train_loss"].append(train_loss / n_train_batch)
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
# Plot Predictions Every Epoch
|
| 135 |
+
if epoch % 1 == 0:
|
| 136 |
+
plt.figure(figsize=(10, 6))
|
| 137 |
+
plt.plot(outputs[0, :, 0].detach().cpu(), label="Prediction")
|
| 138 |
+
plt.plot(targets[0, :, 0].detach().cpu(), label="Actual")
|
| 139 |
+
plt.title(f"Epoch {epoch+1} Predictions")
|
| 140 |
+
plt.legend()
|
| 141 |
+
plt.savefig(f"predictions_epoch_{epoch+1}.png")
|
| 142 |
+
plt.close()
|
| 143 |
+
|
| 144 |
+
print(f"Epoch {epoch+1}/{n_epochs} Completed. Train Loss: {avg_train_loss:.6f}")
|
| 145 |
+
|
| 146 |
+
# Return the training history for analysis
|
| 147 |
+
return training_history
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def setup_data(data, batch_size):
|
| 152 |
+
train_split = int(0.85 * len(data['x']))
|
| 153 |
+
X = data['x']
|
| 154 |
+
y = data['y']
|
| 155 |
+
|
| 156 |
+
X_train = X[:train_split]
|
| 157 |
+
y_train = y[:train_split]
|
| 158 |
+
X_val = X[train_split:]
|
| 159 |
+
y_val = y[train_split:]
|
| 160 |
+
|
| 161 |
+
def normalize_dataset(data):
|
| 162 |
+
data_min = data.amin(dim=(0, 1), keepdim=True)
|
| 163 |
+
data_max = data.amax(dim=(0, 1), keepdim=True)
|
| 164 |
+
normalized_data = (data - data_min) / (data_max - data_min + 1e-8)
|
| 165 |
+
return normalized_data
|
| 166 |
+
|
| 167 |
+
X_train_norm = normalize_dataset(X_train)
|
| 168 |
+
y_train_norm = normalize_dataset(y_train)
|
| 169 |
+
X_val_norm = normalize_dataset(X_val)
|
| 170 |
+
y_val_norm = normalize_dataset(y_val)
|
| 171 |
+
|
| 172 |
+
train_dataset = TensorDataset(X_train_norm, y_train_norm)
|
| 173 |
+
val_dataset = TensorDataset(X_val_norm, y_val_norm)
|
| 174 |
+
|
| 175 |
+
train_loader = DataLoader(
|
| 176 |
+
train_dataset,
|
| 177 |
+
batch_size=batch_size,
|
| 178 |
+
shuffle=True,
|
| 179 |
+
collate_fn=lambda x: tuple(x_.to(device) for x_ in default_collate(x)),
|
| 180 |
+
)
|
| 181 |
+
return train_loader
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
if __name__ == "__main__":
|
| 185 |
+
device = torch.device('cuda:1')
|
| 186 |
+
raw_data = torch.load('../../data/processed/striding/data.pt')
|
| 187 |
+
|
| 188 |
+
train_loader = setup_data(data=raw_data, batch_size=2048)
|
| 189 |
+
|
| 190 |
+
lr = 0.001
|
| 191 |
+
adam = torch.optim.Adam(model.parameters(), lr=lr)
|
| 192 |
+
linear_scheduler = lr_scheduler.LinearLR(adam, start_factor=1.0, end_factor=0.5, total_iters=30)
|
| 193 |
+
|
| 194 |
+
history = train(
|
| 195 |
+
n_epochs=100,
|
| 196 |
+
model=model,
|
| 197 |
+
opt=adam,
|
| 198 |
+
scheduler=linear_scheduler,
|
| 199 |
+
loss_fn=torch.nn.HuberLoss(),
|
| 200 |
+
train_loader=train_loader,
|
| 201 |
+
save_path="./best_model.pt"
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
# Save final model
|
| 205 |
+
torch.save(model.state_dict(), "./final_model.pt")
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
|
sensor_calibration_data
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
1
|
| 2 |
+
0.0136, -0.008133, 0.0043
|
| 3 |
+
|
| 4 |
+
2
|
| 5 |
+
0.0049, 0.0006, -0.0086
|
| 6 |
+
0.0006, 0.0037, -0.0122
|
| 7 |
+
0.0055, 0.0012, -0.0098
|
| 8 |
+
|
| 9 |
+
3
|
| 10 |
+
0.0086, -0.0012, 0.0031
|
| 11 |
+
0.0086, 0.0000, 0.0031
|
| 12 |
+
0.0086, 0.0000, 0.0024
|
| 13 |
+
|
| 14 |
+
4
|
| 15 |
+
0.0000, -0.0031, 0.0061
|
| 16 |
+
0.0000, -0.0037, 0.0061
|
| 17 |
+
0.0000, -0.0037, 0.0061
|
| 18 |
+
|
| 19 |
+
5
|
| 20 |
+
0.0073, -0.0079, 0.0024
|
| 21 |
+
0.0067, -0.0079, 0.0024
|
| 22 |
+
0.0073, -0.0079, 0.0024
|
| 23 |
+
|
| 24 |
+
7
|
| 25 |
+
-0.0012, -0.0049, -0.0159
|
| 26 |
+
-0.0012, -0.0049, -0.0147
|
| 27 |
+
-0.0012, -0.0049, -0.0153
|
| 28 |
+
|
| 29 |
+
9
|
| 30 |
+
0.0018, -0.0061, 0.0000
|
| 31 |
+
0.0012, -0.0061, 0.0000
|
| 32 |
+
0.0018, -0.0061, -0.0006
|
| 33 |
+
|
| 34 |
+
10
|
| 35 |
+
0.0086, -0.0079, -0.0006
|
| 36 |
+
|
| 37 |
+
11
|
| 38 |
+
-0.0073, -0.0073, -0.0012
|