CI Log in

zach/dotter

test/models.test.js 115 lines · 4.3 KB · javascript
1
import { describe, expect, test } from 'bun:test';
2
import { NextDraw } from '../src/nextdraw.js';
3
import { penLiftTimes, servoSettings } from '../src/pen.js';
4
import { calcJerk } from '../src/plan.js';
5
6
function nd(configure) {
7
  const n = new NextDraw({ log: () => {} });
8
  n.interactive();
9
  configure?.(n);
10
  n.updateOptions();
11
  return n;
12
}
13
14
describe('model and handling parameters', () => {
15
  test('NextDraw 8511 defaults (Technical drawing)', () => {
16
    const n = nd();
17
    expect(n.params.modelName).toBe('Bantam Tools NextDraw™ 8511');
18
    expect(n.params.travelX).toBe(11.81);
19
    expect(n.params.travelY).toBe(8.58);
20
    expect(n.params.autoHome).toBe(true);
21
    expect(n.params.resolution).toBe(1);
22
    expect(n.params.speedLimit).toBe(8.6979);
23
    expect(n.params.speedUp).toBe(8.6979);
24
    expect(n.params.jerkPenDown).toBe(20000);
25
    expect(n.params.jerkPenUp).toBe(19000);
26
    expect(n.params.constSpeed).toBe(false);
27
    // Brushless narrow-band pen-lift servo on pin B2
28
    expect(n.params.zMotor).toBe(1);
29
    expect(n.params.servoPin).toBe(2);
30
    expect([n.params.servoMin, n.params.servoMax]).toEqual([5400, 12600]);
31
    expect(n.bounds).toEqual([[-1e-9, -1e-9], [11.81 + 1e-9, 8.58 + 1e-9]]);
32
  });
33
34
  test('handling modes', () => {
35
    const hw = nd((n) => { n.options.handling = 2; });
36
    expect(hw.params.resolution).toBe(2);
37
    expect(hw.params.speedLimit).toBe(7);
38
    expect(hw.params.speedUp).toBe(12);
39
    expect(hw.params.jerkPenDown).toBe(90000);
40
    expect(hw.params.jerkPenUp).toBe(13000);
41
42
    const sk = nd((n) => { n.options.handling = 3; });
43
    expect(sk.params.speedLimit).toBe(12);
44
45
    const cs = nd((n) => { n.options.handling = 4; });
46
    expect(cs.params.constSpeed).toBe(true);
47
    expect(cs.params.speedLimit).toBe(3.0);
48
    expect(cs.params.resolution).toBe(1);
49
  });
50
51
  test('other models and pen-lift options', () => {
52
    const a3 = nd((n) => { n.options.model = 2; });
53
    expect(a3.params.autoHome).toBe(false);
54
    expect(a3.params.zMotor).toBe(0);
55
    expect(a3.params.servoPin).toBe(1);
56
57
    const upgraded = nd((n) => { n.options.model = 1; n.options.penlift = 3; });
58
    expect(upgraded.params.zMotor).toBe(1);
59
60
    const big = nd((n) => { n.options.model = 10; n.options.handling = 1; });
61
    expect(big.params.travelX).toBe(34.02);
62
    expect(big.params.jerkPenDown).toBeCloseTo(20000 * 0.6, 9);
63
  });
64
65
  test('overrides are applied after model defaults', () => {
66
    const n = nd((x) => { x.params.overrides.travelX = 5; x.params.overrides.speedLimit = 4; });
67
    expect(n.params.travelX).toBe(5);
68
    expect(n.params.speedLimit).toBe(4);
69
    expect(n.bounds[1][0]).toBeCloseTo(5, 6);
70
  });
71
72
  test('invalid model is rejected', () => {
73
    expect(() => nd((n) => { n.options.model = 11; })).toThrow();
74
  });
75
76
  test('options are clamped to their documented ranges', () => {
77
    const n = nd((x) => { x.options.penPosUp = 150; x.options.speedPendown = 0; x.options.accel = -5; });
78
    expect(n.options.penPosUp).toBe(100);
79
    expect(n.options.speedPendown).toBe(1);
80
    expect(n.options.accel).toBe(1);
81
  });
82
});
83
84
describe('pen servo settings', () => {
85
  test('default positions, rates and lift times', () => {
86
    const n = nd();
87
    expect(servoSettings(n, 40)).toEqual({ rateUp: 231, rateDown: 154, posUp: 9720, posDown: 8280 });
88
    expect(penLiftTimes(n, 40)).toEqual({ raiseTime: 45, lowerTime: 47 });
89
  });
90
91
  test('equal up/down heights need no delay; extra delays are added', () => {
92
    const n = nd((x) => { x.options.penPosDown = 60; });
93
    expect(penLiftTimes(n, 60)).toEqual({ raiseTime: 0, lowerTime: 0 });
94
    const d = nd((x) => { x.params.penDelayUp = 100; x.params.penDelayDown = -1000; });
95
    const t = penLiftTimes(d, 40);
96
    expect(t.raiseTime).toBe(145);
97
    expect(t.lowerTime).toBe(0); // never negative
98
  });
99
100
  test('standard servo uses 8 PWM channels in its rate scale', () => {
101
    const n = nd((x) => { x.options.model = 2; });
102
    // range 17976 * 0.24 / 200 = 21.5712 per %
103
    expect(servoSettings(n, 40)).toEqual({
104
      rateUp: Math.round(21.5712 * 75), rateDown: Math.round(21.5712 * 50),
105
      posUp: Math.round(9855 + 179.76 * 60), posDown: Math.round(9855 + 179.76 * 40),
106
    });
107
  });
108
109
  test('jerk scales with the cube of accel', () => {
110
    const n = nd((x) => { x.options.accel = 50; });
111
    const [up, down] = calcJerk(n);
112
    expect(up).toBeCloseTo(19000 * 0.125, 9);
113
    expect(down).toBeCloseTo(20000 * 0.125, 9);
114
  });
115
});