Files
appRobotDriver/robot/RobotConfig.js
2026-06-12 18:16:15 +02:00

118 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
const ROBOT_JSON_PATH = 'data/robot/robot.json';
// Backward-compat env-var names für Controller-IPs (werden in Env als GRBL_ELLBOW_IP gespeichert)
const ENV_IP_MAP = {
base: 'GRBL_BASE_IP',
elbow: 'GRBL_ELLBOW_IP',
hand: 'GRBL_HAND_IP'
};
const DEFAULTS = {
kinematics: { type: 'arm3segmentlinearx', l1: 250, l2: 264, l3: 100 },
motion: { defaultFeedrate: 1000, speedMode: 'legacy', useSpeedCalc: false },
controllers: {
base: { ip: 'fluidNcBase.local', port: 2300, protocol: 'telnet', axes: ['x', 'y', 'z'], heartbeatInterval: 10000 },
elbow: { ip: 'fluidNcEllbow.local', port: 5000, protocol: 'telnet', axes: ['a', null, null], heartbeatInterval: 10000 },
hand: { ip: 'fluidNcHand.local', port: 5000, protocol: 'telnet', axes: ['c', 'e', 'b'], heartbeatInterval: 10000 },
// Shelly Smart Plug: schaltet Strom für Emergency Stop.
// url: null → deaktiviert, wenn nicht in robot.json konfiguriert.
emergencyStop: { protocol: 'shelly', url: null }
}
};
function deriveKinematicParams(links) {
if (!links) return {};
const result = {};
const l1raw = links.Arm1?.skeleton?.to?.[1];
const l2raw = links.Arm2?.skeleton?.to?.[1];
const l3raw = links.Ellbow?.skeleton?.to?.[0];
if (l1raw != null) result.l1 = Math.abs(l1raw);
if (l2raw != null) result.l2 = Math.abs(l2raw);
if (l3raw != null) result.l3 = l3raw;
return result;
}
/**
* Liest robot.json synchron und gibt einen typisierten Config-Record zurück.
* Env-Variablen haben Vorrang vor robot.json (nützlich für Tests und Notfall-Overrides).
*
* @param {Object} [fsModule] - Abhängigkeit (Default: require('fs'))
* @param {Object} [processEnv] - Abhängigkeit (Default: process.env)
* @param {Object} [consoleObj] - Abhängigkeit (Default: console)
* @returns {{ kinematics, motion, controllers, axesByController }}
*/
function load(fsModule, processEnv, consoleObj) {
const fs_ = fsModule ?? require('fs');
const env_ = processEnv ?? process.env;
const log_ = consoleObj ?? console;
let json = null;
try {
const raw = fs_.readFileSync(ROBOT_JSON_PATH, 'utf8');
json = JSON.parse(raw);
} catch {
log_.warn('[RobotConfig] data/robot/robot.json nicht lesbar — nutze Defaults');
}
// Kinematik-Typ und Armlängen (aus links abgeleitet)
const linkParams = deriveKinematicParams(json?.links);
const kinematics = {
type: json?.kinematics?.type ?? DEFAULTS.kinematics.type,
l1: linkParams.l1 ?? DEFAULTS.kinematics.l1,
l2: linkParams.l2 ?? DEFAULTS.kinematics.l2,
l3: linkParams.l3 ?? DEFAULTS.kinematics.l3
};
// Bewegungs-Defaults — Env hat Vorrang, dann robot.json, dann Hard-Default
const jsonMotion = json?.motion ?? {};
const rawFeedrate = env_.ROBOT_DEFAULT_FEEDRATE;
const rawMode = env_.ROBOT_SPEED_MODE;
const rawCalc = env_.ROBOT_USE_SPEED_CALC;
const speedMode = (rawMode || jsonMotion.speedMode || DEFAULTS.motion.speedMode).toLowerCase();
const motion = {
defaultFeedrate: rawFeedrate
? Number(rawFeedrate)
: (jsonMotion.defaultFeedrate ?? DEFAULTS.motion.defaultFeedrate),
speedMode,
useSpeedCalc: speedMode === 'correct' || rawCalc === 'true' || rawCalc === '1'
};
// Controller-Endpunkte — robot.json überschreibt Defaults, Env überschreibt IPs
const jsonControllers = json?.controllers ?? {};
const controllers = {};
for (const key of Object.keys(DEFAULTS.controllers)) {
const def = DEFAULTS.controllers[key];
const cfg = jsonControllers[key] ?? {};
if (def.protocol === 'shelly') {
// Shelly Smart Plug: nur protocol + url nötig (kein IP/Port/Axes/Heartbeat)
controllers[key] = {
protocol: cfg.protocol ?? def.protocol,
url: cfg.url ?? def.url,
};
} else {
// Telnet (FluidNC): IP + Port + Achsen + Heartbeat
const envIpKey = ENV_IP_MAP[key];
controllers[key] = {
ip: env_[envIpKey] ?? cfg.ip ?? def.ip,
port: cfg.port ?? def.port,
protocol: cfg.protocol ?? def.protocol,
axes: cfg.axes ?? def.axes,
// Heartbeat-Intervall in ms: wie oft '?' gesendet wird.
// deadTimeout = 2 × heartbeatInterval (zwei verpasste Heartbeats → Verbindung tot).
heartbeatInterval: cfg.heartbeatInterval ?? def.heartbeatInterval,
};
}
}
function axesByController(key) {
return controllers[key]?.axes ?? [];
}
return { kinematics, motion, controllers, axesByController };
}
module.exports = { load, DEFAULTS };