75 lines
5.6 KiB
JavaScript
75 lines
5.6 KiB
JavaScript
import { parseIni } from "./ini-parser.mjs";
|
|
import { WorkspaceRuntime } from "./runtime.mjs";
|
|
import { machineDefinition } from "./machine-definitions.mjs";
|
|
import { readTrtGeometry } from "./trt-geometry.mjs";
|
|
import { WEB_SETTINGS } from "./web-settings.mjs";
|
|
|
|
const NUMBER = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
// ABI capacity constraints from sim_io.h and sim_device_io.h, not machine defaults.
|
|
const IO_CAPACITY = Object.freeze({ spindle_count: 8, tool_capacity: 1001, encoder_count: 8 });
|
|
export function readTrtConfiguration(configuration) {
|
|
const machine = machineDefinition(configuration.entrypoint);
|
|
if (!machine) throw new Error("trt_configuration_machine_missing");
|
|
const parsed = parseIni({ workspace: new WorkspaceRuntime({ files: configuration.files }), entrypoint: configuration.entrypoint });
|
|
const sections = parsed.sections;
|
|
const number = (section, key, { positive = false, fallback } = {}) => {
|
|
const raw = sections[section]?.[key];
|
|
if (raw === undefined && fallback !== undefined) return fallback;
|
|
if (typeof raw !== "string" || !NUMBER.test(raw) || !Number.isFinite(Number(raw)) || positive && Number(raw) <= 0) throw new Error(`trt_configuration_number:[${section}]${key}`);
|
|
return Number(raw);
|
|
};
|
|
const geometry = readTrtGeometry(configuration);
|
|
const coordinates = sections.TRAJ.COORDINATES.replace(/\s/g, "").toUpperCase();
|
|
const axes = [...coordinates.toLowerCase()];
|
|
const jointCount = number("KINS", "JOINTS", { positive: true });
|
|
if (jointCount !== axes.length) throw new Error("trt_configuration_joint_count");
|
|
if (sections.TRAJ.LINEAR_UNITS !== "mm" || sections.TRAJ.ANGULAR_UNITS !== "deg") throw new Error("trt_configuration_units_unsupported");
|
|
if (!/\bsparm=identityfirst\b/.test(sections.KINS.KINEMATICS)) throw new Error("trt_configuration_requires_identityfirst");
|
|
const limits = (section) => {
|
|
const range = [number(section, "MIN_LIMIT"), number(section, "MAX_LIMIT")];
|
|
if (range[0] >= range[1]) throw new Error(`trt_configuration_limits:${section}`);
|
|
return range;
|
|
};
|
|
const jointLimits = {}, axisLimits = {}, velocity = {}, acceleration = {};
|
|
for (const [joint, axis] of axes.entries()) {
|
|
jointLimits[axis] = limits(`JOINT_${joint}`);
|
|
axisLimits[axis] = limits(`AXIS_${axis.toUpperCase()}`);
|
|
velocity[axis] = number(`AXIS_${axis.toUpperCase()}`, "MAX_VELOCITY", { positive: true });
|
|
acceleration[axis] = number(`AXIS_${axis.toUpperCase()}`, "MAX_ACCELERATION", { positive: true });
|
|
number(`JOINT_${joint}`, "MAX_VELOCITY", { positive: true });
|
|
number(`JOINT_${joint}`, "MAX_ACCELERATION", { positive: true });
|
|
for (const key of ["HOME", "HOME_OFFSET", "HOME_FINAL_VEL", "HOME_SEARCH_VEL", "HOME_LATCH_VEL", "HOME_SEQUENCE"]) if (sections[`JOINT_${joint}`][key] !== undefined) number(`JOINT_${joint}`, key);
|
|
}
|
|
const servo = number("EMCMOT", "SERVO_PERIOD", { positive: true }) / 1e9;
|
|
const task = number("TASK", "CYCLE_TIME", { positive: true });
|
|
const ticks = task / servo;
|
|
if (!Number.isSafeInteger(Math.round(ticks)) || ticks < 1 || Math.abs(ticks - Math.round(ticks)) > 1e-9) throw new Error("trt_configuration_task_servo_ratio");
|
|
if (servo > 60 || task > 10) throw new Error("trt_configuration_cycle_capacity");
|
|
const maxFeed = number("DISPLAY", "MAX_FEED_OVERRIDE", { positive: true });
|
|
if (maxFeed < 1) throw new Error("trt_configuration_feed_override");
|
|
const blendKeys = { enable: "ARC_BLEND_ENABLE", fallback_enable: "ARC_BLEND_FALLBACK_ENABLE", optimization_depth: "ARC_BLEND_OPTIMIZATION_DEPTH", gap_cycles: "ARC_BLEND_GAP_CYCLES", ramp_frequency: "ARC_BLEND_RAMP_FREQ", tangent_kink_ratio: "ARC_BLEND_TANGENT_KINK_RATIO" };
|
|
const blend = Object.fromEntries(Object.entries(blendKeys).map(([key, iniKey]) => [key, number("TRAJ", iniKey, { fallback: WEB_SETTINGS.runtime.planner.blend[key] })]));
|
|
if (![0, 1].includes(blend.enable) || ![0, 1].includes(blend.fallback_enable) || !Number.isSafeInteger(blend.optimization_depth) || blend.optimization_depth < 1 || !Number.isSafeInteger(blend.gap_cycles) || blend.gap_cycles < 0 || blend.ramp_frequency <= 0 || blend.tangent_kink_ratio <= 0) throw new Error("trt_configuration_blend");
|
|
const io = { ...Object.fromEntries(Object.entries(WEB_SETTINGS.runtime.io).filter(([key]) => key !== "cycle_time").map(([key, fallback]) => [key, number("WEB_RUNTIME", key.toUpperCase(), { positive: key !== "spindle_tolerance", fallback })])), cycle_time: task };
|
|
if (io.spindle_tolerance < 0) throw new Error("trt_configuration_spindle_tolerance");
|
|
for (const [key, maximum] of Object.entries(IO_CAPACITY)) if (!Number.isSafeInteger(io[key]) || io[key] < 1 || io[key] > maximum) throw new Error(`trt_configuration_io_capacity:${key}`);
|
|
const defaultAcceleration = number("TRAJ", "DEFAULT_LINEAR_ACCELERATION", { positive: true });
|
|
const maxAcceleration = number("TRAJ", "MAX_LINEAR_ACCELERATION", { positive: true });
|
|
return {
|
|
home_limits: { joint_count: jointCount, kinematics_type: machine.kinematics_type, coordinates, ...jointLimits },
|
|
kinematics: {
|
|
type: machine.id, path_mode: "wasm", coordinates, joint_count: jointCount, offsets: geometry.offsets,
|
|
ini_hash: parsed.state_hash,
|
|
servo_cycle_time: servo, cycle_time: servo, task_cycle_time: task,
|
|
max_linear_velocity: number("TRAJ", "MAX_LINEAR_VELOCITY", { positive: true }),
|
|
max_acceleration: Math.min(defaultAcceleration, maxAcceleration),
|
|
max_linear_acceleration: maxAcceleration,
|
|
axis_limits: axisLimits, axis_velocity_limits: velocity, axis_acceleration_limits: acceleration,
|
|
max_feed_override: maxFeed,
|
|
blend,
|
|
io,
|
|
switchkins: { 0: "identity", 1: coordinates.toLowerCase(), 2: "userk" },
|
|
},
|
|
};
|
|
}
|