Files @ 9bb0eb587d5b
Branch filter:

Location: light9/web/calibrate/Light9Calibrate.ts - annotation

drewp@bigasterisk.com
640x480 camera res
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
ae4b90efb55a
import debug from "debug";
import { css, html, LitElement } from "lit";
import { customElement, query, state } from "lit/decorators.js";
import { CollectorClient } from "../collector/CollectorClient";
import { getTopGraph } from "../RdfdbSyncedGraph";
import { SyncedGraph } from "../SyncedGraph";
import { Light9Camera } from "./Light9Camera";
import { XyPlot } from "./XyPlot";
export { RdfdbSyncedGraph } from "../RdfdbSyncedGraph";
export { Light9Camera } from "./Light9Camera";
export { XyPlot } from "./XyPlot";
debug.enable("*");
const log = debug("calibrate");

async function sleep(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

@customElement("light9-calibrate")
export class Light9Calibrate extends LitElement {
  graph!: SyncedGraph;
  static styles = [
    css`
      button {
        min-height: 3em;
        min-width: 10em;
      }
    `,
  ];
  collector: CollectorClient = new CollectorClient("calibrate");
  @query("light9-camera", true) cam?: Light9Camera;
  @query("xy-plot", true) plot?: XyPlot;
  @state() device: string;
  constructor() {
    super();
    this.device = "http://light9.bigasterisk.com/theater/vet/device/parR3";
    getTopGraph().then((g) => {
      this.graph = g;
    });
  }

  render() {
    return html`<rdfdb-synced-graph></rdfdb-synced-graph>
      <h1>Calibrate</h1>
      <light9-camera></light9-camera>

      <p>Device to calibrate: [ ${this.device} ]</p>

      <ol>
        <li><button @click=${this.setToFull}>Set to full</button></li>
        <li><button @click=${this.findSafeExposure}>Find safe exposure</button></li>
        <li><button @click=${this.setToZero}>Set to 0</button></li>
        <li><button @click=${this.markTare}>Mark tare</button></li>
        <li><button @click=${this.calibrateLoop}>Calibrate loop</button></li>
      </ol>
      <xy-plot label="zebra pixels vs exposure"></xy-plot>
      r/g/b/r*g*b lines ,x=send y=seen `;
  }

  async withButtonSpinner(ev: MouseEvent, fn: () => Promise<void>) {
    const btn = ev.target as HTMLButtonElement;
    try {
      btn.disabled = true;
      await fn();
    } finally {
      btn.disabled = false;
    }
  }
  async setToFull(ev: MouseEvent) {
    await this.withButtonSpinner(ev, async () => {
      this.collector.updateSettings([
        /// device,attr,value
        [this.device, "http://light9.bigasterisk.com/color", "#ffffff"],
        [this.device, "http://light9.bigasterisk.com/white", 1],
      ]);
    });
  }

  async findSafeExposure(ev: MouseEvent) {
    await this.withButtonSpinner(ev, async () => {

      const gatherSample = async (expo: number) => {
        await this.cam?.set("exposureTime", expo);
        const settleUntil = Date.now() + 1000;
        let miny = this.cam?.saturatedPixelCount!;
        while (Date.now() < settleUntil) {
          await sleep(50);
          miny = Math.min(miny, this.cam?.saturatedPixelCount!);
        }
        this.plot!.insertPoint(expo, miny);
      };

      // todo: drive around without big skips, gradually slower, looking for the max workable expo
      let fixedSteps = 8;
      const expoMin = 1;
      const expoMax = 200;
      let expo = 0;
      const data=this.plot!.data;
      while (data.length < 20) {
        if (data.length < fixedSteps + 1) {
          expo = expoMin + ((expoMax - expoMin) / fixedSteps) * data.length;
        } else {
          let x2 = data.findIndex(([_, y]) => y > 2);
          if (x2 < 1) x2 = 1;
          const x1 = x2 - 1;
          log(JSON.stringify([x1, data[x1], x2, data[x2]]));
          expo = (data[x1][0] + data[x2][0]) / 2;
          log(data);
        }
        await gatherSample(expo);
      }
    });
  }
  async setToZero(ev: MouseEvent) {
    await this.withButtonSpinner(ev, async () => {
      this.collector.updateSettings([
        [this.device, "http://light9.bigasterisk.com/color", "#000000"],
        [this.device, "http://light9.bigasterisk.com/white", 0],
      ]);
    });
  }
  async markTare(ev: MouseEvent) {
    await this.withButtonSpinner(ev, async () => {});
  }
  async calibrateLoop(ev: MouseEvent) {
    await this.withButtonSpinner(ev, async () => {});
  }
}