File size: 1,568 Bytes
26753ca
 
 
 
99e34b4
26753ca
99e34b4
 
 
26753ca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import { Matrix4 } from "three";
import { interpolateTarget } from "../reachy/reachyKinematics.js";

export const EMOTIONS = Object.freeze({
  joy: { sentence: "Oh, you're happy! Me too!", motion: "cheerful1" },
  sadness: { sentence: "Oh, you're sad! Me too!", motion: "sad1" },
  // Reprimand is the official library's angry gesture with a clear head
  // shake; keep the more extreme furious1 recording available in the assets.
  anger: { sentence: "Oh, you're angry! Me too!", motion: "reprimand2" },
});

const matrixFromRows = (rows) => new Matrix4().set(...rows.flat());

export async function loadReachyEmotion(name) {
  const response = await fetch(`./robot/reachy/emotions/${name}.json`);
  if (!response.ok) throw new Error(`Unable to load Reachy emotion ${name}`);
  const source = await response.json();
  const frames = source.time.map((time, i) => {
    const frame = source.set_target_data[i];
    return { time, target: { head: matrixFromRows(frame.head), antennas: [...frame.antennas], bodyYaw: frame.body_yaw } };
  });
  const duration = frames.at(-1)?.time ?? 0;
  return {
    duration,
    sample(seconds) {
      if (!frames.length) throw new Error(`Empty Reachy emotion ${name}`);
      if (seconds <= frames[0].time) return frames[0].target;
      if (seconds >= duration) return frames.at(-1).target;
      let hi = 1;
      while (hi < frames.length && frames[hi].time < seconds) hi++;
      const a = frames[hi - 1], b = frames[hi];
      return interpolateTarget(a.target, b.target, (seconds - a.time) / (b.time - a.time));
    },
  };
}