code wiki / _hdl_build / nx_skill_coach_dance.nx
nx_skill_coach_dance.nx source
↩ module page · 74 lines · 5099 B
1// nx_skill_coach_dance.nx -- SKILL-COACH vision/DANCE vertical, the COACH LOOP (parallel to audio R1). Given pose
2// KEYPOINTS (joint x,y), compute JOINT ANGLES, grade vs a reference pose, diagnose WHICH joint is off (too bent /
3// too straight) -> drill. This is the dance-coach core; the PERCEPTION (camera->keypoints = a sovereign bits-up
4// pose-net) is the RESEARCHER-owned research arc CAP-COACH-POSE -- here keypoints are synthetic (the pose-net is
5// the separate long-pole, exactly as nx_pitch was the separate perception for audio R1). Pure integer (cos via
6// dot/|.|, isqrt; NO floats, NO acos -- compare cosines: larger cos = smaller angle = more bent). license_tier: ORIGINAL
7import "nx_syscalls.nx"
8import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
9const DC_MAGIC_16384: i64 = 16384
10
11const DC_TOL: i64 = 3000 // Q14 cosine-difference tolerance (data-driven; R2 rubric-store could hold it)
12
13func dc_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
14// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
15// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
16// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
17// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
18func dc_putn(v: i64) -> i64 { nxi_out(v); return 0 }
19func dc_isqrt(n: i64) -> i64 {
20 if n <= 0 { return 0 }
21 var x: i64 = n
22 var y: i64 = (x + 1) / 2
23 while y < x { x = y; y = (x + n / x) / 2 }
24 return x
25}
26func dc_jx(p: *i64, j: i64) -> i64 { return p[2 * j] }
27func dc_jy(p: *i64, j: i64) -> i64 { return p[2 * j + 1] }
28// cosine (Q14) of the joint angle at jb, from points ja-jb-jc
29func dc_jcos(p: *i64, ja: i64, jb: i64, jc: i64) -> i64 {
30 let bax: i64 = dc_jx(p, ja) - dc_jx(p, jb)
31 let bay: i64 = dc_jy(p, ja) - dc_jy(p, jb)
32 let bcx: i64 = dc_jx(p, jc) - dc_jx(p, jb)
33 let bcy: i64 = dc_jy(p, jc) - dc_jy(p, jb)
34 let dot: i64 = bax * bcx + bay * bcy
35 let mba: i64 = dc_isqrt(bax * bax + bay * bay)
36 let mbc: i64 = dc_isqrt(bcx * bcx + bcy * bcy)
37 if mba == 0 { return DC_MAGIC_16384 }
38 if mbc == 0 { return DC_MAGIC_16384 }
39 return dot * DC_MAGIC_16384 / (mba * mbc)
40}
41// grade one joint vs the reference pose. verdict: 0 GOOD, 1 TOO-BENT (angle smaller -> cos larger), 2 TOO-STRAIGHT.
42func dc_coach_joint(pose: *i64, ref: *i64, ja: i64, jb: i64, jc: i64, name: *u8) -> i64 {
43 let dcos: i64 = dc_jcos(pose, ja, jb, jc)
44 let rcos: i64 = dc_jcos(ref, ja, jb, jc)
45 let diff: i64 = dcos - rcos
46 dc_puts(" "); dc_puts(name); dc_puts(": cos="); dc_putn(dcos); dc_puts(" vs ref="); dc_putn(rcos); dc_puts(" -> ")
47 if diff > DC_TOL { dc_puts("TOO BENT -> straighten the joint; DRILL: hold the target shape, mirror-check\n" as *u8); return 1 }
48 if diff < (0 - DC_TOL) { dc_puts("TOO STRAIGHT -> bend more to the target; DRILL: slow ramp into the pose\n" as *u8); return 2 }
49 dc_puts("GOOD form -> hold it / advance\n" as *u8); return 0
50}
51func main() -> i64 {
52 dc_puts("SKILL-COACH (dance R1): pose keypoints -> JOINT ANGLES -> grade vs reference -> DIAGNOSE -> DRILL\n" as *u8)
53 // joints: 0 shoulder 1 elbow 2 wrist 3 hip 4 knee 5 ankle. elbow angle=(0,1,2), knee angle=(3,4,5)
54 let ref: *i64 = sys_mmap(8 * 12) as *i64
55 ref[0] = 0; ref[1] = 0; ref[2] = 10; ref[3] = 0; ref[4] = 10; ref[5] = 10
56 ref[6] = 0; ref[7] = 20; ref[8] = 10; ref[9] = 20; ref[10] = 10; ref[11] = 30
57 var pass: i64 = 0
58 // T1: perfect form (= ref) -> elbow GOOD + knee GOOD
59 dc_puts(" [attempt 1: matches the reference pose]\n" as *u8)
60 let p1: *i64 = sys_mmap(8 * 12) as *i64; var i: i64 = 0; while i < 12 { p1[i] = ref[i]; i = i + 1 }
61 if dc_coach_joint(p1, ref, 0, 1, 2, "L-elbow" as *u8) == 0 { if dc_coach_joint(p1, ref, 3, 4, 5, "L-knee" as *u8) == 0 { pass = pass + 1 } }
62 // T2: bent elbow (wrist pulled in toward shoulder) -> elbow TOO BENT, knee GOOD
63 dc_puts(" [attempt 2: elbow over-bent]\n" as *u8)
64 let p2: *i64 = sys_mmap(8 * 12) as *i64; i = 0; while i < 12 { p2[i] = ref[i]; i = i + 1 } p2[4] = 2; p2[5] = 2
65 if dc_coach_joint(p2, ref, 0, 1, 2, "L-elbow" as *u8) == 1 { if dc_coach_joint(p2, ref, 3, 4, 5, "L-knee" as *u8) == 0 { pass = pass + 1 } }
66 // T3: straight knee (leg locked vertical) -> elbow GOOD, knee TOO STRAIGHT
67 dc_puts(" [attempt 3: knee locked straight]\n" as *u8)
68 let p3: *i64 = sys_mmap(8 * 12) as *i64; i = 0; while i < 12 { p3[i] = ref[i]; i = i + 1 } p3[6] = 10; p3[7] = 0; p3[10] = 10; p3[11] = 40
69 if dc_coach_joint(p3, ref, 0, 1, 2, "L-elbow" as *u8) == 0 { if dc_coach_joint(p3, ref, 3, 4, 5, "L-knee" as *u8) == 2 { pass = pass + 1 } }
70 dc_puts(" dance verdicts correct = "); dc_putn(pass); dc_puts("/3\n" as *u8)
71 if pass == 3 { dc_puts("SKILL-COACH-DANCE: GREEN -- pose->joint-angle->diagnose->drill works; the dance-coach loop (perception=the RESEARCHER pose-net arc)\n" as *u8); return 0 }
72 dc_puts("SKILL-COACH-DANCE: RED\n" as *u8)
73 return 1
74}