James Kuszmaul | 5f5e123 | 2020-12-22 20:58:00 -0800 | [diff] [blame] | 1 | // This script provides a basic utility for de-batching the IMUValues |
| 2 | // message. See imu_plotter.ts for usage. |
James Kuszmaul | dac091f | 2022-03-22 09:35:06 -0700 | [diff] [blame] | 3 | import {IMUValuesBatch} from 'org_frc971/frc971/wpilib/imu_batch_generated'; |
James Kuszmaul | 5f5e123 | 2020-12-22 20:58:00 -0800 | [diff] [blame] | 4 | import {MessageHandler, TimestampedMessage} from 'org_frc971/aos/network/www/aos_plotter'; |
James Kuszmaul | 0d7df89 | 2021-04-09 22:19:49 -0700 | [diff] [blame] | 5 | import {Point} from 'org_frc971/aos/network/www/plotter'; |
James Kuszmaul | 5f5e123 | 2020-12-22 20:58:00 -0800 | [diff] [blame] | 6 | import {Table} from 'org_frc971/aos/network/www/reflection'; |
James Kuszmaul | dac091f | 2022-03-22 09:35:06 -0700 | [diff] [blame] | 7 | import {ByteBuffer} from 'flatbuffers'; |
| 8 | import {Schema} from 'org_frc971/external/com_github_google_flatbuffers/reflection/reflection_generated'; |
James Kuszmaul | 5f5e123 | 2020-12-22 20:58:00 -0800 | [diff] [blame] | 9 | |
James Kuszmaul | ac2b6b4 | 2021-03-07 22:38:06 -0800 | [diff] [blame] | 10 | const FILTER_WINDOW_SIZE = 100; |
| 11 | |
James Kuszmaul | 5f5e123 | 2020-12-22 20:58:00 -0800 | [diff] [blame] | 12 | export class ImuMessageHandler extends MessageHandler { |
James Kuszmaul | ac2b6b4 | 2021-03-07 22:38:06 -0800 | [diff] [blame] | 13 | // Calculated magnitude of the measured acceleration from the IMU. |
James Kuszmaul | 0d7df89 | 2021-04-09 22:19:49 -0700 | [diff] [blame] | 14 | private acceleration_magnitudes: Point[] = []; |
James Kuszmaul | 5f5e123 | 2020-12-22 20:58:00 -0800 | [diff] [blame] | 15 | constructor(private readonly schema: Schema) { |
| 16 | super(schema); |
| 17 | } |
James Kuszmaul | dac091f | 2022-03-22 09:35:06 -0700 | [diff] [blame] | 18 | private readScalar(table: Table, fieldName: string): number|BigInt|null { |
James Kuszmaul | ac2b6b4 | 2021-03-07 22:38:06 -0800 | [diff] [blame] | 19 | return this.parser.readScalar(table, fieldName); |
| 20 | } |
James Kuszmaul | 5f5e123 | 2020-12-22 20:58:00 -0800 | [diff] [blame] | 21 | addMessage(data: Uint8Array, time: number): void { |
James Kuszmaul | dac091f | 2022-03-22 09:35:06 -0700 | [diff] [blame] | 22 | const batch = IMUValuesBatch.getRootAsIMUValuesBatch(new ByteBuffer(data)); |
James Kuszmaul | 5f5e123 | 2020-12-22 20:58:00 -0800 | [diff] [blame] | 23 | for (let ii = 0; ii < batch.readingsLength(); ++ii) { |
| 24 | const message = batch.readings(ii); |
| 25 | const table = Table.getNamedTable( |
James Kuszmaul | dac091f | 2022-03-22 09:35:06 -0700 | [diff] [blame] | 26 | message.bb, this.schema, 'frc971.IMUValues', message.bb_pos); |
James Kuszmaul | 5f5e123 | 2020-12-22 20:58:00 -0800 | [diff] [blame] | 27 | if (this.parser.readScalar(table, "monotonic_timestamp_ns") == null) { |
| 28 | console.log('Ignoring unpopulated IMU values: '); |
| 29 | console.log(this.parser.toObject(table)); |
| 30 | continue; |
| 31 | } |
James Kuszmaul | dac091f | 2022-03-22 09:35:06 -0700 | [diff] [blame] | 32 | const time = Number(message.monotonicTimestampNs()) * 1e-9; |
James Kuszmaul | ac2b6b4 | 2021-03-07 22:38:06 -0800 | [diff] [blame] | 33 | this.messages.push(new TimestampedMessage(table, time)); |
James Kuszmaul | 0d7df89 | 2021-04-09 22:19:49 -0700 | [diff] [blame] | 34 | this.acceleration_magnitudes.push(new Point( |
| 35 | time, |
| 36 | Math.hypot( |
| 37 | message.accelerometerX(), message.accelerometerY(), |
| 38 | message.accelerometerZ()))); |
James Kuszmaul | ac2b6b4 | 2021-03-07 22:38:06 -0800 | [diff] [blame] | 39 | } |
| 40 | } |
| 41 | |
| 42 | // Computes a moving average for a given input, using a basic window centered |
| 43 | // on each value. |
James Kuszmaul | 0d7df89 | 2021-04-09 22:19:49 -0700 | [diff] [blame] | 44 | private movingAverageCentered(input: Point[]): Point[] { |
| 45 | const num_measurements = input.length; |
| 46 | const filtered_measurements = []; |
James Kuszmaul | ac2b6b4 | 2021-03-07 22:38:06 -0800 | [diff] [blame] | 47 | for (let ii = 0; ii < num_measurements; ++ii) { |
| 48 | let sum = 0; |
| 49 | let count = 0; |
| 50 | for (let jj = Math.max(0, Math.ceil(ii - FILTER_WINDOW_SIZE / 2)); |
| 51 | jj < Math.min(num_measurements, ii + FILTER_WINDOW_SIZE / 2); ++jj) { |
James Kuszmaul | 0d7df89 | 2021-04-09 22:19:49 -0700 | [diff] [blame] | 52 | sum += input[jj].y; |
James Kuszmaul | ac2b6b4 | 2021-03-07 22:38:06 -0800 | [diff] [blame] | 53 | ++count; |
| 54 | } |
James Kuszmaul | 0d7df89 | 2021-04-09 22:19:49 -0700 | [diff] [blame] | 55 | filtered_measurements.push(new Point(input[ii].x, sum / count)); |
James Kuszmaul | ac2b6b4 | 2021-03-07 22:38:06 -0800 | [diff] [blame] | 56 | } |
James Kuszmaul | 0d7df89 | 2021-04-09 22:19:49 -0700 | [diff] [blame] | 57 | return filtered_measurements; |
James Kuszmaul | ac2b6b4 | 2021-03-07 22:38:06 -0800 | [diff] [blame] | 58 | } |
| 59 | |
James Kuszmaul | 0d7df89 | 2021-04-09 22:19:49 -0700 | [diff] [blame] | 60 | getField(field: string[]): Point[] { |
James Kuszmaul | ac2b6b4 | 2021-03-07 22:38:06 -0800 | [diff] [blame] | 61 | // Any requested input that ends with "_filtered" will get a moving average |
| 62 | // applied to the original field. |
| 63 | const filtered_suffix = "_filtered"; |
| 64 | if (field[0] == "acceleration_magnitude") { |
James Kuszmaul | 0d7df89 | 2021-04-09 22:19:49 -0700 | [diff] [blame] | 65 | return this.acceleration_magnitudes; |
James Kuszmaul | ac2b6b4 | 2021-03-07 22:38:06 -0800 | [diff] [blame] | 66 | } else if (field[0].endsWith(filtered_suffix)) { |
| 67 | return this.movingAverageCentered(this.getField( |
| 68 | [field[0].slice(0, field[0].length - filtered_suffix.length)])); |
| 69 | } else { |
| 70 | return super.getField(field); |
James Kuszmaul | 5f5e123 | 2020-12-22 20:58:00 -0800 | [diff] [blame] | 71 | } |
| 72 | } |
| 73 | } |