Konfig in robot.json

This commit is contained in:
chk
2026-06-11 22:05:45 +02:00
parent 05355facf1
commit 66a8e247b5
18 changed files with 1761 additions and 151 deletions

View File

@@ -21,18 +21,19 @@ const MotorPosition = require('./RobotMotorPosition.js')
class RobotBase{
constructor() {
// Umgebungsvariablen-Logik
const DEFAULT_FEEDRATE = process.env.ROBOT_DEFAULT_FEEDRATE ?
Number(process.env.ROBOT_DEFAULT_FEEDRATE) : 1000;
constructor(config = {}) {
// config-Werte haben Vorrang, Env-Variablen als Fallback (Kompatibilität).
const DEFAULT_FEEDRATE = config.defaultFeedrate
?? (process.env.ROBOT_DEFAULT_FEEDRATE ? Number(process.env.ROBOT_DEFAULT_FEEDRATE) : 1000);
// Speed-Regelung-Schalter: 'legacy' (Default — exakt wie bisher) oder 'correct'.
// Siehe doc/ToDo_6a_Speed.md.
this.speedMode = (process.env.ROBOT_SPEED_MODE || 'legacy').toLowerCase();
this.speedMode = (config.speedMode || process.env.ROBOT_SPEED_MODE || 'legacy').toLowerCase();
// ROBOT_USE_SPEED_CALC bleibt der interne Schalter für calculateSpeeds();
// der Korrekt-Modus aktiviert die Berechnung automatisch.
this.useSpeedCalc = this.speedMode === 'correct' ||
process.env.ROBOT_USE_SPEED_CALC === 'true' ||
process.env.ROBOT_USE_SPEED_CALC === '1';
this.useSpeedCalc = config.useSpeedCalc
?? (this.speedMode === 'correct' ||
process.env.ROBOT_USE_SPEED_CALC === 'true' ||
process.env.ROBOT_USE_SPEED_CALC === '1');
/** @type {number} Bewegungszeit des letzten Schritts in Minuten (für koordinierte Feedrate) */
this.lastMoveTime = 0;

101
robot/RobotConfig.js Normal file
View File

@@ -0,0 +1,101 @@
'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'] },
elbow: { ip: 'fluidNcEllbow.local', port: 5000, protocol: 'telnet', axes: ['a', null, null] },
hand: { ip: 'fluidNcHand.local', port: 5000, protocol: 'telnet', axes: ['c', 'e', 'b'] }
}
};
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] ?? {};
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
};
}
function axesByController(key) {
return controllers[key]?.axes ?? [];
}
return { kinematics, motion, controllers, axesByController };
}
module.exports = { load, DEFAULTS };

View File

@@ -20,9 +20,10 @@ class Arm3SegmentLinearX extends RobotBase {
* @param {number} l1 Länge des Oberarms in mm
* @param {number} l2 Länge des Unterarms in mm
* @param {number} l3 Länge der Hand (Endeffector) in mm
* @param {Object} [config] Bewegungs-Config (defaultFeedrate, speedMode, …)
*/
constructor(l1, l2, l3) {
super();
constructor(l1, l2, l3, config = {}) {
super(config);
/** @type {number} Länge des Oberarms in mm */
this.l1 = l1;

View File

@@ -61,7 +61,7 @@ class Arm3SegmentRotaryBase extends RobotBase {
* @param {number} [params.baseHeight=110] Höhe der Schulterachse über der Basis in mm
*/
constructor(l1 = 105, l2 = 98, l3 = 100, params = {}) {
super();
super(params);
/** @type {number} Länge des Oberarms in mm */
this.l1 = l1;