| // Provides a plot for debugging robot state-related issues. |
| import {AosPlotter} from '../../../aos/network/www/aos_plotter'; |
| import * as proxy from '../../../aos/network/www/proxy'; |
| import * as configuration from '../../../aos/configuration_generated'; |
| import {BLUE, BROWN, CYAN, GREEN, PINK, RED, WHITE} from '../../../aos/network/www/colors'; |
| import {MessageHandler, TimestampedMessage} from '../../../aos/network/www/aos_plotter'; |
| import {Point} from '../../../aos/network/www/plotter'; |
| import {Table} from '../../../aos/network/www/reflection'; |
| import {ByteBuffer} from 'flatbuffers'; |
| import {Schema} from 'flatbuffers_reflection/reflection_generated'; |
| |
| import Connection = proxy.Connection; |
| |
| const TIME = AosPlotter.TIME; |
| |
| class DerivativeMessageHandler extends MessageHandler { |
| // Calculated magnitude of the measured acceleration from the IMU. |
| private acceleration_magnitudes: Point[] = []; |
| constructor(private readonly schema: Schema) { |
| super(schema); |
| } |
| private readScalar(table: Table, fieldName: string): number|BigInt|null { |
| return this.parser.readScalar(table, fieldName); |
| } |
| |
| // Computes a numerical derivative for a given input. |
| private derivative(input: Point[]): Point[] { |
| const num_measurements = input.length; |
| const results = []; |
| for (let ii = 0; ii < num_measurements - 1; ++ii) { |
| const x0 = input[ii].x; |
| const x1 = input[ii + 1].x; |
| const y0 = input[ii].y; |
| const y1 = input[ii + 1].y; |
| results.push(new Point((x0 + x1) / 2.0, (y1 - y0) / (x1 - x0))); |
| } |
| return results; |
| } |
| |
| getField(field: string[]): Point[] { |
| // Any requested input that ends with "_derivative" will get a derivative |
| // calculated for the provided field. |
| const derivative_suffix = "_derivative"; |
| const num_fields = field.length; |
| const end_field = field[num_fields - 1]; |
| if (end_field.endsWith(derivative_suffix)) { |
| const field_copy = []; |
| for (let ii = 0; ii < num_fields - 1; ++ii) { |
| field_copy.push(field[ii]); |
| } |
| field_copy.push(end_field.slice(0, end_field.length - derivative_suffix.length)); |
| return this.derivative(this.getField(field_copy)); |
| } else { |
| return super.getField(field); |
| } |
| } |
| } |
| |
| export function plotTurret(conn: Connection, element: Element) : void { |
| const aosPlotter = new AosPlotter(conn); |
| const goal = aosPlotter.addMessageSource('/superstructure', 'y2020.control_loops.superstructure.Goal'); |
| const output = aosPlotter.addMessageSource('/superstructure', 'y2020.control_loops.superstructure.Output'); |
| const status = aosPlotter.addRawMessageSource( |
| '/superstructure', 'y2020.control_loops.superstructure.Status', |
| new DerivativeMessageHandler(conn.getSchema('y2020.control_loops.superstructure.Status')) |
| ); |
| const pdpValues = |
| aosPlotter.addMessageSource('/roborio/aos', 'frc971.PDPValues'); |
| const localizerDebug = |
| aosPlotter.addMessageSource('/drivetrain', 'y2020.control_loops.drivetrain.LocalizerDebug'); |
| |
| const turretPosPlot = aosPlotter.addPlot(element); |
| turretPosPlot.plot.getAxisLabels().setTitle('Turret Position'); |
| turretPosPlot.plot.getAxisLabels().setXLabel(TIME); |
| turretPosPlot.plot.getAxisLabels().setYLabel('rad'); |
| |
| turretPosPlot.addMessageLine(status, ['aimer', 'turret_position']) |
| .setColor(RED) |
| .setPointSize(0.0); |
| turretPosPlot.addMessageLine(status, ['turret', 'position']) |
| .setColor(GREEN) |
| .setPointSize(0.0); |
| turretPosPlot.addMessageLine(localizerDebug, ['matches[]', 'implied_turret_goal']) |
| .setColor(GREEN) |
| .setDrawLine(false); |
| turretPosPlot.addMessageLine(status, ['turret', 'unprofiled_goal_position']) |
| .setColor(BLUE) |
| .setDrawLine(false); |
| |
| const turretVelPlot = aosPlotter.addPlot(element); |
| turretVelPlot.plot.getAxisLabels().setTitle('Turret Velocity'); |
| turretVelPlot.plot.getAxisLabels().setXLabel(TIME); |
| turretVelPlot.plot.getAxisLabels().setYLabel('rad / sec'); |
| |
| turretVelPlot.addMessageLine(status, ['aimer', 'turret_velocity']) |
| .setColor(RED) |
| .setPointSize(0.0); |
| turretVelPlot.addMessageLine(status, ['turret', 'velocity']) |
| .setColor(GREEN) |
| .setPointSize(0.0); |
| turretVelPlot.addMessageLine(status, ['turret', 'unprofiled_goal_velocity']) |
| .setColor(BLUE) |
| .setDrawLine(false); |
| |
| const turretAccelPlot = aosPlotter.addPlot(element); |
| turretAccelPlot.plot.getAxisLabels().setTitle('Turret Acceleration'); |
| turretAccelPlot.plot.getAxisLabels().setXLabel(TIME); |
| turretAccelPlot.plot.getAxisLabels().setYLabel('rad / sec / sec'); |
| |
| turretAccelPlot.addMessageLine(status, ['aimer', 'turret_velocity_derivative']) |
| .setColor(RED) |
| .setPointSize(0.0); |
| |
| const turretVoltagePlot = aosPlotter.addPlot(element); |
| turretVoltagePlot.plot.getAxisLabels().setTitle('Turret Voltage'); |
| turretVoltagePlot.plot.getAxisLabels().setXLabel(TIME); |
| turretVoltagePlot.plot.getAxisLabels().setYLabel('V'); |
| |
| turretVoltagePlot.addMessageLine(status, ['turret', 'voltage_error']) |
| .setColor(GREEN) |
| .setPointSize(0.0); |
| turretVoltagePlot.addMessageLine(status, ['turret', 'position_power']) |
| .setColor(BLUE) |
| .setPointSize(0.0); |
| turretVoltagePlot.addMessageLine(status, ['turret', 'velocity_power']) |
| .setColor(CYAN) |
| .setPointSize(0.0); |
| turretVoltagePlot.addMessageLine(output, ['turret_voltage']) |
| .setColor(RED) |
| .setPointSize(0.0); |
| |
| const currentPlot = aosPlotter.addPlot(element); |
| currentPlot.plot.getAxisLabels().setTitle('Current'); |
| currentPlot.plot.getAxisLabels().setXLabel(TIME); |
| currentPlot.plot.getAxisLabels().setYLabel('Amps'); |
| currentPlot.plot.setDefaultYRange([0.0, 40.0]); |
| |
| currentPlot.addMessageLine(pdpValues, ['currents[6]']) |
| .setColor(GREEN) |
| .setPointSize(0.0); |
| |
| |
| const targetDistancePlot = aosPlotter.addPlot(element); |
| targetDistancePlot.plot.getAxisLabels().setTitle('Target distance'); |
| targetDistancePlot.plot.getAxisLabels().setXLabel(TIME); |
| targetDistancePlot.plot.getAxisLabels().setYLabel('m'); |
| |
| targetDistancePlot.addMessageLine(status, ['aimer', 'target_distance']) |
| .setColor(RED) |
| .setPointSize(0.0); |
| |
| const targetChoicePlot = aosPlotter.addPlot(element); |
| targetChoicePlot.plot.getAxisLabels().setTitle('Target choice'); |
| targetChoicePlot.plot.getAxisLabels().setXLabel(TIME); |
| targetChoicePlot.plot.getAxisLabels().setYLabel('[bool]'); |
| targetChoicePlot.plot.setDefaultYRange([-0.05, 1.05]); |
| |
| targetChoicePlot.addMessageLine(status, ['aimer', 'aiming_for_inner_port']) |
| .setColor(RED) |
| .setPointSize(0.0); |
| |
| const imageAcceptedPlot = aosPlotter.addPlot(element); |
| imageAcceptedPlot.plot.getAxisLabels().setTitle('Image Acceptance'); |
| imageAcceptedPlot.plot.getAxisLabels().setXLabel(TIME); |
| imageAcceptedPlot.plot.getAxisLabels().setYLabel('[bool]'); |
| imageAcceptedPlot.plot.setDefaultYRange([-0.05, 1.05]); |
| |
| imageAcceptedPlot.addMessageLine(localizerDebug, ['matches[]', 'accepted']) |
| .setColor(RED) |
| .setDrawLine(false); |
| } |