按规划持续工作

结论:已纳入 LinuxCNC 五轴 switchkins M428/M429/M430 来源资产,补齐 remap source probe 与 native 验证闭环,未新增自写 CNC 语义。
This commit is contained in:
2026-06-08 15:33:05 +08:00
parent 19687c3268
commit 5df62ad60a
61 changed files with 12160 additions and 4 deletions

View File

@@ -587,3 +587,11 @@ switchable `5axiskins` XYZBCW bridge-mill model, TRT `xyzac`/`xyzbc`
table-rotary models, CoreXY, rotated-axis, rose, max, linear-delta, table-rotary models, CoreXY, rotated-axis, rose, max, linear-delta,
rotary-delta, Scorbot, tripod, SCARA, PUMA, generic serial, generic hexapod, rotary-delta, Scorbot, tripod, SCARA, PUMA, generic serial, generic hexapod,
and pentapod models. and pentapod models.
`linuxcnc_5axis_remap_asset_probe` pins the LinuxCNC sample-machine assets
that define five-axis switchkins `M428`, `M429`, and `M430`: bridge-mill,
dual-rotary, and table-rotary-tilting INI files, `remap_subs/*.ngc`, HAL
switchkins links, tool tables, and demo programs. It verifies that these
commands remain LinuxCNC `REMAP` entries backed by LinuxCNC NGC subroutines
using `M68`, `M66`, and `_hal[motion.switchkins-type]`; it does not implement
the remap execution path.

View File

@@ -783,6 +783,30 @@ Steps:
- planner outputs - planner outputs
- forward/inverse kinematics - forward/inverse kinematics
- 5-axis world/joint transforms - 5-axis world/joint transforms
- LinuxCNC five-axis `M428`/`M429`/`M430` remap assets and switchkins
machine configuration links
Current five-axis switchkins status:
1. Vendored LinuxCNC `5axiskins`, `xyzac-trt-kins`, and `xyzbc-trt-kins`
sources are compiled and probed natively.
2. Vendored LinuxCNC sample machine assets now cover bridge-mill,
table-dual-rotary, and table-rotary-tilting INI/HAL/tool/demo/remap
files.
3. `M428`, `M429`, and `M430` remain LinuxCNC `REMAP` entries backed by
vendored LinuxCNC NGC subroutines; do not replace them with standalone
M-code handlers.
Next work:
1. Route vendored LinuxCNC remap lookup/execution through the standalone
interpreter harness for NGC remaps.
2. Connect the standalone HAL adapter so LinuxCNC `M68`/`M66` remap
synchronization updates and reads `_hal[motion.switchkins-type]`.
3. Add a native machine-session harness for `xyzac-trt` and `xyzbc-trt`
programs that switch `M429 -> M428 -> M429`.
4. Export the validated switchkins/remap status through the WASM SDK and INI
panel without adding JavaScript CNC semantics.
Involved LinuxCNC source: Involved LinuxCNC source:
@@ -796,6 +820,9 @@ Involved LinuxCNC source:
- `src/hal/components/xyzab_tdr_kins.comp` - `src/hal/components/xyzab_tdr_kins.comp`
- `src/hal/components/xyzacb_trsrn.comp` - `src/hal/components/xyzacb_trsrn.comp`
- `src/hal/components/xyzbca_trsrn.comp` - `src/hal/components/xyzbca_trsrn.comp`
- `configs/sim/axis/vismach/5axis/bridgemill/*`
- `configs/sim/axis/vismach/5axis/table-dual-rotary/*`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/*`
## Phase 10: Build the Standalone WASM Program ## Phase 10: Build the Standalone WASM Program

View File

@@ -70,5 +70,7 @@ The native baseline compares those negative fixtures with upstream
Machine baseline is still limited to standalone interpreter, trajectory Machine baseline is still limited to standalone interpreter, trajectory
planner, LinuxCNC identity/trivial kinematics, LinuxCNC `5axiskins` XYZBCW planner, LinuxCNC identity/trivial kinematics, LinuxCNC `5axiskins` XYZBCW
bridge-mill probing, and LinuxCNC TRT `xyzac`/`xyzbc` probing. Additional bridge-mill probing, LinuxCNC TRT `xyzac`/`xyzbc` probing, and vendored
non-trivial kinematics and fuller machine baselines remain future work. LinuxCNC five-axis sample machine assets for `M428`, `M429`, and `M430`
switchkins remaps. Full standalone execution of those remaps still needs the
LinuxCNC remap runtime and HAL synchronization boundary connected.

View File

@@ -40,6 +40,7 @@ Current validation is intentionally mechanical:
| Identity/trivial kinematics | `src/emc/kinematics/kinematics.h`, `cubic.h`, `kins_util.c`, `trivkins.c` | Copy unchanged | HAL component lifecycle and RTAPI module metadata are replaced by standalone shims; forward/inverse mapping behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_kinematics_probe` | | Identity/trivial kinematics | `src/emc/kinematics/kinematics.h`, `cubic.h`, `kins_util.c`, `trivkins.c` | Copy unchanged | HAL component lifecycle and RTAPI module metadata are replaced by standalone shims; forward/inverse mapping behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_kinematics_probe` |
| Switchable 5-axis bridge kinematics | `src/emc/kinematics/5axiskins.c`, `switchkins.c`, `switchkins.h`, `userkfuncs.c`, plus `src/rtapi/rtapi_ctype.h` | Copy unchanged | HAL pin allocation, HAL component lifecycle, and RTAPI module metadata are standalone runtime edges; switchable 5-axis forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_5axis_kinematics_probe` | | Switchable 5-axis bridge kinematics | `src/emc/kinematics/5axiskins.c`, `switchkins.c`, `switchkins.h`, `userkfuncs.c`, plus `src/rtapi/rtapi_ctype.h` | Copy unchanged | HAL pin allocation, HAL component lifecycle, and RTAPI module metadata are standalone runtime edges; switchable 5-axis forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_5axis_kinematics_probe` |
| TRT table-rotary kinematics | `src/emc/kinematics/trtfuncs.c`, `xyzac-trt-kins.c`, `xyzbc-trt-kins.c` | Copy unchanged | HAL pin allocation and switchkins lifecycle stay runtime boundaries; XYZAC/XYZBC TRT forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_xyzac_trt_kinematics_probe`, `linuxcnc_xyzbc_trt_kinematics_probe` | | TRT table-rotary kinematics | `src/emc/kinematics/trtfuncs.c`, `xyzac-trt-kins.c`, `xyzbc-trt-kins.c` | Copy unchanged | HAL pin allocation and switchkins lifecycle stay runtime boundaries; XYZAC/XYZBC TRT forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_xyzac_trt_kinematics_probe`, `linuxcnc_xyzbc_trt_kinematics_probe` |
| Five-axis switchkins machine configs and M428/M429/M430 remaps | `configs/sim/axis/vismach/5axis/bridgemill/*`, `table-dual-rotary/*`, and `table-rotary-tilting/*` selected INI, HAL, tool-table, XML, demo, and `remap_subs/*.ngc` files | Copy unchanged | `M428`, `M429`, and `M430` remain LinuxCNC `REMAP` entries that call LinuxCNC NGC subroutines using `M68`, `M66`, `_hal[motion.switchkins-type]`, and the INI/HAL `motion.analog-out-03 => motion.switchkins-type` link; standalone execution of these remaps still requires the interpreter remap runtime and HAL synchronization edge to be connected | Vendor byte sync, `linuxcnc_5axis_remap_asset_probe`, browser INI panel sample loaded from vendored `xyzab-tdr.ini` |
| Additional non-switchable kinematics | `src/emc/kinematics/corexykins.c`, `rotatekins.c`, `rosekins.c`, `maxkins.c`, `lineardeltakins.c`, `lineardeltakins-common.h`, `rotarydeltakins.c`, `rotarydeltakins-common.h`, `scorbot-kins.c`, `tripodkins.c`, `scarakins.c`, `pumakins.c`, `pumakins.h`, `genhexkins.c`, `genhexkins.h`, `genserfuncs.c`, `genserkins.c`, `genserkins.h`, `ugenserkins.c`, `pentakins.c`, `pentakins.h`, `cubic.c` | Copy unchanged | HAL pin allocation, HAL parameter allocation, HAL component lifecycle, RTAPI module metadata, Go math C/C++ linkage, switchkins iterative-forward warmup, and userspace test-program process entry remain standalone runtime edges; forward/inverse behavior remains LinuxCNC source where the module exposes it | Vendor byte sync, per-file source probes, `linuxcnc_corexy_kinematics_probe`, `linuxcnc_rotate_kinematics_probe`, `linuxcnc_rose_kinematics_probe`, `linuxcnc_max_kinematics_probe`, `linuxcnc_lineardelta_kinematics_probe`, `linuxcnc_rotarydelta_kinematics_probe`, `linuxcnc_scorbot_kinematics_probe`, `linuxcnc_tripod_kinematics_probe`, `linuxcnc_scara_kinematics_probe`, `linuxcnc_puma_kinematics_probe`, `linuxcnc_genser_kinematics_probe`, `linuxcnc_genhex_kinematics_probe`, `linuxcnc_pentakins_kinematics_probe` | | Additional non-switchable kinematics | `src/emc/kinematics/corexykins.c`, `rotatekins.c`, `rosekins.c`, `maxkins.c`, `lineardeltakins.c`, `lineardeltakins-common.h`, `rotarydeltakins.c`, `rotarydeltakins-common.h`, `scorbot-kins.c`, `tripodkins.c`, `scarakins.c`, `pumakins.c`, `pumakins.h`, `genhexkins.c`, `genhexkins.h`, `genserfuncs.c`, `genserkins.c`, `genserkins.h`, `ugenserkins.c`, `pentakins.c`, `pentakins.h`, `cubic.c` | Copy unchanged | HAL pin allocation, HAL parameter allocation, HAL component lifecycle, RTAPI module metadata, Go math C/C++ linkage, switchkins iterative-forward warmup, and userspace test-program process entry remain standalone runtime edges; forward/inverse behavior remains LinuxCNC source where the module exposes it | Vendor byte sync, per-file source probes, `linuxcnc_corexy_kinematics_probe`, `linuxcnc_rotate_kinematics_probe`, `linuxcnc_rose_kinematics_probe`, `linuxcnc_max_kinematics_probe`, `linuxcnc_lineardelta_kinematics_probe`, `linuxcnc_rotarydelta_kinematics_probe`, `linuxcnc_scorbot_kinematics_probe`, `linuxcnc_tripod_kinematics_probe`, `linuxcnc_scara_kinematics_probe`, `linuxcnc_puma_kinematics_probe`, `linuxcnc_genser_kinematics_probe`, `linuxcnc_genhex_kinematics_probe`, `linuxcnc_pentakins_kinematics_probe` |
| Trajectory planner | `src/emc/tp/tp.c`, `tc.c`, `tcq.c`, `spherical_arc.c`, `blendmath.c`, `sp_scurve.c`, `ruckig_wrapper.c`, plus matching `*.h` files | Copy unchanged | Native realtime scheduling and motion process state are replaced by standalone probe setup; the WASM TP probe uses the same deterministic status/config boundary and calls vendored TP APIs through a narrow C ABI | Vendor byte sync, per-file source probes, `linuxcnc_tp_api_probe`, `tests/wasm/node/verify_tp_wasm.sh` | | Trajectory planner | `src/emc/tp/tp.c`, `tc.c`, `tcq.c`, `spherical_arc.c`, `blendmath.c`, `sp_scurve.c`, `ruckig_wrapper.c`, plus matching `*.h` files | Copy unchanged | Native realtime scheduling and motion process state are replaced by standalone probe setup; the WASM TP probe uses the same deterministic status/config boundary and calls vendored TP APIs through a narrow C ABI | Vendor byte sync, per-file source probes, `linuxcnc_tp_api_probe`, `tests/wasm/node/verify_tp_wasm.sh` |
| Ruckig C planner support | Selected `src/emc/tp/cruckig/*.c` and `*.h` files in the manifest | Copy unchanged | Used as LinuxCNC planner support code through vendored TP sources | Vendor byte sync, per-file source probes, `tests/wasm/node/verify_tp_wasm.sh` | | Ruckig C planner support | Selected `src/emc/tp/cruckig/*.c` and `*.h` files in the manifest | Copy unchanged | Used as LinuxCNC planner support code through vendored TP sources | Vendor byte sync, per-file source probes, `tests/wasm/node/verify_tp_wasm.sh` |
@@ -58,7 +59,7 @@ Current validation is intentionally mechanical:
| RTAPI | `rtapi_*.h`, TP, posemath, motion headers | Minimal standalone shim in `runtime/core/shims/rtapi.h` | | RTAPI | `rtapi_*.h`, TP, posemath, motion headers | Minimal standalone shim in `runtime/core/shims/rtapi.h` |
| NML transport | `emc.hh`, motion/NML type headers | Transport is not ported; only the status/type edges needed by vendored compute code are exposed through standalone shims and probes | | NML transport | `emc.hh`, motion/NML type headers | Transport is not ported; only the status/type edges needed by vendored compute code are exposed through standalone shims and probes |
| HAL runtime | named parameter lookup, kinematics component lifecycle, and runtime status edges | Standalone HAL adapter under `runtime/core/linuxcnc_wrap/` | | HAL runtime | named parameter lookup, kinematics component lifecycle, and runtime status edges | Standalone HAL adapter under `runtime/core/linuxcnc_wrap/` |
| Python/remap | `rs274ngc_pre.cc`, `interp_o_word.cc`, remap hooks | Stubbed at runtime boundary; no Python CNC semantics are reimplemented | | Python/remap | `rs274ngc_pre.cc`, `interp_o_word.cc`, remap hooks, selected LinuxCNC `configs/sim/axis/vismach/5axis/*/remap_subs/*.ngc` files | Stubbed at runtime boundary today; five-axis M428/M429/M430 source assets are vendored unchanged, and the next runtime step is to route LinuxCNC NGC remap execution plus HAL pin synchronization through standalone adapters without reimplementing the remap semantics |
| Canonical machine actions | `interp_convert.cc`, `interp_execute.cc`, `interp_queue.cc` | Captured by standalone canonical event sink functions for regression fixtures | | Canonical machine actions | `interp_convert.cc`, `interp_execute.cc`, `interp_queue.cc` | Captured by standalone canonical event sink functions for regression fixtures |
| Realtime scheduling | TP and motion headers | Not ported; native TP probes seed deterministic status/config state | | Realtime scheduling | TP and motion headers | Not ported; native TP probes seed deterministic status/config state |
| GUI | None used as implementation | Native LinuxCNC GUI remains reference-only | | GUI | None used as implementation | Native LinuxCNC GUI remains reference-only |
@@ -69,6 +70,11 @@ Current validation is intentionally mechanical:
source-probe level. Serial `genserkins`, hexapod `genhexkins`, and pentapod source-probe level. Serial `genserkins`, hexapod `genhexkins`, and pentapod
`pentakins` have native runtime baselines; full runtime machine baselines for `pentakins` have native runtime baselines; full runtime machine baselines for
userspace genser flows are not yet established. userspace genser flows are not yet established.
- Five-axis M428/M429/M430 source assets are now vendored for bridge-mill,
dual-rotary, and table-rotary-tilting LinuxCNC sample machines. Full
standalone execution still needs LinuxCNC remap dispatch, the `M68`/`M66`
synchronization path, and `_hal[motion.switchkins-type]` readback connected
through the standalone HAL boundary.
- Cutter compensation positive motion and negative interpreter paths are - Cutter compensation positive motion and negative interpreter paths are
fixture-covered through vendored `interp_convert.cc` and `interp_queue.cc`. fixture-covered through vendored `interp_convert.cc` and `interp_queue.cc`.
- Browser/WASM C ABI and JS SDK layers are now present for the INI parser, the - Browser/WASM C ABI and JS SDK layers are now present for the INI parser, the

View File

@@ -0,0 +1,235 @@
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
#include "emc/ini/inifile.hh"
#ifndef LINUXCNC_VENDOR_DIR
#error "LINUXCNC_VENDOR_DIR must point at wasm-port/vendor/linuxcnc"
#endif
namespace {
struct MachineCase {
const char *label;
const char *ini_rel;
const char *machine;
const char *kinematics;
const char *coordinates;
const char *joints;
const char *parameter_file;
const char *tool_table;
bool expects_m430;
};
std::string vendor_path(const std::string &rel)
{
return std::string(LINUXCNC_VENDOR_DIR) + "/" + rel;
}
std::string read_text(const std::string &path)
{
std::ifstream input(path);
return std::string(
std::istreambuf_iterator<char>(input),
std::istreambuf_iterator<char>());
}
bool contains(const std::string &text, const std::string &needle)
{
return text.find(needle) != std::string::npos;
}
void print_bool(const std::string &name, bool value)
{
std::cout << name << "=" << (value ? 1 : 0) << "\n";
}
bool check_string(
const linuxcnc::IniFile &ini,
const std::string &label,
const std::string &section,
const std::string &tag,
const std::string &expected)
{
const auto actual = ini.findString(tag, section);
std::cout << label << "_" << section << "." << tag << "="
<< (actual ? *actual : "<missing>") << "\n";
const bool ok = actual && *actual == expected;
print_bool(label + "_" + section + "." + tag + "_ok", ok);
return ok;
}
bool check_remap_entry(
const std::vector<std::string> &remaps,
const std::string &label,
const std::string &mcode,
const std::string &ngc)
{
const std::string mcode_needle = "REMAP = " + mcode;
const std::string ngc_needle = "ngc=" + ngc;
bool ok = false;
for (const auto &remap : remaps) {
if (contains(remap, mcode) && contains(remap, ngc_needle)) {
ok = true;
}
}
print_bool(label + "_remap_" + mcode + "_" + ngc, ok);
(void)mcode_needle;
return ok;
}
bool check_remap_file(
const std::string &label,
const std::string &dir_rel,
const std::string &mcode,
const std::string &expected_kinstype)
{
const std::string path = vendor_path(dir_rel + "/remap_subs/" + mcode.substr(1) + "remap.ngc");
const std::string text = read_text(path);
const bool ok =
contains(text, "o<" + mcode.substr(1) + "remap>sub") &&
contains(text, "#<kinstype> = " + expected_kinstype) &&
contains(text, "#<SWITCHKINS_PIN> = 3") &&
contains(text, "#<_hal[motion.switchkins-type]>") &&
contains(text, "M68") &&
contains(text, "M66") &&
contains(text, "o<" + mcode.substr(1) + "remap>endsub");
print_bool(label + "_" + mcode + "_remap_file_from_linuxcnc", ok);
return ok;
}
bool check_text_mcodes(
const std::string &label,
const std::string &rel,
bool expects_m428,
bool expects_m429)
{
const std::string text = read_text(vendor_path(rel));
const bool ok =
(!expects_m428 || contains(text, "M428")) &&
(!expects_m429 || contains(text, "M429"));
print_bool(label + "_switch_mcodes_from_linuxcnc", ok);
return ok;
}
bool check_machine(const MachineCase &machine)
{
bool ok = true;
const std::string ini_path = vendor_path(machine.ini_rel);
linuxcnc::IniFile ini(ini_path);
const bool opened = static_cast<bool>(ini);
print_bool(std::string(machine.label) + "_ini_open", opened);
if (!opened) {
return false;
}
ok &= check_string(ini, machine.label, "EMC", "MACHINE", machine.machine);
ok &= check_string(ini, machine.label, "KINS", "KINEMATICS", machine.kinematics);
ok &= check_string(ini, machine.label, "TRAJ", "COORDINATES", machine.coordinates);
ok &= check_string(ini, machine.label, "KINS", "JOINTS", machine.joints);
ok &= check_string(ini, machine.label, "RS274NGC", "SUBROUTINE_PATH", "./remap_subs");
ok &= check_string(ini, machine.label, "RS274NGC", "PARAMETER_FILE", machine.parameter_file);
ok &= check_string(ini, machine.label, "EMCIO", "TOOL_TABLE", machine.tool_table);
const auto remaps = ini.findStringAll("REMAP", "RS274NGC");
std::cout << machine.label << "_remap_count=" << remaps.size() << "\n";
ok &= check_remap_entry(remaps, machine.label, "M428", "428remap");
ok &= check_remap_entry(remaps, machine.label, "M429", "429remap");
if (machine.expects_m430) {
ok &= check_remap_entry(remaps, machine.label, "M430", "430remap");
}
const std::string ini_text = read_text(ini_path);
const bool has_switchkins_halcmd =
contains(ini_text, "motion.analog-out-03 => motion.switchkins-type");
ok &= has_switchkins_halcmd;
print_bool(std::string(machine.label) + "_halcmd_switchkins_from_linuxcnc", has_switchkins_halcmd);
const std::string dir_rel = std::string(machine.ini_rel).substr(
0,
std::string(machine.ini_rel).find_last_of('/'));
return ok && check_remap_file(machine.label, dir_rel, "M428",
std::string(machine.label) == "bridgemill" ? "0" : "1") &&
check_remap_file(machine.label, dir_rel, "M429",
std::string(machine.label) == "bridgemill" ? "1" : "0") &&
(!machine.expects_m430 || check_remap_file(machine.label, dir_rel, "M430", "2"));
}
} // namespace
int main()
{
const MachineCase cases[] = {
{
"bridgemill",
"configs/sim/axis/vismach/5axis/bridgemill/5axis.ini",
"Sim-5Axis Bridge Mill (xyzbcw)",
"5axiskins coordinates=xyzbcwy",
"XYZBCWY",
"7",
"5axis.var",
"5axis.tbl",
true,
},
{
"xyzab_tdr",
"configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini",
"sim-xyzab-tdr-kins (switchkins)",
"xyzab_tdr_kins",
"XYZAB",
"5",
"xyzab-tdr.var",
"xyzab-tdr.tbl",
false,
},
{
"xyzac_trt",
"configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini",
"sim-xyzac-trt-kins (switchkins)",
"xyzac-trt-kins sparm=identityfirst",
"XYZAC",
"5",
"xyzac.var",
"xyzac-trt.tbl",
true,
},
{
"xyzbc_trt",
"configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini",
"sim-xyzbc-trt-kins (switchkins)",
"xyzbc-trt-kins sparm=identityfirst",
"XYZBC",
"5",
"xyzbc.var",
"xyzbc-trt.tbl",
true,
},
};
bool ok = true;
for (const auto &machine : cases) {
ok &= check_machine(machine);
}
ok &= check_text_mcodes(
"xyzab_tdr",
"configs/sim/axis/vismach/5axis/table-dual-rotary/README",
true,
true);
ok &= check_text_mcodes(
"xyzac_trt",
"configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc",
true,
true);
ok &= check_text_mcodes(
"xyzbc_trt",
"configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc",
true,
true);
print_bool("fiveaxis_remap_assets_from_linuxcnc", ok);
return ok ? 0 : 1;
}

View File

@@ -14,6 +14,7 @@ typedef _object PyObject;
inline int PyCallable_Check(PyObject *) { return 0; } inline int PyCallable_Check(PyObject *) { return 0; }
inline int PyErr_ExceptionMatches(PyObject *) { return 0; } inline int PyErr_ExceptionMatches(PyObject *) { return 0; }
inline void PyErr_Clear() {} inline void PyErr_Clear() {}
inline void PyErr_Print() {}
inline int PyUnicode_Check(PyObject *) { return 0; } inline int PyUnicode_Check(PyObject *) { return 0; }
inline int PyLong_Check(PyObject *) { return 0; } inline int PyLong_Check(PyObject *) { return 0; }
inline int PyFloat_Check(PyObject *) { return 0; } inline int PyFloat_Check(PyObject *) { return 0; }
@@ -36,6 +37,9 @@ public:
template <typename T> template <typename T>
explicit object(const T &) {} explicit object(const T &) {}
template <typename T>
object &operator=(const T &) { return *this; }
object attr(const char *) const { return object(); } object attr(const char *) const { return object(); }
object operator[](const char *) const { return object(); } object operator[](const char *) const { return object(); }
object operator[](const std::string &) const { return object(); } object operator[](const std::string &) const { return object(); }

View File

@@ -0,0 +1,7 @@
#pragma once
#include <cwctype>
#ifndef towlower
#define towlower std::towlower
#endif

View File

@@ -19,7 +19,7 @@ import {
} from "../../opfs/linuxcnc-machine-session-bridge.js"; } from "../../opfs/linuxcnc-machine-session-bridge.js";
const SAMPLE_PATH = const SAMPLE_PATH =
"../../../linuxcnc/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini"; "../../../vendor/linuxcnc/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini";
const MACHINE_ID = "xyzab-tdr"; const MACHINE_ID = "xyzab-tdr";
const MACHINE_PATHS = machineFilePaths(MACHINE_ID); const MACHINE_PATHS = machineFilePaths(MACHINE_ID);
const OPFS_FILE = MACHINE_PATHS.ini; const OPFS_FILE = MACHINE_PATHS.ini;

View File

@@ -80,6 +80,8 @@ check_exitcode linuxcnc_interp_state_probe
check_exitcode linuxcnc_emc_status_probe check_exitcode linuxcnc_emc_status_probe
check_exitcode linuxcnc_emc_status_probe.run check_exitcode linuxcnc_emc_status_probe.run
check_exitcode linuxcnc_inifile_source_probe check_exitcode linuxcnc_inifile_source_probe
check_exitcode linuxcnc_5axis_remap_asset_probe
check_exitcode linuxcnc_5axis_remap_asset_probe.run
check_exitcode linuxcnc_tp_api_probe check_exitcode linuxcnc_tp_api_probe
check_exitcode linuxcnc_tp_api_probe.run check_exitcode linuxcnc_tp_api_probe.run
check_exitcode linuxcnc_kinematics_probe check_exitcode linuxcnc_kinematics_probe
@@ -200,6 +202,7 @@ check_exitcode linuxcnc_interp_find_source_probe
check_exitcode linuxcnc_interp_namedparams_source_probe check_exitcode linuxcnc_interp_namedparams_source_probe
check_exitcode linuxcnc_interp_write_source_probe check_exitcode linuxcnc_interp_write_source_probe
check_exitcode linuxcnc_interp_o_word_source_probe check_exitcode linuxcnc_interp_o_word_source_probe
check_exitcode linuxcnc_interp_remap_source_probe
check_exitcode linuxcnc_rs274ngc_pre_source_probe check_exitcode linuxcnc_rs274ngc_pre_source_probe
check_exitcode linuxcnc_interp_base_source_probe check_exitcode linuxcnc_interp_base_source_probe
check_exitcode linuxcnc_gomath_source_probe check_exitcode linuxcnc_gomath_source_probe
@@ -212,6 +215,32 @@ grep -Fq "emc_status_default_machine_units_mm=1" "$EMC_STATUS_STDOUT"
grep -Fq "emc_status_inch_machine_units_visible=1" "$EMC_STATUS_STDOUT" grep -Fq "emc_status_inch_machine_units_visible=1" "$EMC_STATUS_STDOUT"
grep -Fq "emc_status_mm_machine_units_visible=1" "$EMC_STATUS_STDOUT" grep -Fq "emc_status_mm_machine_units_visible=1" "$EMC_STATUS_STDOUT"
FIVEAXIS_REMAP_ASSET_STDOUT="$BUILD_DIR/linuxcnc_5axis_remap_asset_probe.run.stdout.log"
grep -Fq "bridgemill_ini_open=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "bridgemill_remap_M428_428remap=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "bridgemill_remap_M429_429remap=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "bridgemill_remap_M430_430remap=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "bridgemill_M428_remap_file_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "bridgemill_M429_remap_file_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "bridgemill_M430_remap_file_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzab_tdr_ini_open=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzab_tdr_remap_M428_428remap=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzab_tdr_remap_M429_429remap=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzab_tdr_M428_remap_file_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzab_tdr_M429_remap_file_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzac_trt_ini_open=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzac_trt_remap_M428_428remap=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzac_trt_remap_M429_429remap=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzac_trt_remap_M430_430remap=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzbc_trt_ini_open=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzbc_trt_remap_M428_428remap=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzbc_trt_remap_M429_429remap=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzbc_trt_remap_M430_430remap=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzab_tdr_switch_mcodes_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzac_trt_switch_mcodes_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "xyzbc_trt_switch_mcodes_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "fiveaxis_remap_assets_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
NAMEDPARAM_STDOUT="$BUILD_DIR/linuxcnc_namedparam_harness.run.stdout.log" NAMEDPARAM_STDOUT="$BUILD_DIR/linuxcnc_namedparam_harness.run.stdout.log"
grep -Fq "init_named_parameters=0" "$NAMEDPARAM_STDOUT" grep -Fq "init_named_parameters=0" "$NAMEDPARAM_STDOUT"
grep -Fq "global_named_count=57" "$NAMEDPARAM_STDOUT" grep -Fq "global_named_count=57" "$NAMEDPARAM_STDOUT"

View File

@@ -40,6 +40,16 @@ COMMON_INI_FLAGS=(
-I"$VENDOR_DIR/src/emc/ini" -I"$VENDOR_DIR/src/emc/ini"
) )
REMAP_SOURCE_FLAGS=(
"${COMMON_INI_FLAGS[@]}"
-include "$SHIM_DIR/linuxcnc_remap_compile_compat.hh"
)
VENDOR_ASSET_FLAGS=(
"${COMMON_INI_FLAGS[@]}"
-DLINUXCNC_VENDOR_DIR=\"$VENDOR_DIR\"
)
MINIMAL_FLAGS=( MINIMAL_FLAGS=(
"${COMMON_INI_FLAGS[@]}" "${COMMON_INI_FLAGS[@]}"
-ffunction-sections -ffunction-sections
@@ -338,6 +348,11 @@ INI_PROBE_SOURCES=(
"$WRAP_DIR/linuxcnc_ini_probe.cpp" "$WRAP_DIR/linuxcnc_ini_probe.cpp"
) )
FIVEAXIS_REMAP_ASSET_PROBE_SOURCES=(
"$VENDOR_DIR/src/emc/ini/inifile.cc"
"$WRAP_DIR/linuxcnc_5axis_remap_asset_probe.cpp"
)
STATE_PROBE_SOURCES=( STATE_PROBE_SOURCES=(
"$WRAP_DIR/linuxcnc_interp_state_probe.cpp" "$WRAP_DIR/linuxcnc_interp_state_probe.cpp"
) )
@@ -654,6 +669,29 @@ build_binary_target \
NO_LINK_FLAGS \ NO_LINK_FLAGS \
-lfmt -lfmt
build_binary_target \
linuxcnc_5axis_remap_asset_probe \
"$BUILD_DIR/linuxcnc_5axis_remap_asset_probe" \
VENDOR_ASSET_FLAGS \
FIVEAXIS_REMAP_ASSET_PROBE_SOURCES \
NO_LINK_FLAGS \
-lfmt
if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_5axis_remap_asset_probe.exitcode")" == "0" ]]; then
set +e
"$BUILD_DIR/linuxcnc_5axis_remap_asset_probe" \
>"$BUILD_DIR/linuxcnc_5axis_remap_asset_probe.run.stdout.log" \
2>"$BUILD_DIR/linuxcnc_5axis_remap_asset_probe.run.stderr.log"
FIVEAXIS_REMAP_ASSET_RUN_RC=$?
set -e
echo "$FIVEAXIS_REMAP_ASSET_RUN_RC" > "$BUILD_DIR/linuxcnc_5axis_remap_asset_probe.run.exitcode"
else
rm -f \
"$BUILD_DIR/linuxcnc_5axis_remap_asset_probe.run.exitcode" \
"$BUILD_DIR/linuxcnc_5axis_remap_asset_probe.run.stdout.log" \
"$BUILD_DIR/linuxcnc_5axis_remap_asset_probe.run.stderr.log"
fi
build_object_target \ build_object_target \
linuxcnc_inifile_source_probe \ linuxcnc_inifile_source_probe \
"$BUILD_DIR/linuxcnc_inifile_source_probe.o" \ "$BUILD_DIR/linuxcnc_inifile_source_probe.o" \
@@ -1454,6 +1492,12 @@ build_object_target \
"$VENDOR_DIR/src/emc/rs274ngc/interp_o_word.cc" \ "$VENDOR_DIR/src/emc/rs274ngc/interp_o_word.cc" \
COMMON_INI_FLAGS COMMON_INI_FLAGS
build_object_target \
linuxcnc_interp_remap_source_probe \
"$BUILD_DIR/linuxcnc_interp_remap_source_probe.o" \
"$VENDOR_DIR/src/emc/rs274ngc/interp_remap.cc" \
REMAP_SOURCE_FLAGS
build_object_target \ build_object_target \
linuxcnc_rs274ngc_pre_source_probe \ linuxcnc_rs274ngc_pre_source_probe \
"$BUILD_DIR/linuxcnc_rs274ngc_pre_source_probe.o" \ "$BUILD_DIR/linuxcnc_rs274ngc_pre_source_probe.o" \

View File

@@ -146,6 +146,56 @@ src/emc/rs274ngc/interp_execute.cc
src/emc/rs274ngc/interp_find.cc src/emc/rs274ngc/interp_find.cc
src/emc/rs274ngc/interp_inverse.cc src/emc/rs274ngc/interp_inverse.cc
src/emc/rs274ngc/interp_o_word.cc src/emc/rs274ngc/interp_o_word.cc
src/emc/rs274ngc/interp_remap.cc
src/emc/rs274ngc/interp_convert.cc src/emc/rs274ngc/interp_convert.cc
src/emc/rs274ngc/interp_cycles.cc src/emc/rs274ngc/interp_cycles.cc
src/emc/rs274ngc/interp_g7x.cc src/emc/rs274ngc/interp_g7x.cc
configs/sim/axis/vismach/5axis/bridgemill/5axis.ini
configs/sim/axis/vismach/5axis/bridgemill/5axis.tbl
configs/sim/axis/vismach/5axis/bridgemill/5axis.xml
configs/sim/axis/vismach/5axis/bridgemill/5axis_postgui.hal
configs/sim/axis/vismach/5axis/bridgemill/5axisgui.hal
configs/sim/axis/vismach/5axis/bridgemill/5axisgui.ngc
configs/sim/axis/vismach/5axis/bridgemill/README
configs/sim/axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc
configs/sim/axis/vismach/5axis/bridgemill/remap_subs/429remap.ngc
configs/sim/axis/vismach/5axis/bridgemill/remap_subs/430remap.ngc
configs/sim/axis/vismach/5axis/table-dual-rotary/README
configs/sim/axis/vismach/5axis/table-dual-rotary/demos/xyzab-tdr-demo.ngc
configs/sim/axis/vismach/5axis/table-dual-rotary/remap_subs/428remap.ngc
configs/sim/axis/vismach/5axis/table-dual-rotary/remap_subs/429remap.ngc
configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr-postgui.hal
configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini
configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.tbl
configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.var
configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.var.bak
configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.xml
configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr_cmds.hal
configs/sim/axis/vismach/5axis/table-rotary-tilting/README
configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_2.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_3.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/centering.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/helix_ac.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/helix_bc.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/xyzac_switchkins_sub.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/xyzbc_switchkins_sub.ngc
configs/sim/axis/vismach/5axis/table-rotary-tilting/switchkins.halshow
configs/sim/axis/vismach/5axis/table-rotary-tilting/switchkins_postgui.hal
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.tbl
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.txt
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.xml
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt_cmds.hal
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.tbl
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.txt
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.xml

View File

@@ -0,0 +1,202 @@
[EMC]
VERSION = 1.1
MACHINE = Sim-5Axis Bridge Mill (xyzbcw)
DEBUG = 0
[DISPLAY]
GEOMETRY = XYZCBW
OPEN_FILE = ./5axisgui.ngc
INCREMENTS = 10 mm, 1 mm, .1 mm
JOG_AXES = XYZC
GEOMETRY = XYZCBW
DISPLAY = axis
CYCLE_TIME = 0.200
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
MAX_FEED_OVERRIDE = 2.0
PROGRAM_PREFIX = ../../nc_files/
INTRO_GRAPHIC = linuxcnc.gif
INTRO_TIME = 5
TOOL_EDITOR = tooledit z diam
#EDITOR = geany
PYVCP = 5axis.xml
[RS274NGC]
SUBROUTINE_PATH = ./remap_subs
HAL_PIN_VARS = 1
REMAP = M428 modalgroup=10 ngc=428remap
REMAP = M429 modalgroup=10 ngc=429remap
REMAP = M430 modalgroup=10 ngc=430remap
PARAMETER_FILE = 5axis.var
[EMCMOT]
EMCMOT = motmod
COMM_TIMEOUT = 1.0
SERVO_PERIOD = 1000000
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[HAL]
HALUI = halui
HALFILE = LIB:basic_sim.tcl
HALFILE = 5axisgui.hal
HALCMD = net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type
POSTGUI_HALFILE = 5axis_postgui.hal
[HALUI]
# M428:bridgemill (kinstype==0 startupDEFAULT)
# M429:identity kins (kinstype==1)
# M430:userk kins (kinstype==2)
MDI_COMMAND = M428
MDI_COMMAND = M429
MDI_COMMAND = M430
[TRAJ]
COORDINATES = XYZBCWY
LINEAR_UNITS = mm
ANGULAR_UNITS = degree
MAX_ANGULAR_VELOCITY = 360.0
DEFAULT_LINEAR_VELOCITY = 200.0
MAX_LINEAR_VELOCITY = 346.0
MAX_LINEAR_ACCELERATION = 800.0
DEFAULT_LINEAR_ACCELERATION = 800.0
MAX_ANGULAR_VELOCITY = 360
[EMCIO]
TOOL_TABLE = 5axis.tbl
[KINS]
# Note: Supported coordinates are XYZBCW but the W coordinate
# motion is incorporated into the X,Y,Z axes.
# Use of the W coordinate requires a joint (5)
# in order to allow display of W values.
# Use immediate homing for this joint (JOINT_5)
# Note: 5axiskins is misnomer
# (xyzbcw uses 6 joints)
# (xyzbcwy uses 7 joints)
# xyzbcw
# type0:5axiskins, type1:identity, type2:userk
# x:joint0,y:joint1,z:joint2,b:joint3,c:joint4,w:joint5
# JOINTS = 6
# KINEMATICS = 5axiskins
# illustraed below is complex example with duplicate
# coord letters for y, 7 joints total):
# type0:5axiskins, type1:identity, type2:userk
# x:joint0
# y:joint1 AND joint6
# z:joint2
# b:joint3
# c:joint4
# w:joint5
JOINTS = 7
KINEMATICS = 5axiskins coordinates=xyzbcwy
[AXIS_X]
MIN_LIMIT = -500
MAX_LIMIT = 500
MAX_VELOCITY = 200
MAX_ACCELERATION = 800
[AXIS_Y]
MIN_LIMIT = -500
MAX_LIMIT = 500
MAX_VELOCITY = 200
MAX_ACCELERATION = 800
[AXIS_Z]
MIN_LIMIT = -500
MAX_LIMIT = 100
MAX_VELOCITY = 200
MAX_ACCELERATION = 800
# B is one-to-one to JOINT_3
[AXIS_B]
MIN_LIMIT = -120
MAX_LIMIT = 120
MAX_VELOCITY = 60
MAX_ACCELERATION = 200
# C is one-to-one to JOINT_4
[AXIS_C]
MIN_LIMIT = -36000
MAX_LIMIT = 36000
MAX_VELOCITY = 60
MAX_ACCELERATION = 200
# W motion is incorporated in Z motion
# but a joint (JOINT_5) must be configured
# to support display of W values
[AXIS_W]
MIN_LIMIT = -100
MAX_LIMIT = 500
MAX_VELOCITY = 200
MAX_ACCELERATION = 800
[JOINT_0]
TYPE = LINEAR
MAX_VELOCITY = 200
MAX_ACCELERATION = 800
MIN_LIMIT = -500
MAX_LIMIT = 500
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_1]
TYPE = LINEAR
MAX_VELOCITY = 200
MAX_ACCELERATION = 800
MIN_LIMIT = -500
MAX_LIMIT = 500
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = -1
# joints 1 and 6 used for y
[JOINT_6]
TYPE = LINEAR
MAX_VELOCITY = 200
MAX_ACCELERATION = 800
MIN_LIMIT = -500
MAX_LIMIT = 500
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = -1
[JOINT_2]
TYPE = LINEAR
MAX_VELOCITY = 200
MAX_ACCELERATION = 800
MIN_LIMIT = -500
MAX_LIMIT = 100
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_3]
TYPE = ANGULAR
MAX_VELOCITY = 60
MAX_ACCELERATION = 200
MIN_LIMIT = -120
MAX_LIMIT = 120
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_4]
TYPE = ANGULAR
MAX_VELOCITY = 60
MAX_ACCELERATION = 200
MIN_LIMIT = -36000
MAX_LIMIT = 36000
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
# immediate homing for JOINT_5 (w coordinate)
[JOINT_5]
TYPE = LINEAR
MIN_LIMIT = -100
MAX_LIMIT = 500
MAX_VELOCITY = 200
MAX_ACCELERATION = 800
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0

View File

@@ -0,0 +1,4 @@
T10 P10 Z10 D10
T11 P11 Z11 D10
T100 P100 Z100 D10
T150 P150 Z150 D10

View File

@@ -0,0 +1,128 @@
<?xml version='1.0' encoding='UTF-8'?>
<pyvcp>
<vbox>
<relief>"ridge"</relief>
<bd>5</bd>
<label>
<text>"SWITCHKINS"</text>
<relief>RIDGE</relief>
<bd>3</bd>
</label>
<multilabel>
<legends>[" 0:BRIDGE ", "1:IDENTITY", " 2:USERK "]</legends>
<font>("DejaVu Sans Mono",16)</font>
<bg>"black"</bg>
<fg>"yellow"</fg>
</multilabel>
<button>
<halpin>"type0-button"</halpin>
<text>"Brigemill"</text>
<bd>3</bd>
</button>
<button>
<halpin>"type1-button"</halpin>
<text>"Identity "</text>
<bd>3</bd>
</button>
<button>
<halpin>"type2-button"</halpin>
<text>"userk "</text>
<bd>3</bd>
</button>
</vbox>
<vbox>
<labelframe text="Joints values">
<font>("Helvetica",14)</font>
<hbox>
<label>
<text>"0: "</text>
<font>("Helvetica",14)</font>
</label>
<number>
<halpin>"joint0"</halpin>
<font>("Helvetica",14)</font>
<format>"4.4f"</format>
</number>
</hbox>
<hbox>
<label>
<text>"1: "</text>
<font>("Helvetica",14)</font>
</label>
<number>
<halpin>"joint1"</halpin>
<font>("Helvetica",14)</font>
<format>"4.4f"</format>
</number>
</hbox>
<hbox>
<label>
<text>"2: "</text>
<font>("Helvetica",14)</font>
</label>
<number>
<halpin>"joint2"</halpin>
<font>("Helvetica",14)</font>
<format>"4.4f"</format>
</number>
</hbox>
<hbox>
<label>
<text>"3: "</text>
<font>("Helvetica",14)</font>
</label>
<number>
<halpin>"joint3"</halpin>
<font>("Helvetica",14)</font>
<format>"4.4f"</format>
</number>
</hbox>
<hbox>
<label>
<text>"4: "</text>
<font>("Helvetica",14)</font>
</label>
<number>
<halpin>"joint4"</halpin>
<font>("Helvetica",14)</font>
<format>"4.4f"</format>
</number>
</hbox>
<hbox>
<label>
<text>"5: "</text>
<font>("Helvetica",14)</font>
</label>
<number>
<halpin>"joint5"</halpin>
<font>("Helvetica",14)</font>
<format>"4.4f"</format>
</number>
</hbox>
<hbox>
<label>
<text>"6: "</text>
<font>("Helvetica",14)</font>
</label>
<number>
<halpin>"joint6"</halpin>
<font>("Helvetica",14)</font>
<format>"4.4f"</format>
</number>
</hbox>
</labelframe>
</vbox>
<vbox>
<relief>"ridge"</relief>
<bd>5</bd>
<button>
<halpin>"vismach-clear"</halpin>
<text>"vismach-clear"</text>
<bd>3</bd>
</button>
</vbox>
</pyvcp>

View File

@@ -0,0 +1,17 @@
net :kinstype.is-0 <= kinstype.is-0 => pyvcp.multilabel.0.legend0
net :kinstype.is-1 <= kinstype.is-1 => pyvcp.multilabel.0.legend1
net :kinstype.is-2 <= kinstype.is-2 => pyvcp.multilabel.0.legend2
net :type0-button <= pyvcp.type0-button => halui.mdi-command-00
net :type1-button <= pyvcp.type1-button => halui.mdi-command-01
net :type2-button <= pyvcp.type2-button => halui.mdi-command-02
net :jx => pyvcp.joint0
net :jy => pyvcp.joint1
net :jz => pyvcp.joint2
net :jb => pyvcp.joint3
net :jc => pyvcp.joint4
net :jw => pyvcp.joint5
net :jy2 => pyvcp.joint6
net :vismach-clear <= pyvcp.vismach-clear => vismach.plotclear

View File

@@ -0,0 +1,32 @@
loadusr -W 5axisgui
# to set different pivot_len, use:
# 'loadusr -W 5axisgui pivot_len=value'
net :jx joint.0.pos-fb 5axisgui.jx
net :jy joint.1.pos-fb 5axisgui.jy
net :jz joint.2.pos-fb 5axisgui.jz
net :jb joint.3.pos-fb 5axisgui.jb
net :jc joint.4.pos-fb 5axisgui.jc
net :jw joint.5.pos-fb
net :jy2 joint.6.pos-fb
# Note: no joint or motor connections are used
# for the w coordinate
# compute pivot-length needed for 5axiskins
# according to gui pivot_len and tool z offset
loadrt sum2 names=pivotsum
addf pivotsum servo-thread
net :gui-pivot-len <= 5axisgui.pivot_len
net :gui-pivot-len => pivotsum.in0
net :tool-len <= motion.tooloffset.z
net :tool-len => pivotsum.in1
net :tool-len => 5axisgui.tool_length
net :pivot-len <= pivotsum.out
net :pivot-len => 5axiskins.pivot-length
net :tool-diam <= halui.tool.diameter
net :tool-diam => 5axisgui.tool_diam

View File

@@ -0,0 +1,53 @@
#<r> = 60 ; sphere radius
#<rdelta> = 5 ; safe distance
#<drilldepth> = -5
#<zstart> = 0
#<bctmax> = 8
#<cctmax> = 16
#<toolno> = 100
#<frate> = 1000
#<bct> = 0
#<cct> = 0
#<cdelta> = [360/#<cctmax>]
#<bdelta> = [90/#<bctmax>]
g49
t#<toolno>m6g43
g53 g0 x0y0z#<zstart>b0c0 w0
g10l20 p0 x0 y0 z[#<r>+#<rdelta>] b0 c0 w0
g0 z0
f#<frate>
o100 while [#<bct> lt #<bctmax>]
#<b> = [#<bct>*#<bdelta>]
#<rnow> = [[#<r>+#<rdelta>]*[cos[#<b>]]]
#<x> = [#<rnow>]
#<y> = 0
#<z> = [-#<rnow>]
g0 x#<x> y#<y>
m66e0l0 ; force sync
g0 z#<z>
g0b[-90+#<b>]
#<cct> = 0
o200 while [#<cct> lt #<cctmax>]
o210 if [[#<bct> mod 2] eq 0]
#<c> = [#<cct> * #<cdelta>]
o210 else
#<c> = [360 - [1+ #<cct>] * #<cdelta>]
o210 endif
#<x> = [#<rnow>*[cos[#<c>]]]
#<y> = [#<rnow>*[sin[#<c>]]]
g0 x#<x> y#<y> z#<z> c#<c>
f#<frate>
g1 w[ #<drilldepth> - #<rdelta>]
g0 w0
m66e0l0 ;force sync
#<cct> = [#<cct>+1]
o200 endwhile
#<bct> = [#<bct>+1]
o100 endwhile
g0x0y0z0b0c0w0
g53 g0 x0y0z0
m2

View File

@@ -0,0 +1,38 @@
This is a simulation of an XYZBCWY 5 axis bridge mill.
Example demo:
1) $ linuxcnc 5axis.ini
2) F1 ---------- Estop off
F2 ---------- Machine on
CTRL-HOME --- home all
F5 ---------- MDI tab
3) orient vismach gui as required
4) g0w10 ; retract w
5) g43h100 ; tool offset (100)
6) g0b45 ; tilt 45 deg wrt z
7) g0c30 ; rotate 30 deg in xy
8) g0w-10 ; simulate drill
9) g0w10 ; retract drill
10) etc
Note: Motion for the W coordinate is incorporated
into the motions of the joints used for X,Y,Z
motion but a corresponding joint.5 is needed to
correctly display W values.
The joint.5.motor-pos-cmd should be looped to the
joint.5.motor-pos-fb and joint.5 should use immediate
homimg (HOME_SEARCH_VEL = 0).
The 5axis.ini illustrates how to use multiple (2)
joints for the axis y coordinate.
Configuration for XYZBCWY (7 joints total)
J0: X
J1: Y
J2: Z
J3: B
J4: C
J5: W
J6: Y

View File

@@ -0,0 +1,24 @@
;M428 by remap: select kinstype=0 genhexkins
o<428remap>sub
#<kinstype> = 0
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M428:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M428: Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<428remap>endsub

View File

@@ -0,0 +1,24 @@
;M429 by remap: select kinstype==1 Identity kinematics
o<429remap>sub
#<kinstype> = 1
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M429:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M429:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<429remap>endsub

View File

@@ -0,0 +1,24 @@
;M430 by remap: select kinstype==2 userk kins
o<430remap>sub
#<kinstype> = 2
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M30:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M430:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<430remap>endsub

View File

@@ -0,0 +1,42 @@
Switchable Table Dual Rotary (tdr) Sim config
xyzab-tdr (switchable kinematics)
Demonstrations:
For a demonstration of XYZAB_TCP kinematics the user can run the preloaded demo gcode with the default offsets.
In the right hand panel of the axis gui sliders are provided to
- change the geometrical (x,z)-offsets as measured from the rotation-point of the A/B rotary-assembly to the
face center of the rotary A table. The offsets are visibly adjusted in the vismach simulation and represented by a red indicator
for the x-offset and a blue indicator for the z-offset.
- see the effects of misconfiguring the (x,y,z)-rot-point values used in the kinematics. These values represent the
physical position of the rotary-assembly in the machine as measured from the machine home position to the rotation-point
of the assembly. The rotation-point is identical to the intersection of the two rotational axes A and B when the (x,z)-offsets
are zero. When (x,z)-offsets are applied the rotation-point stays on the rotational B axis. The 'rot-point' as set by
these values as well as the true rotation-point of the rotary-assembly are indicated in the vismach simulation by a yellow cross
and a red sphere respectively.
NOTE:
For proper tool-path preview RELOAD THE CGODE after startup and after changing offset values.
***********************************************
Note: IMPORTANT ini file requirements:
[HAL]
HALCMD = net :kinstype-select <= motion.analog-out-0N => motion.switchkins-type
[RS274NGC]
SUBROUTINE_PATH = ./remap_subs
REMAP = M428 modalgroup=10 ngc=428remap
REMAP = M429 modalgroup=10 ngc=429remap
[HALUI]
MDI_COMMAND = M429
MDI_COMMAND = M428
***********************************************

View File

@@ -0,0 +1,49 @@
; -- RELOAD GCODE FOR PROPER TOOL-PATH PREVIEW --
g21 g90 g49 g54
; switch to identity mode
m429
; clear g54
g10 l2 p0 x0 y0 z0 a0 b0
; go to machine origin
g53 g0 x0 y0 z0 a0 b0
; set g54 for face center of rotary
g10 l20 p0 x-[#<_hal[xyzab_tdr_kins.x-rot-point]>+#<_hal[xyzab_tdr_kins.x-offset]>] y-#<_hal[xyzab_tdr_kins.x-rot-point]> z-[#<_hal[xyzab_tdr_kins.z-rot-point]>+#<_hal[xyzab_tdr_kins.z-offset]>] a0 b0
; load a tool
M61 Q2 G43 H2
; switch to tcp mode
m428
g0 b30
; go to face center of rotary a
g0 x0 y0 z0
; show basic tcp functionality
g0 x30 a180
g0 x0 a0
g0 b100
g0 y-50
g0 a90
g0 b120
g0 y0
g0 a0 b30
g0 x1
; start with square
f1000
g0 y-30 z-30
g1 z30
g1 a45
g1 y30
g1 a90 b45
g1 z-30
g1 a180 b100
g1 y30
g1 a90 b120
g1 y-30
g1 a0 b30
g0 x5
g1 y-30 z-30 a90
g1 z30 a45 b60
g1 y30 a90 b90
g1 z-30 a135 b120
g1 y-30 a0 b30
; go to machine origin
g53 g0 x0 y0 z0 a0 b0
m2

View File

@@ -0,0 +1,24 @@
;M428 by remap: kinstype==1 (xyzac,xyzbc) (note: sparm=identityfirst)
o<428remap>sub
#<kinstype> = 1 ; xyzac,xyzbc
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M428:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M428: Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<428remap>endsub

View File

@@ -0,0 +1,24 @@
;M429 by remap: kinstype==0 Identity kinematics
o<429remap>sub
#<kinstype> = 0
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M429:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M429:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<429remap>endsub

View File

@@ -0,0 +1,23 @@
# switchkins pyvcp connections for:
# xyzab-tdr-kins.ini
net :kinstype.is-0 <= kinstype.is-0 => pyvcp.multilabel.0.legend0
net :kinstype.is-1 <= kinstype.is-1 => pyvcp.multilabel.0.legend1
net :vismach-clear <= pyvcp.vismach-clear => vismach.plotclear
net :type0-button <= pyvcp.type0-button => halui.mdi-command-00
net :type1-button <= pyvcp.type1-button => halui.mdi-command-01
net :axis-x => pyvcp.joint0
net :axis-y => pyvcp.joint1
net :axis-z => pyvcp.joint2
net :rotary-a => pyvcp.joint3
net :rotary-b => pyvcp.joint4
net :x-offset => pyvcp.x-offset-f
net :z-offset => pyvcp.z-offset-f
net :x-rot-point => pyvcp.x-rot-point-f
net :y-rot-point => pyvcp.y-rot-point-f
net :z-rot-point => pyvcp.z-rot-point-f

View File

@@ -0,0 +1,183 @@
[EMC]
VERSION = 1.1
MACHINE = sim-xyzab-tdr-kins (switchkins)
[DISPLAY]
GEOMETRY = XYZA-B
OPEN_FILE = ./demos/xyzab-tdr-demo.ngc
PYVCP = ./xyzab-tdr.xml
DISPLAY = axis
MAX_ANGULAR_VELOCITY = 360
MAX_LINEAR_VELOCITY = 1000
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
MAX_FEED_OVERRIDE = 2
PROGRAM_PREFIX = ../../nc_files
INTRO_GRAPHIC = emc2.gif
INTRO_TIME = 1
TOOL_EDITOR = tooledit z diam
[RS274NGC]
SUBROUTINE_PATH = ./remap_subs
REMAP = M428 modalgroup=10 ngc=428remap
REMAP = M429 modalgroup=10 ngc=429remap
PARAMETER_FILE = xyzab-tdr.var
[KINS]
#NOTE:
# switchkins-type == 0 is identity kins
# switchkins-type == 1 is xyzab-tdr-kins
KINEMATICS = xyzab_tdr_kins
JOINTS = 5
[HAL]
HALUI = halui
HALFILE = LIB:basic_sim.tcl
POSTGUI_HALFILE = xyzab-tdr-postgui.hal
# net for control of motion.switchkins-type
HALCMD = net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type
# Values '(x,z)-offsets' for geometric offset of the rotary-assembly and the
# values '(x,y,z)-rot-point' that describe the position of the
# rotation-point of the rotary-assembly can be changed using the sliders
# in the axis-gui.
# Default values (initval) and ranges (min,max) are set
# in the corresponding 'scale' sections in the file 'xyzab-tdr.xml'
# vismach xyzab-tdr-gui items
HALCMD = loadusr -W xyzab-tdr-gui
HALCMD = net :axis-x joint.0.pos-fb xyzab-tdr-gui.axis-x
HALCMD = net :axis-y joint.1.pos-fb xyzab-tdr-gui.axis-y
HALCMD = net :axis-z joint.2.pos-fb xyzab-tdr-gui.axis-z
HALCMD = net :rotary-a joint.3.pos-fb xyzab-tdr-gui.rotary-a
HALCMD = net :rotary-b joint.4.pos-fb xyzab-tdr-gui.rotary-b
HALCMD = net :tool-offset motion.tooloffset.z xyzab-tdr-gui.tool_length
HALCMD = net :tool-diam halui.tool.diameter xyzab-tdr-gui.tool_diameter
HALCMD = net :x-offset xyzab-tdr-gui.x_offset
HALCMD = net :z-offset xyzab-tdr-gui.z_offset
HALCMD = net :x-rot-point xyzab-tdr-gui.x-rot-point
HALCMD = net :y-rot-point xyzab-tdr-gui.y-rot-point
HALCMD = net :z-rot-point xyzab-tdr-gui.z-rot-point
# xyzab_tdr_kins items
HALCMD = net :tool-offset xyzab_tdr_kins.tool-offset-z
HALCMD = net :x-offset xyzab_tdr_kins.x-offset
HALCMD = net :z-offset xyzab_tdr_kins.z-offset
HALCMD = net :x-rot-point xyzab_tdr_kins.x-rot-point
HALCMD = net :y-rot-point xyzab_tdr_kins.y-rot-point
HALCMD = net :z-rot-point xyzab_tdr_kins.z-rot-point
# This is only used to preset the vismach model to the default values as set
# in the xml scale widgets
# These will be overwritten by the values in the xml
HALCMD = sets :x-offset -20
HALCMD = sets :z-offset -10
[HALUI]
# M429:identity kins (motion.switchkins-type==0 startupDEFAULT)
# M428:xyzab-tdr kins (motion.switchkins-type==1)
MDI_COMMAND = M429
MDI_COMMAND = M428
[TRAJ]
COORDINATES = XYZAB
LINEAR_UNITS = mm
ANGULAR_UNITS = deg
DEFAULT_LINEAR_VELOCITY = 20
MAX_LINEAR_VELOCITY = 35
MAX_LINEAR_ACCELERATION = 400
DEFAULT_LINEAR_ACCELERATION = 300
[EMCMOT]
EMCMOT = motmod
SERVO_PERIOD = 1000000
COMM_TIMEOUT = 1
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[EMCIO]
TOOL_TABLE = xyzab-tdr.tbl
[AXIS_X]
MIN_LIMIT = -200
MAX_LIMIT = 200
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
[AXIS_Y]
MIN_LIMIT = -200
MAX_LIMIT = 200
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
[AXIS_Z]
MIN_LIMIT = -300
MAX_LIMIT = 300
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
[AXIS_A]
MIN_LIMIT = -3600
MAX_LIMIT = 3600
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
[AXIS_B]
MIN_LIMIT = -180
MAX_LIMIT = 180
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
[JOINT_0]
TYPE = LINEAR
HOME = 0
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
MIN_LIMIT = -200
MAX_LIMIT = 200
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_1]
TYPE = LINEAR
HOME = 0
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
MIN_LIMIT = -200
MAX_LIMIT = 200
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_2]
TYPE = LINEAR
HOME = 0
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
MIN_LIMIT = -300
MAX_LIMIT = 300
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_3]
TYPE = ANGULAR
HOME = 0
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
MIN_LIMIT = -3600
MAX_LIMIT = 3600
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_4]
TYPE = ANGULAR
HOME = 0
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
MIN_LIMIT = -180
MAX_LIMIT = 180
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0

View File

@@ -0,0 +1,4 @@
T1 P1 D1
T2 P2 Z30 D3
T3 P3 Z40 D4
T4 P4 Z50 D5

View File

@@ -0,0 +1,119 @@
5161 0.000000
5162 0.000000
5163 0.000000
5164 0.000000
5165 0.000000
5166 0.000000
5167 0.000000
5168 0.000000
5169 0.000000
5181 0.000000
5182 0.000000
5183 0.000000
5184 0.000000
5185 0.000000
5186 0.000000
5187 0.000000
5188 0.000000
5189 0.000000
5210 0.000000
5211 0.000000
5212 0.000000
5213 0.000000
5214 0.000000
5215 0.000000
5216 0.000000
5217 0.000000
5218 0.000000
5219 0.000000
5220 1.000000
5221 -70.000000
5222 -50.000000
5223 -110.000000
5224 0.000000
5225 0.000000
5226 0.000000
5227 0.000000
5228 0.000000
5229 0.000000
5230 0.000000
5241 0.000000
5242 0.000000
5243 0.000000
5244 0.000000
5245 0.000000
5246 0.000000
5247 0.000000
5248 0.000000
5249 0.000000
5250 0.000000
5261 0.000000
5262 0.000000
5263 0.000000
5264 0.000000
5265 0.000000
5266 0.000000
5267 0.000000
5268 0.000000
5269 0.000000
5270 0.000000
5281 0.000000
5282 0.000000
5283 0.000000
5284 0.000000
5285 0.000000
5286 0.000000
5287 0.000000
5288 0.000000
5289 0.000000
5290 0.000000
5301 0.000000
5302 0.000000
5303 0.000000
5304 0.000000
5305 0.000000
5306 0.000000
5307 0.000000
5308 0.000000
5309 0.000000
5310 0.000000
5321 0.000000
5322 0.000000
5323 0.000000
5324 0.000000
5325 0.000000
5326 0.000000
5327 0.000000
5328 0.000000
5329 0.000000
5330 0.000000
5341 0.000000
5342 0.000000
5343 0.000000
5344 0.000000
5345 0.000000
5346 0.000000
5347 0.000000
5348 0.000000
5349 0.000000
5350 0.000000
5361 0.000000
5362 0.000000
5363 0.000000
5364 0.000000
5365 0.000000
5366 0.000000
5367 0.000000
5368 0.000000
5369 0.000000
5370 0.000000
5381 0.000000
5382 0.000000
5383 0.000000
5384 0.000000
5385 0.000000
5386 0.000000
5387 0.000000
5388 0.000000
5389 0.000000
5390 0.000000

View File

@@ -0,0 +1,119 @@
5161 0.000000
5162 0.000000
5163 0.000000
5164 0.000000
5165 0.000000
5166 0.000000
5167 0.000000
5168 0.000000
5169 0.000000
5181 0.000000
5182 0.000000
5183 0.000000
5184 0.000000
5185 0.000000
5186 0.000000
5187 0.000000
5188 0.000000
5189 0.000000
5210 0.000000
5211 0.000000
5212 0.000000
5213 0.000000
5214 0.000000
5215 0.000000
5216 0.000000
5217 0.000000
5218 0.000000
5219 0.000000
5220 1.000000
5221 -70.000000
5222 -50.000000
5223 -110.000000
5224 0.000000
5225 0.000000
5226 0.000000
5227 0.000000
5228 0.000000
5229 0.000000
5230 0.000000
5241 0.000000
5242 0.000000
5243 0.000000
5244 0.000000
5245 0.000000
5246 0.000000
5247 0.000000
5248 0.000000
5249 0.000000
5250 0.000000
5261 0.000000
5262 0.000000
5263 0.000000
5264 0.000000
5265 0.000000
5266 0.000000
5267 0.000000
5268 0.000000
5269 0.000000
5270 0.000000
5281 0.000000
5282 0.000000
5283 0.000000
5284 0.000000
5285 0.000000
5286 0.000000
5287 0.000000
5288 0.000000
5289 0.000000
5290 0.000000
5301 0.000000
5302 0.000000
5303 0.000000
5304 0.000000
5305 0.000000
5306 0.000000
5307 0.000000
5308 0.000000
5309 0.000000
5310 0.000000
5321 0.000000
5322 0.000000
5323 0.000000
5324 0.000000
5325 0.000000
5326 0.000000
5327 0.000000
5328 0.000000
5329 0.000000
5330 0.000000
5341 0.000000
5342 0.000000
5343 0.000000
5344 0.000000
5345 0.000000
5346 0.000000
5347 0.000000
5348 0.000000
5349 0.000000
5350 0.000000
5361 0.000000
5362 0.000000
5363 0.000000
5364 0.000000
5365 0.000000
5366 0.000000
5367 0.000000
5368 0.000000
5369 0.000000
5370 0.000000
5381 0.000000
5382 0.000000
5383 0.000000
5384 0.000000
5385 0.000000
5386 0.000000
5387 0.000000
5388 0.000000
5389 0.000000
5390 0.000000

View File

@@ -0,0 +1,325 @@
<?xml version='1.0' encoding='UTF-8'?>
<pyvcp>
<vbox>
<relief>"ridge"</relief>
<bd>5</bd>
<multilabel>
<legends>["0:IDENTITY", "1: XYZAB ", "2: USERK "]</legends>
<font>("Helvetica",16)</font>
<bg>"black"</bg>
<fg>"yellow"</fg>
</multilabel>
<button>
<halpin>"type0-button"</halpin>
<text>"IDENTITY"</text>
<bd>3</bd>
</button>
<button>
<halpin>"type1-button"</halpin>
<text>"TCP:XYZAB"</text>
<bd>3</bd>
</button>
</vbox>
<!-- create a space to the next element -->
<vbox>
<hbox>
<label>
<text>" "</text>
<font>("Helvetica",4)</font>
</label>
</hbox>
</vbox>
<vbox>
<labelframe text="Joint position">
<font>("Helvetica",14)</font>
<hbox>
<vbox>
<hbox>
<label>
<text>"0: "</text>
<font>("Helvetica",10)</font>
</label>
<number>
<halpin>"joint0"</halpin>
<font>("Helvetica",10)</font>
<format>"4.4f"</format>
</number>
</hbox>
<hbox>
<label>
<text>"1: "</text>
<font>("Helvetica",10)</font>
</label>
<number>
<halpin>"joint1"</halpin>
<font>("Helvetica",10)</font>
<format>"4.4f"</format>
</number>
</hbox>
<hbox>
<label>
<text>"2: "</text>
<font>("Helvetica",10)</font>
</label>
<number>
<halpin>"joint2"</halpin>
<font>("Helvetica",10)</font>
<format>"4.4f"</format>
</number>
</hbox>
</vbox>
<vbox>
<label>
<text>" "</text>
<font>("Helvetica",10)</font>
</label>
</vbox>
<vbox>
<hbox>
<label>
<text>"3: "</text>
<font>("Helvetica",10)</font>
</label>
<number>
<halpin>"joint3"</halpin>
<font>("Helvetica",10)</font>
<format>"4.4f"</format>
</number>
</hbox>
<hbox>
<label>
<text>"4: "</text>
<font>("Helvetica",10)</font>
</label>
<number>
<halpin>"joint4"</halpin>
<font>("Helvetica",10)</font>
<format>"4.4f"</format>
</number>
</hbox>
<hbox>
<label>
<text>"5: "</text>
<font>("Helvetica",10)</font>
</label>
<number>
<halpin>"joint5"</halpin>
<font>("Helvetica",10)</font>
<format>"4.4f"</format>
</number>
</hbox>
</vbox>
</hbox>
</labelframe>
</vbox>
<!-- create a space to the next element -->
<vbox>
<hbox>
<label>
<text>" "</text>
<font>("Helvetica",4)</font>
</label>
</hbox>
</vbox>
<vbox>
<relief>"ridge"</relief>
<bd>5</bd>
<button>
<halpin>"vismach-clear"</halpin>
<text>"vismach-clear"</text>
<bd>3</bd>
</button>
</vbox>
<!-- create a space to the next element -->
<vbox>
<hbox>
<label>
<text>" "</text>
<font>("Helvetica",4)</font>
</label>
</hbox>
</vbox>
<vbox>
<labelframe text="Rotary Assembly Offset">
<font>("Helvetica",14)</font>
<hbox>
<label>
<text>"x-offset: "</text>
<font>("Helvetica",10)</font>
</label>
<scale>
<font>("Helvetica",10)</font>
<width>"15"</width>
<halpin>"x-offset"</halpin>
<resolution>1</resolution>
<orient>HORIZONTAL</orient>
<initval>-20</initval>
<min_>-50</min_>
<max_>50</max_>
</scale>
</hbox>
<hbox>
<label>
<text>"z-offset: "</text>
<font>("Helvetica",10)</font>
</label>
<scale>
<font>("Helvetica",10)</font>
<width>"15"</width>
<halpin>"z-offset"</halpin>
<resolution>1</resolution>
<orient>HORIZONTAL</orient>
<initval>-10</initval>
<min_>-50</min_>
<max_>50</max_>
</scale>
</hbox>
<hbox>
<label>
<font>("Helvetica",8)</font>
<text>" "</text>
</label>
</hbox>
<hbox>
<label>
<text>"Use hover + mouse wheel to change values"</text>
<font>("Helvetica",6)</font>
</label>
</hbox>
</labelframe>
</vbox>
<!-- create a space to the next element -->
<vbox>
<hbox>
<label>
<text>" "</text>
<font>("Helvetica",4)</font>
</label>
</hbox>
</vbox>
<vbox>
<labelframe text="Rotation Point Offset">
<font>("Helvetica",14)</font>
<hbox>
<label>
<text>" This should demonstrate that TCP kinematics\n require the 'rot-point' settings (yellow)\n to match the physical location\n of the rotation-point (red)."</text>
<font>("Helvetica",8)</font>
</label>
</hbox>
<hbox>
<label>
<font>("Helvetica",8)</font>
<text>" "</text>
</label>
</hbox>
<hbox>
<label>
<font>("Helvetica",8)</font>
<text>"Physical location of rotation-point in the model\n in absolute machine coordinates:"</text>
</label>
</hbox>
<hbox>
<label>
<font>("Helvetica",8)</font>
<text>" x: -50\n y: -50\n z: -100"</text>
</label>
</hbox>
<hbox>
<label>
<font>("Helvetica",8)</font>
<text>" "</text>
</label>
</hbox>
<hbox>
<label>
<font>("Helvetica",8)</font>
<text>"these are also the correct 'rot-point' settings\n for this model"</text>
</label>
</hbox>
<hbox>
<label>
<text>"x-rot-point: "</text>
<font>("Helvetica",10)</font>
</label>
<scale>
<font>("Helvetica",10)</font>
<width>"15"</width>
<halpin>"x-rot-point"</halpin>
<resolution>1</resolution>
<orient>HORIZONTAL</orient>
<initval>-50</initval>
<min_>-55</min_>
<max_>-45</max_>
</scale>
</hbox>
<hbox>
<label>
<text>"y-rot-point: "</text>
<font>("Helvetica",10)</font>
</label>
<scale>
<font>("Helvetica",10)</font>
<width>"15"</width>
<halpin>"y-rot-point"</halpin>
<resolution>1</resolution>
<orient>HORIZONTAL</orient>
<initval>-50</initval>
<min_>-55</min_>
<max_>-45</max_>
</scale>
</hbox>
<hbox>
<label>
<text>"z-rot-point: "</text>
<font>("Helvetica",10)</font>
</label>
<scale>
<font>("Helvetica",10)</font>
<width>"15"</width>
<halpin>"z-rot-point"</halpin>
<resolution>1</resolution>
<orient>HORIZONTAL</orient>
<initval>-100</initval>
<min_>-105</min_>
<max_>-95</max_>
</scale>
</hbox>
<hbox>
<label>
<font>("Helvetica",8)</font>
<text>" "</text>
</label>
</hbox>
<hbox>
<label>
<text>"Use hover + mouse wheel to change values"</text>
<font>("Helvetica",6)</font>
</label>
</hbox>
</labelframe>
</vbox>
<!-- create a space to the next element -->
<vbox>
<hbox>
<label>
<text>" "</text>
<font>("Helvetica",4)</font>
</label>
</hbox>
</vbox>
<vbox>
<hbox>
<label>
<text>" FOR PROPER TOOL-PATH PREVIEW \n RELOAD AND RESTART THE\n GCODE AFTER STARTUP AND\n AFTER CHANGING OFFSETS!"</text>
<font>("Helvetica",9)</font>
</label>
</hbox>
</vbox>
</pyvcp>

View File

@@ -0,0 +1,207 @@
# Sat Jun 06 15:59:10 CST 2026
#
# This file: ./xyzab-tdr_cmds.hal
# Created by: /home/cnc/桌面/cnc_wams/linuxcnc/lib/hallib/basic_sim.tcl
# With options:
# From inifile: /home/cnc/桌面/cnc_wams/linuxcnc/configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini
# Halfiles: LIB:basic_sim.tcl
#
# This file contains the hal commands produced by basic_sim.tcl
# (and any hal commands executed prior to its execution).
# ------------------------------------------------------------------
# To use ./xyzab-tdr_cmds.hal in the original inifile (or a copy of it),
# edit to change:
# [HAL]
# HALFILE = LIB:basic_sim.tcl parameters
# to:
# [HAL]
# HALFILE = ./xyzab-tdr_cmds.hal
#
# Notes:
# 1) Inifile Variables substitutions specified in the inifile
# and interpreted by halcmd are automatically substituted
# in the created halfile (./xyzab-tdr_cmds.hal).
# 2) Input pins connected to a signal with no writer are
# not included in the setp listings herein so must be added
# manually
#
# user space components
loadusr -W hal_manualtoolchange
# components
#preloaded module: loadrt tpmod
#preloaded module: loadrt homemod
loadrt xyzab_tdr_kins
loadrt motmod base_period_nsec=0 servo_period_nsec=1000000 num_joints=5
#loadrt __servo-thread (not loaded by loadrt, no args saved)
loadrt pid names=J0_pid,J1_pid,J2_pid,J3_pid,J4_pid
loadrt mux2 names=J0_mux,J1_mux,J2_mux,J3_mux,J4_mux
loadrt ddt names=J0_vel,J0_accel,J1_vel,J1_accel,J2_vel,J2_accel,J3_vel,J3_accel,J4_vel,J4_accel
loadrt sim_home_switch names=J0_switch,J1_switch,J2_switch,J3_switch,J4_switch
loadrt sim_spindle names=sim_spindle
loadrt limit2 names=limit_speed
loadrt lowpass names=spindle_mass
loadrt near names=near_speed
loadrt scale names=rpm_rps
# pin aliases
# param aliases
# signals
# nets
net J0:acc J0_accel.out
net J0:enable joint.0.amp-enable-out => J0_pid.enable
net J0:homesw J0_switch.home-sw => joint.0.home-sw-in
net J0:on-pos J0_pid.output => J0_mux.in1
net J0:pos-cmd joint.0.motor-pos-cmd => J0_pid.command
net J0:pos-fb J0_mux.out => J0_mux.in0 J0_switch.cur-pos J0_vel.in joint.0.motor-pos-fb
net J0:vel J0_vel.out => J0_accel.in
net J1:acc J1_accel.out
net J1:enable joint.1.amp-enable-out => J1_pid.enable
net J1:homesw J1_switch.home-sw => joint.1.home-sw-in
net J1:on-pos J1_pid.output => J1_mux.in1
net J1:pos-cmd joint.1.motor-pos-cmd => J1_pid.command
net J1:pos-fb J1_mux.out => J1_mux.in0 J1_switch.cur-pos J1_vel.in joint.1.motor-pos-fb
net J1:vel J1_vel.out => J1_accel.in
net J2:acc J2_accel.out
net J2:enable joint.2.amp-enable-out => J2_pid.enable
net J2:homesw J2_switch.home-sw => joint.2.home-sw-in
net J2:on-pos J2_pid.output => J2_mux.in1
net J2:pos-cmd joint.2.motor-pos-cmd => J2_pid.command
net J2:pos-fb J2_mux.out => J2_mux.in0 J2_switch.cur-pos J2_vel.in joint.2.motor-pos-fb
net J2:vel J2_vel.out => J2_accel.in
net J3:acc J3_accel.out
net J3:enable joint.3.amp-enable-out => J3_pid.enable
net J3:homesw J3_switch.home-sw => joint.3.home-sw-in
net J3:on-pos J3_pid.output => J3_mux.in1
net J3:pos-cmd joint.3.motor-pos-cmd => J3_pid.command
net J3:pos-fb J3_mux.out => J3_mux.in0 J3_switch.cur-pos J3_vel.in joint.3.motor-pos-fb
net J3:vel J3_vel.out => J3_accel.in
net J4:acc J4_accel.out
net J4:enable joint.4.amp-enable-out => J4_pid.enable
net J4:homesw J4_switch.home-sw => joint.4.home-sw-in
net J4:on-pos J4_pid.output => J4_mux.in1
net J4:pos-cmd joint.4.motor-pos-cmd => J4_pid.command
net J4:pos-fb J4_mux.out => J4_mux.in0 J4_switch.cur-pos J4_vel.in joint.4.motor-pos-fb
net J4:vel J4_vel.out => J4_accel.in
net estop:loop iocontrol.0.user-enable-out => iocontrol.0.emc-enable-in
net sample:enable motion.motion-enabled => J0_mux.sel J1_mux.sel J2_mux.sel J3_mux.sel J4_mux.sel
net spindle-at-speed near_speed.out => spindle.0.at-speed
net spindle-index-enable sim_spindle.index-enable <=> spindle.0.index-enable
net spindle-orient spindle.0.orient => spindle.0.is-oriented
net spindle-pos sim_spindle.position-fb => spindle.0.revs
net spindle-rpm-filtered spindle_mass.out => near_speed.in2 rpm_rps.in
net spindle-rps-filtered rpm_rps.out => spindle.0.speed-in
net spindle-speed-cmd spindle.0.speed-out => limit_speed.in near_speed.in1
net spindle-speed-limited limit_speed.out => sim_spindle.velocity-cmd spindle_mass.in
net tool:change iocontrol.0.tool-change => hal_manualtoolchange.change
net tool:changed hal_manualtoolchange.changed => iocontrol.0.tool-changed
net tool:prep-loop iocontrol.0.tool-prepare => iocontrol.0.tool-prepared
net tool:prep-number iocontrol.0.tool-prep-number => hal_manualtoolchange.number
# parameter values
setp J0_accel.tmax 0
setp J0_mux.tmax 0
setp J0_pid.do-pid-calcs.tmax 0
setp J0_switch.tmax 0
setp J0_vel.tmax 0
setp J1_accel.tmax 0
setp J1_mux.tmax 0
setp J1_pid.do-pid-calcs.tmax 0
setp J1_switch.tmax 0
setp J1_vel.tmax 0
setp J2_accel.tmax 0
setp J2_mux.tmax 0
setp J2_pid.do-pid-calcs.tmax 0
setp J2_switch.tmax 0
setp J2_vel.tmax 0
setp J3_accel.tmax 0
setp J3_mux.tmax 0
setp J3_pid.do-pid-calcs.tmax 0
setp J3_switch.tmax 0
setp J3_vel.tmax 0
setp J4_accel.tmax 0
setp J4_mux.tmax 0
setp J4_pid.do-pid-calcs.tmax 0
setp J4_switch.tmax 0
setp J4_vel.tmax 0
setp limit_speed.tmax 0
setp motion-command-handler.tmax 0
setp motion-controller.tmax 0
setp near_speed.difference 10
setp near_speed.scale 1.1
setp near_speed.tmax 0
setp rpm_rps.tmax 0
setp servo-thread.tmax 0
setp sim_spindle.scale 0.01666667
setp sim_spindle.tmax 0
setp spindle_mass.gain 0.07
setp spindle_mass.tmax 0
# realtime thread/function links
addf motion-command-handler servo-thread
addf motion-controller servo-thread
addf J0_pid.do-pid-calcs servo-thread
addf J1_pid.do-pid-calcs servo-thread
addf J2_pid.do-pid-calcs servo-thread
addf J3_pid.do-pid-calcs servo-thread
addf J4_pid.do-pid-calcs servo-thread
addf J0_mux servo-thread
addf J1_mux servo-thread
addf J2_mux servo-thread
addf J3_mux servo-thread
addf J4_mux servo-thread
addf J0_vel servo-thread
addf J0_accel servo-thread
addf J1_vel servo-thread
addf J1_accel servo-thread
addf J2_vel servo-thread
addf J2_accel servo-thread
addf J3_vel servo-thread
addf J3_accel servo-thread
addf J4_vel servo-thread
addf J4_accel servo-thread
addf J0_switch servo-thread
addf J1_switch servo-thread
addf J2_switch servo-thread
addf J3_switch servo-thread
addf J4_switch servo-thread
addf limit_speed servo-thread
addf spindle_mass servo-thread
addf rpm_rps servo-thread
addf near_speed servo-thread
addf sim_spindle servo-thread
# setp commands for unconnected input pins
setp J0_pid.FF0 1.0
setp J0_pid.Pgain 0
setp J0_pid.Dgain 0
setp J0_pid.Igain 0
setp J0_pid.FF1 0
setp J0_pid.FF2 0
setp J1_pid.FF0 1.0
setp J1_pid.Pgain 0
setp J1_pid.Dgain 0
setp J1_pid.Igain 0
setp J1_pid.FF1 0
setp J1_pid.FF2 0
setp J2_pid.FF0 1.0
setp J2_pid.Pgain 0
setp J2_pid.Dgain 0
setp J2_pid.Igain 0
setp J2_pid.FF1 0
setp J2_pid.FF2 0
setp J3_pid.FF0 1.0
setp J3_pid.Pgain 0
setp J3_pid.Dgain 0
setp J3_pid.Igain 0
setp J3_pid.FF1 0
setp J3_pid.FF2 0
setp J4_pid.FF0 1.0
setp J4_pid.Pgain 0
setp J4_pid.Dgain 0
setp J4_pid.Igain 0
setp J4_pid.FF1 0
setp J4_pid.FF2 0
setp sim_spindle.scale 0.01666667
setp limit_speed.maxv 5000.0
setp spindle_mass.gain .07
setp near_speed.scale 1.1
setp near_speed.difference 10

View File

@@ -0,0 +1,32 @@
Switchable Table Rotary/Tilting (trt) Sim configs
xyzac-trt-switchkins
xyzbc-trt-switchkins
Demonstrations:
demos/xyzac_switchkins.ngc
demos/xyzac_switchkins_test_1.ngc
demos/xyzac_switchkins_test_2.ngc
demos/xyzac_switchkins_test_3.ngc
demos/boat-xyzac.ngc
demos/impeller-7bl-xyzac.ngc
demos/xyzbc_switchkins.ngc
demos/boat-xyzbc.ngc
***********************************************
Note: IMPORTANT ini file requirements:
[HAL]
HALCMD = net :kinstype-select <= motion.analog-out-0N => motion.switchkins-type
[RS274NGC]
SUBROUTINE_PATH = ./remap_subs
REMAP = M428 modalgroup=10 ngc=428remap
REMAP = M429 modalgroup=10 ngc=429remap
[HALUI]
MDI_COMMAND = M429
MDI_COMMAND = M428
MDI_COMMAND = M430
***********************************************

View File

@@ -0,0 +1,3 @@
; zmax zmin r frate n a b c dist
o<xyzac_switchkins_sub> call [10] [5] [10][1000][3][20][0][45][20]
m2

View File

@@ -0,0 +1,39 @@
; for debugging, use mdi to set global #<_switchkins_debug>=1
#<FRATE>=1000
M429
G0 X0 Y0 Z0 A0 C0
G0 C90 X10 Y0
G1 F#<FRATE> Z2
M428
G1 F#<FRATE> Z0
M429
G1 F#<FRATE> Z2
G0 C90 X0 Y10
G1 F#<FRATE> Z0
M428
G1 F#<FRATE> Z2
M429
G1 F#<FRATE> Z0
G0 C90 X10 Y30
G1 F#<FRATE> Z2
M428
G1 F#<FRATE> Z0
M429
G1 F#<FRATE> Z2
G0 C90 X30 Y10
G1 F#<FRATE> Z0
M428
G1 F#<FRATE> Z2
M429
G1 F#<FRATE> Z0
G0 X0 Y0 Z0 A0 C0
M2

View File

@@ -0,0 +1,49 @@
; for debugging, use mdi to set global #<_switchkins_debug>=1
#<FRATE>=1000
M429 ;Trivkins
G64 P0.01
S1500 M3
G0 X0 Y0 Z5 A0 C0
G1 F#<FRATE> Z0
G1 X20 Y0 F#<FRATE>
M428 ;XYZAC
G1 C90
G1 X20
G1 Y20
G1 X0
G1 Y0
G1 A20
G1 X-20
G1 Y-20
G1 X0
G1 Y0
(-------)
G1 C45
G1 X-15
G1 Y15
G1 X0
G1 Y0
G1 Y-15
G1 X15
G1 Y0
G1 X0
(-------)
G1 C90 X15
G1 C180 Y15
G1 C270 X0
G1 C360 Y0
G1 C0
G1 C-90 X-15
G1 C-180 Y-15
G1 C-270 X0
G1 C-360 Y0
G1 Z5
M429 ;Trivkins
G1 X0 Y0 Z1 A0 C0
M2

View File

@@ -0,0 +1,15 @@
;# enable optional stop for m1
m429 ;trivkins
G0 X0 Y0 Z0 A0 C0
G0 C90 X10 Y0
G1 F1000 Z2
(debug,A expect: 10 0 2) m1
(debug,B expect: 10 0 2) m1
m428 ;tcp
(debug,C expect: 0 -10 2) m1
g1f1000 z0
(debug,D expect: 0 -10 0) m1
(debug,E expect: 0 -10 0) m1
m429 ;trivkins
(debug,F expect: 10 0 0)
m2

View File

@@ -0,0 +1,3 @@
; zmax zmin r frate n a b c dist
o<xyzbc_switchkins_sub> call [10] [5] [10][1000][3][0][20][45][20]
m2

View File

@@ -0,0 +1,24 @@
;M428 by remap: kinstype==1 (xyzac,xyzbc) (note: sparm=identityfirst)
o<428remap>sub
#<kinstype> = 1 ; xyzac,xyzbc
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M428:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M428: Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<428remap>endsub

View File

@@ -0,0 +1,24 @@
;M429 by remap: kinstype==0 Identity kinematics
o<429remap>sub
#<kinstype> = 0
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M429:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M429:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<429remap>endsub

View File

@@ -0,0 +1,24 @@
;M430 by remap: kinstype==2 userk kins
o<430remap>sub
#<kinstype> = 2
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M430:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M430:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<430remap>endsub

View File

@@ -0,0 +1,42 @@
(info: tests for values of [xyz]-rot-point)
o<centering>sub
#<xstart> = #1 (=-2.5)
#<ystart> = #2 (=-2.5)
#<xlen> = #3 (= 5)
#<ylen> = #4 (= 5)
#<zfinal> = #5 (=60)
#<n> = #6 (=12)
#<f> = #7 (=1000 feed)
#<angle> = 0
#<delta_angle> = [360/#<n>]
o1 if [exists [#<_hal[xyzac-trt-kins.x-rot-point]>]]
(debug,x-rot-point=#<_hal[xyzac-trt-kins.x-rot-point]>)
(debug,y-rot-point=#<_hal[xyzac-trt-kins.y-rot-point]>)
(debug,z-rot-point=#<_hal[xyzac-trt-kins.z-rot-point]>)
o1 endif
o2 if [exists [#<_hal[xyzbc-trt-kins.x-rot-point]>]]
(debug,x-rot-point=#<_hal[xyzbc-trt-kins.x-rot-point]>)
(debug,y-rot-point=#<_hal[xyzbc-trt-kins.y-rot-point]>)
(debug,z-rot-point=#<_hal[xyzac-trt-kins.z-rot-point]>)
o2 endif
M429 ;Identity kinematics
g0 x#<xstart> y#<ystart> z0 c0
M428 ;tcp
g61
o10 while [#<angle> le 360]
g1 f#<f>
#<angle> = [#<angle> + #<delta_angle>]
g0 c#<angle>
g1 x[#<xstart> + #<xlen>]
g1 y[#<ystart> + #<ylen>]
g1 x[#<xstart> + 0 ]
g1 y[#<ystart> + 0 ]
o10 endwhile
M429 ;Identity kinematics
g0 x0 y0 z#<zfinal> c0
o<centering>endsub

View File

@@ -0,0 +1,22 @@
; helix using switchkins (xyzac) a,c angles
o<helix_ac>sub
#<zmax> = #1 (=10)
#<zmin> = #2 (= 5)
#<r> = #3 (=10)
#<frate> = #4 (=1000)
#<n> = #5 (=3)
#<a> = #6 (=45)
#<b> = #7 (=0 NA)
#<c> = #8 (=20)
M429 ;Identity kinematics
g0 x[#<_x> - #<r>] ;adjust for radius
g10l20p0 x0y0 z#<zmax> a0 c0 ;new g54
M428 ;XYZAC
g0a#<a>c#<c> ;exercise a,c
f#<frate> g2i#<r>z#<zmin> p#<n> ;helix
M429 ;Identity kinematics
g0 x0 y0 z#<zmax> a0 c0 ;return to start
g0 x[#<_x> + #<r>] ;adjust restore
M428 ;XYZAC
o<helix_ac>endsub

View File

@@ -0,0 +1,22 @@
; helix using switchkins (xyzbc) b,c angles
o<helix_bc>sub
#<zmax> = #1 (=10)
#<zmin> = #2 (= 5)
#<r> = #3 (=10)
#<frate> = #4 (=1000)
#<n> = #5 (=3)
#<a> = #6 (=0 NA)
#<b> = #7 (=45)
#<c> = #8 (=20)
M429 ;Identity kinematics
g0 x[#<_x> - #<r>] ;adjust for radius
g10l20p0 x0y0 z#<zmax> b0 c0 ;new g54
M428 ;XYZBC
g0b#<b>c#<c> ;exercise b,c
f#<frate> g2i#<r>z#<zmin> p#<n> ;helix
M429 ;Identity kinematics
g0 x0 y0 z#<zmax> b0 c0 ;return to start
g0 x[#<_x> + #<r>] ;adjust restore
M428 ;XYZBC
o<helix_bc>endsub

View File

@@ -0,0 +1,47 @@
; ngcgui-compatible subroutine
(info: helix in each quadrant at angles A,C)
o<xyzac_switchkins_sub>sub
#<zmax> = #1 (=10)
#<zmin> = #2 (= 5)
#<r> = #3 (=10 radius)
#<frate> = #4 (=1000 feedrate)
#<n> = #5 (=3 n circles)
#<a> = #6 (=30 A angle)
#<b> = #7 (=0 B angle NA)
#<c> = #8 (=45 C angle)
#<dist> = #9 (=20 distance)
; quadrant I
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> a0 c0 ;MACHINE coordinates
g10l20p0 x0y0 z#<zmax> a0 c0 ;new g54
g0 x+#<dist> y+#<dist> z#<zmax> ;move to pattern center position
o<helix_ac> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant II
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> a0 c0
g10l20p0 x0y0 z#<zmax> a0 c0
g0 x-#<dist> y+#<dist> z#<zmax>
o<helix_ac> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant III
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> a0 c0
g10l20p0 x0y0 z#<zmax> a0 c0
g0 x-#<dist> y-#<dist> z#<zmax>
o<helix_ac> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant IV
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> a0 c0
g10l20p0 x0y0 z#<zmax> a0 c0
g0 x+#<dist> y-#<dist> z#<zmax>
o<helix_ac> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
;final position
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> ;MACHINE coordinates
g10l20p0 x0y0 z#<zmax> ;new g54
o<xyzac_switchkins_sub>endsub

View File

@@ -0,0 +1,47 @@
; ngcgui-compatible subroutine
(info: helix in each quadrant at angles B,C)
o<xyzbc_switchkins_sub>sub
#<zmax> = #1 (=10)
#<zmin> = #2 (= 5)
#<r> = #3 (=10 radius)
#<frate> = #4 (=1000 feedrate)
#<n> = #5 (=3 n circles)
#<a> = #6 (=0 A angle NA)
#<b> = #7 (=30 B angle)
#<c> = #8 (=45 C angle)
#<dist> = #9 (=20 distance)
; quadrant I
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> b0 c0 ;MACHINE coordinates
g10l20p0 x0y0 z#<zmax> b0 c0 ;new g54
g0 x+#<dist> y+#<dist> z#<zmax> ;move to pattern center position
o<helix_bc> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant II
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> b0 c0
g10l20p0 x0y0 z#<zmax> b0 c0
g0 x-#<dist> y+#<dist> z#<zmax>
o<helix_bc> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant III
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> b0 c0
g10l20p0 x0y0 z#<zmax> b0 c0
g0 x-#<dist> y-#<dist> z#<zmax>
o<helix_bc> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant IV
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> b0 c0
g10l20p0 x0y0 z#<zmax> b0 c0
g0 x+#<dist> y-#<dist> z#<zmax>
o<helix_bc> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
;final position
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> ;MACHINE coordinates
g10l20p0 x0y0 z#<zmax> ;new g54
o<xyzbc_switchkins_sub>endsub

View File

@@ -0,0 +1,29 @@
pin+motion.analog-out-03
pin+motion.switchkins-type
pin+joint.0.pos-cmd
pin+joint.1.pos-cmd
pin+joint.2.pos-cmd
pin+joint.3.pos-cmd
pin+joint.4.pos-cmd
pin+axis.x.pos-cmd
pin+axis.y.pos-cmd
pin+axis.z.pos-cmd
pin+axis.a.pos-cmd
pin+axis.b.pos-cmd
pin+axis.c.pos-cmd
pin+pyvcp.tcpkins-button
pin+pyvcp.identitykins-button
pin+pyvcp.vismach-clear
pin+kinstype-0
pin+kinstype-1
pin+halui.mdi-command-00
pin+halui.mdi-command-01
pin+kinstype.is-0
pin+kinstype.is-1
pin+kinstype.is-2

View File

@@ -0,0 +1,12 @@
# switchkins pyvcp connections for:
# xyzac-trt-kins.ini,xyzbc-trt-kins.ini
net :kinstype.is-0 <= kinstype.is-0 => pyvcp.multilabel.0.legend0
net :kinstype.is-1 <= kinstype.is-1 => pyvcp.multilabel.0.legend1
net :kinstype.is-2 <= kinstype.is-2 => pyvcp.multilabel.0.legend2
net :vismach-clear <= pyvcp.vismach-clear => vismach.plotclear
net :type0-button <= pyvcp.type0-button => halui.mdi-command-00
net :type1-button <= pyvcp.type1-button => halui.mdi-command-01
net :type2-button <= pyvcp.type2-button => halui.mdi-command-02

View File

@@ -0,0 +1,182 @@
[APPLICATIONS]
# uncomment to enable:
#APP = halshow --fformat %.5f switchkins.halshow
[EMC]
VERSION = 1.1
MACHINE = sim-xyzac-trt-kins (switchkins)
[DISPLAY]
GEOMETRY = XYZ-A
OPEN_FILE = ./demos/xyzac_switchkins.ngc
PYVCP = ./xyzac-trt.xml
JOG_AXES = XYZC
DISPLAY = axis
MAX_ANGULAR_VELOCITY = 360
MAX_LINEAR_VELOCITY = 1000
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
MAX_FEED_OVERRIDE = 2
PROGRAM_PREFIX = ../../nc_files
INTRO_GRAPHIC = emc2.gif
INTRO_TIME = 1
#EDITOR = geany
TOOL_EDITOR = tooledit z diam
TKPKG = Ngcgui 1.0
NGCGUI_FONT = Helvetica -12 normal
NGCGUI_SUBFILE = xyzac_switchkins_sub.ngc
NGCGUI_SUBFILE = centering.ngc
[RS274NGC]
SUBROUTINE_PATH = ./remap_subs
HAL_PIN_VARS = 1
REMAP = M428 modalgroup=10 ngc=428remap
REMAP = M429 modalgroup=10 ngc=429remap
REMAP = M430 modalgroup=10 ngc=430remap
PARAMETER_FILE = xyzac.var
[KINS]
#NOTE: for backwrds compatibility !!!!!!!!!!!!!!!!!!!
# default switchkins-type == 0 is xyzac-trt-kins
# here switchkins-type == 0 is identity kins
KINEMATICS = xyzac-trt-kins sparm=identityfirst
JOINTS = 5
[HAL]
HALUI = halui
HALFILE = LIB:basic_sim.tcl
POSTGUI_HALFILE = switchkins_postgui.hal
# net for control of motion.switchkins-type
HALCMD = net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type
# vismach xyzac-trt-gui items
HALCMD = loadusr -W xyzac-trt-gui
HALCMD = net :table-x joint.0.pos-fb xyzac-trt-gui.table-x
HALCMD = net :saddle-y joint.1.pos-fb xyzac-trt-gui.saddle-y
HALCMD = net :spindle-z joint.2.pos-fb xyzac-trt-gui.spindle-z
HALCMD = net :tilt-a joint.3.pos-fb xyzac-trt-gui.tilt-a
HALCMD = net :rotate-c joint.4.pos-fb xyzac-trt-gui.rotate-c
HALCMD = net :tool-offset motion.tooloffset.z
HALCMD = net :tool-offset xyzac-trt-kins.tool-offset xyzac-trt-gui.tool-offset
HALCMD = net :y-offset xyzac-trt-kins.y-offset xyzac-trt-gui.y-offset
HALCMD = net :z-offset xyzac-trt-kins.z-offset xyzac-trt-gui.z-offset
HALCMD = sets :y-offset 20
HALCMD = sets :z-offset 10
# not currently supported by xyzac-trt-gui:
HALCMD = setp xyzac-trt-kins.x-rot-point 0
HALCMD = setp xyzac-trt-kins.y-rot-point 0
HALCMD = setp xyzac-trt-kins.z-rot-point 0
HALCMD = setp xyzac-trt-kins.conventional-directions 0
[HALUI]
# NOTE: kinstype==0 is identity kins because sparm=identityfirst
# M429:identity kins (motion.switchkins-type==0 startupDEFAULT)
# M428:xyzac kins (motion.switchkins-type==1)
# M430:userk kins (motion.switchkins-type==2)
MDI_COMMAND = M429
MDI_COMMAND = M428
MDI_COMMAND = M430
[TRAJ]
COORDINATES = XYZAC
LINEAR_UNITS = mm
ANGULAR_UNITS = deg
DEFAULT_LINEAR_VELOCITY = 20
MAX_LINEAR_VELOCITY = 35
MAX_LINEAR_ACCELERATION = 400
DEFAULT_LINEAR_ACCELERATION = 300
[EMCMOT]
EMCMOT = motmod
SERVO_PERIOD = 1000000
COMM_TIMEOUT = 1
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[EMCIO]
TOOL_TABLE = xyzac-trt.tbl
[AXIS_X]
MIN_LIMIT = -200
MAX_LIMIT = 200
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
[AXIS_Y]
MIN_LIMIT = -100
MAX_LIMIT = 100
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
[AXIS_Z]
MIN_LIMIT = -120
MAX_LIMIT = 120
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
[AXIS_A]
MIN_LIMIT = -100
MAX_LIMIT = 50
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
[AXIS_C]
MIN_LIMIT = -36000
MAX_LIMIT = 36000
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
[JOINT_0]
TYPE = LINEAR
HOME = 0
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
MIN_LIMIT = -200
MAX_LIMIT = 200
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_1]
TYPE = LINEAR
HOME = 0
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
MIN_LIMIT = -100
MAX_LIMIT = 100
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_2]
TYPE = LINEAR
HOME = 0
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
MIN_LIMIT = -120
MAX_LIMIT = 120
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_3]
TYPE = ANGULAR
HOME = 0
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
MIN_LIMIT = -100
MAX_LIMIT = 50
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_4]
TYPE = ANGULAR
HOME = 0
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
MIN_LIMIT = -36000
MAX_LIMIT = 36000
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0

View File

@@ -0,0 +1,10 @@
T1 P1 Z0 D1 ;end mill
T2 P2 Z15 D8 ;end mill
T3 P3 Z0 D4.2 ;#7 tap drill
T4 P4 Z0 D10
T5 P5 Z30 D10
T6 P6 Z30 D10
T7 P7 Z30 D10
T8 P8 Z30 D10
T9 P9 Z30 D10
T10 P10 D0.5

View File

@@ -0,0 +1,37 @@
xyzac-trt-kins (switchkins)
Uses remapped user m codes for kins switch:
M429: Identity Kinematics
M428: XYZAC (TCP)
M430: userk Kinematics
A hal net is required to connect the
analog out pin N, Example (for N=3):
net :kinstype-select <= motion.analog-out-03
net :kinstype-select => motion.switchkins-type
Hal Input pins:
xyzac-trt-kins.y-offset
xyzac-trt-kins.z-offset
Y and Z offsets are the offsets from the center
of rotation of the A axis relative to the center
of rotation of the C axis.
Hal Input pins:
xyzac-trt-kins.x-rot-point
xyzac-trt-kins.y-rot-point
xyzac-trt-kins.z-rot-point
X, Y and Z rot-point pins represent the
offsets of the center of rotation of the C axis
relative to the machine absolute zero
Hal Input pins:
xyzac-trt-kins.conventional-directions
Pin conventional-directions is false by default. If true,
axis directions follow the conventions as defined
at https://linuxcnc.org/docs/html/gcode/machining-center.html#_rotational_axes

View File

@@ -0,0 +1,45 @@
<?xml version='1.0' encoding='UTF-8'?>
<pyvcp>
<vbox>
<relief>"ridge"</relief>
<bd>5</bd>
<label>
<text>"SWITCHKINS"</text>
<relief>RIDGE</relief>
<bd>3</bd>
</label>
<multilabel>
<legends>["0:IDENTITY", "1: XYZAC ", "2: USERK "]</legends>
<font>("Helvetica",16)</font>
<bg>"black"</bg>
<fg>"yellow"</fg>
</multilabel>
<button>
<halpin>"type0-button"</halpin>
<text>"IDENTITY"</text>
<bd>3</bd>
</button>
<button>
<halpin>"type1-button"</halpin>
<text>"TCP:XYZAC"</text>
<bd>3</bd>
</button>
<button>
<halpin>"type2-button"</halpin>
<text>"userk "</text>
<bd>3</bd>
</button>
</vbox>
<vbox>
<relief>"ridge"</relief>
<bd>5</bd>
<button>
<halpin>"vismach-clear"</halpin>
<text>"vismach-clear"</text>
<bd>3</bd>
</button>
</vbox>
</pyvcp>

View File

@@ -0,0 +1,207 @@
# Sat Jun 06 15:43:11 CST 2026
#
# This file: ./xyzac-trt_cmds.hal
# Created by: /home/cnc/桌面/cnc_wams/linuxcnc/lib/hallib/basic_sim.tcl
# With options:
# From inifile: /home/cnc/桌面/cnc_wams/linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini
# Halfiles: LIB:basic_sim.tcl
#
# This file contains the hal commands produced by basic_sim.tcl
# (and any hal commands executed prior to its execution).
# ------------------------------------------------------------------
# To use ./xyzac-trt_cmds.hal in the original inifile (or a copy of it),
# edit to change:
# [HAL]
# HALFILE = LIB:basic_sim.tcl parameters
# to:
# [HAL]
# HALFILE = ./xyzac-trt_cmds.hal
#
# Notes:
# 1) Inifile Variables substitutions specified in the inifile
# and interpreted by halcmd are automatically substituted
# in the created halfile (./xyzac-trt_cmds.hal).
# 2) Input pins connected to a signal with no writer are
# not included in the setp listings herein so must be added
# manually
#
# user space components
loadusr -W hal_manualtoolchange
# components
#preloaded module: loadrt tpmod
#preloaded module: loadrt homemod
loadrt xyzac-trt-kins sparm=identityfirst
loadrt motmod base_period_nsec=0 servo_period_nsec=1000000 num_joints=5
#loadrt __servo-thread (not loaded by loadrt, no args saved)
loadrt pid names=J0_pid,J1_pid,J2_pid,J3_pid,J4_pid
loadrt mux2 names=J0_mux,J1_mux,J2_mux,J3_mux,J4_mux
loadrt ddt names=J0_vel,J0_accel,J1_vel,J1_accel,J2_vel,J2_accel,J3_vel,J3_accel,J4_vel,J4_accel
loadrt sim_home_switch names=J0_switch,J1_switch,J2_switch,J3_switch,J4_switch
loadrt sim_spindle names=sim_spindle
loadrt limit2 names=limit_speed
loadrt lowpass names=spindle_mass
loadrt near names=near_speed
loadrt scale names=rpm_rps
# pin aliases
# param aliases
# signals
# nets
net J0:acc J0_accel.out
net J0:enable joint.0.amp-enable-out => J0_pid.enable
net J0:homesw J0_switch.home-sw => joint.0.home-sw-in
net J0:on-pos J0_pid.output => J0_mux.in1
net J0:pos-cmd joint.0.motor-pos-cmd => J0_pid.command
net J0:pos-fb J0_mux.out => J0_mux.in0 J0_switch.cur-pos J0_vel.in joint.0.motor-pos-fb
net J0:vel J0_vel.out => J0_accel.in
net J1:acc J1_accel.out
net J1:enable joint.1.amp-enable-out => J1_pid.enable
net J1:homesw J1_switch.home-sw => joint.1.home-sw-in
net J1:on-pos J1_pid.output => J1_mux.in1
net J1:pos-cmd joint.1.motor-pos-cmd => J1_pid.command
net J1:pos-fb J1_mux.out => J1_mux.in0 J1_switch.cur-pos J1_vel.in joint.1.motor-pos-fb
net J1:vel J1_vel.out => J1_accel.in
net J2:acc J2_accel.out
net J2:enable joint.2.amp-enable-out => J2_pid.enable
net J2:homesw J2_switch.home-sw => joint.2.home-sw-in
net J2:on-pos J2_pid.output => J2_mux.in1
net J2:pos-cmd joint.2.motor-pos-cmd => J2_pid.command
net J2:pos-fb J2_mux.out => J2_mux.in0 J2_switch.cur-pos J2_vel.in joint.2.motor-pos-fb
net J2:vel J2_vel.out => J2_accel.in
net J3:acc J3_accel.out
net J3:enable joint.3.amp-enable-out => J3_pid.enable
net J3:homesw J3_switch.home-sw => joint.3.home-sw-in
net J3:on-pos J3_pid.output => J3_mux.in1
net J3:pos-cmd joint.3.motor-pos-cmd => J3_pid.command
net J3:pos-fb J3_mux.out => J3_mux.in0 J3_switch.cur-pos J3_vel.in joint.3.motor-pos-fb
net J3:vel J3_vel.out => J3_accel.in
net J4:acc J4_accel.out
net J4:enable joint.4.amp-enable-out => J4_pid.enable
net J4:homesw J4_switch.home-sw => joint.4.home-sw-in
net J4:on-pos J4_pid.output => J4_mux.in1
net J4:pos-cmd joint.4.motor-pos-cmd => J4_pid.command
net J4:pos-fb J4_mux.out => J4_mux.in0 J4_switch.cur-pos J4_vel.in joint.4.motor-pos-fb
net J4:vel J4_vel.out => J4_accel.in
net estop:loop iocontrol.0.user-enable-out => iocontrol.0.emc-enable-in
net sample:enable motion.motion-enabled => J0_mux.sel J1_mux.sel J2_mux.sel J3_mux.sel J4_mux.sel
net spindle-at-speed near_speed.out => spindle.0.at-speed
net spindle-index-enable sim_spindle.index-enable <=> spindle.0.index-enable
net spindle-orient spindle.0.orient => spindle.0.is-oriented
net spindle-pos sim_spindle.position-fb => spindle.0.revs
net spindle-rpm-filtered spindle_mass.out => near_speed.in2 rpm_rps.in
net spindle-rps-filtered rpm_rps.out => spindle.0.speed-in
net spindle-speed-cmd spindle.0.speed-out => limit_speed.in near_speed.in1
net spindle-speed-limited limit_speed.out => sim_spindle.velocity-cmd spindle_mass.in
net tool:change iocontrol.0.tool-change => hal_manualtoolchange.change
net tool:changed hal_manualtoolchange.changed => iocontrol.0.tool-changed
net tool:prep-loop iocontrol.0.tool-prepare => iocontrol.0.tool-prepared
net tool:prep-number iocontrol.0.tool-prep-number => hal_manualtoolchange.number
# parameter values
setp J0_accel.tmax 0
setp J0_mux.tmax 0
setp J0_pid.do-pid-calcs.tmax 0
setp J0_switch.tmax 0
setp J0_vel.tmax 0
setp J1_accel.tmax 0
setp J1_mux.tmax 0
setp J1_pid.do-pid-calcs.tmax 0
setp J1_switch.tmax 0
setp J1_vel.tmax 0
setp J2_accel.tmax 0
setp J2_mux.tmax 0
setp J2_pid.do-pid-calcs.tmax 0
setp J2_switch.tmax 0
setp J2_vel.tmax 0
setp J3_accel.tmax 0
setp J3_mux.tmax 0
setp J3_pid.do-pid-calcs.tmax 0
setp J3_switch.tmax 0
setp J3_vel.tmax 0
setp J4_accel.tmax 0
setp J4_mux.tmax 0
setp J4_pid.do-pid-calcs.tmax 0
setp J4_switch.tmax 0
setp J4_vel.tmax 0
setp limit_speed.tmax 0
setp motion-command-handler.tmax 0
setp motion-controller.tmax 0
setp near_speed.difference 10
setp near_speed.scale 1.1
setp near_speed.tmax 0
setp rpm_rps.tmax 0
setp servo-thread.tmax 0
setp sim_spindle.scale 0.01666667
setp sim_spindle.tmax 0
setp spindle_mass.gain 0.07
setp spindle_mass.tmax 0
# realtime thread/function links
addf motion-command-handler servo-thread
addf motion-controller servo-thread
addf J0_pid.do-pid-calcs servo-thread
addf J1_pid.do-pid-calcs servo-thread
addf J2_pid.do-pid-calcs servo-thread
addf J3_pid.do-pid-calcs servo-thread
addf J4_pid.do-pid-calcs servo-thread
addf J0_mux servo-thread
addf J1_mux servo-thread
addf J2_mux servo-thread
addf J3_mux servo-thread
addf J4_mux servo-thread
addf J0_vel servo-thread
addf J0_accel servo-thread
addf J1_vel servo-thread
addf J1_accel servo-thread
addf J2_vel servo-thread
addf J2_accel servo-thread
addf J3_vel servo-thread
addf J3_accel servo-thread
addf J4_vel servo-thread
addf J4_accel servo-thread
addf J0_switch servo-thread
addf J1_switch servo-thread
addf J2_switch servo-thread
addf J3_switch servo-thread
addf J4_switch servo-thread
addf limit_speed servo-thread
addf spindle_mass servo-thread
addf rpm_rps servo-thread
addf near_speed servo-thread
addf sim_spindle servo-thread
# setp commands for unconnected input pins
setp J0_pid.FF0 1.0
setp J0_pid.Pgain 0
setp J0_pid.Dgain 0
setp J0_pid.Igain 0
setp J0_pid.FF1 0
setp J0_pid.FF2 0
setp J1_pid.FF0 1.0
setp J1_pid.Pgain 0
setp J1_pid.Dgain 0
setp J1_pid.Igain 0
setp J1_pid.FF1 0
setp J1_pid.FF2 0
setp J2_pid.FF0 1.0
setp J2_pid.Pgain 0
setp J2_pid.Dgain 0
setp J2_pid.Igain 0
setp J2_pid.FF1 0
setp J2_pid.FF2 0
setp J3_pid.FF0 1.0
setp J3_pid.Pgain 0
setp J3_pid.Dgain 0
setp J3_pid.Igain 0
setp J3_pid.FF1 0
setp J3_pid.FF2 0
setp J4_pid.FF0 1.0
setp J4_pid.Pgain 0
setp J4_pid.Dgain 0
setp J4_pid.Igain 0
setp J4_pid.FF1 0
setp J4_pid.FF2 0
setp sim_spindle.scale 0.01666667
setp limit_speed.maxv 5000.0
setp spindle_mass.gain .07
setp near_speed.scale 1.1
setp near_speed.difference 10

View File

@@ -0,0 +1,182 @@
[APPLICATIONS]
# uncomment to enable:
#APP = halshow --fformat %.5f switchkins.halshow
[EMC]
VERSION = 1.1
MACHINE = sim-xyzbc-trt-kins (switchkins)
[DISPLAY]
GEOMETRY = XYZB
OPEN_FILE = ./demos/xyzbc_switchkins.ngc
PYVCP = ./xyzbc-trt.xml
JOG_AXES = XYZC
DISPLAY = axis
MAX_ANGULAR_VELOCITY = 360
MAX_LINEAR_VELOCITY = 1000
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
MAX_FEED_OVERRIDE = 2
PROGRAM_PREFIX = ../../nc_files
INTRO_GRAPHIC = emc2.gif
INTRO_TIME = 1
#EDITOR = geany
TOOL_EDITOR = tooledit z diam
TKPKG = Ngcgui 1.0
NGCGUI_FONT = Helvetica -12 normal
NGCGUI_SUBFILE = xyzbc_switchkins_sub.ngc
NGCGUI_SUBFILE = centering.ngc
[RS274NGC]
SUBROUTINE_PATH = ./remap_subs
HAL_PIN_VARS = 1
REMAP = M428 modalgroup=10 ngc=428remap
REMAP = M429 modalgroup=10 ngc=429remap
REMAP = M430 modalgroup=10 ngc=430remap
PARAMETER_FILE = xyzbc.var
[KINS]
#NOTE: for backwrds compatibility !!!!!!!!!!!!!!!!!!!
# default switchkins-type == 0 is xyzbc-trt-kins
# here switchkins-type == 0 is identity kins
KINEMATICS = xyzbc-trt-kins sparm=identityfirst
JOINTS = 5
[HAL]
HALUI = halui
HALFILE = LIB:basic_sim.tcl
POSTGUI_HALFILE = switchkins_postgui.hal
# net for control of motion.switchkins-type
HALCMD = net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type
# vismach xyzbc-trt-gui items
HALCMD = loadusr -W xyzbc-trt-gui
HALCMD = net :table-x joint.0.pos-fb xyzbc-trt-gui.table-x
HALCMD = net :saddle-y joint.1.pos-fb xyzbc-trt-gui.saddle-y
HALCMD = net :spindle-z joint.2.pos-fb xyzbc-trt-gui.spindle-z
HALCMD = net :tilt-b joint.3.pos-fb xyzbc-trt-gui.tilt-b
HALCMD = net :rotate-c joint.4.pos-fb xyzbc-trt-gui.rotate-c
HALCMD = net :tool-offset motion.tooloffset.z
HALCMD = net :tool-offset xyzbc-trt-kins.tool-offset xyzbc-trt-gui.tool-offset
HALCMD = net :x-offset xyzbc-trt-kins.x-offset xyzbc-trt-gui.x-offset
HALCMD = net :z-offset xyzbc-trt-kins.z-offset xyzbc-trt-gui.z-offset
HALCMD = sets :x-offset -20
HALCMD = sets :z-offset -15
# not currently supported by xyzbc-trt-gui:
HALCMD = setp xyzbc-trt-kins.x-rot-point 0
HALCMD = setp xyzbc-trt-kins.y-rot-point 0
HALCMD = setp xyzbc-trt-kins.z-rot-point 0
HALCMD = setp xyzbc-trt-kins.conventional-directions 0
[HALUI]
# NOTE: kinstype==0 is identity kins because sparm=identityfirst
# M429:identity kins (motion.switchkins-type==0 startupDEFAULT)
# M428:xyzbc kins (motion.switchkins-type==1)
# M430:userk kins (motion.switchkins-type==2)
MDI_COMMAND = M429
MDI_COMMAND = M428
MDI_COMMAND = M430
[TRAJ]
COORDINATES = XYZBC
LINEAR_UNITS = mm
ANGULAR_UNITS = deg
DEFAULT_LINEAR_VELOCITY = 20
MAX_LINEAR_VELOCITY = 35
MAX_LINEAR_ACCELERATION = 400
DEFAULT_LINEAR_ACCELERATION = 300
[EMCMOT]
EMCMOT = motmod
SERVO_PERIOD = 1000000
COMM_TIMEOUT = 1
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[EMCIO]
TOOL_TABLE = xyzbc-trt.tbl
[AXIS_X]
MIN_LIMIT = -200
MAX_LIMIT = 200
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
[AXIS_Y]
MIN_LIMIT = -100
MAX_LIMIT = 100
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
[AXIS_Z]
MIN_LIMIT = -120
MAX_LIMIT = 120
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
[AXIS_B]
MIN_LIMIT = -36000
MAX_LIMIT = 36000
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
[AXIS_C]
MIN_LIMIT = -36000
MAX_LIMIT = 36000
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
[JOINT_0]
TYPE = LINEAR
HOME = 0
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
MIN_LIMIT = -200
MAX_LIMIT = 200
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_1]
TYPE = LINEAR
HOME = 0
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
MIN_LIMIT = -100
MAX_LIMIT = 100
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_2]
TYPE = LINEAR
HOME = 0
MAX_VELOCITY = 20
MAX_ACCELERATION = 300
MIN_LIMIT = -120
MAX_LIMIT = 120
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_3]
TYPE = ANGULAR
HOME = 0
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
MIN_LIMIT = -100
MAX_LIMIT = 50
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_4]
TYPE = ANGULAR
HOME = 0
MAX_VELOCITY = 30
MAX_ACCELERATION = 300
MIN_LIMIT = -36000
MAX_LIMIT = 36000
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0

View File

@@ -0,0 +1,2 @@
T1 P1 D1
T2 P2 Z10 D8

View File

@@ -0,0 +1,37 @@
xyzbc-trt-kins (switchkins)
Uses remapped user m codes for kins switch:
M429: Identity Kinematics
M428: XYZBC (TCP)
M430: userk Kinematics
A hal net is required to connect the
analog out pin N, Example (for N=3):
net :kinstype-select <= motion.analog-out-03
net :kinstype-select => motion.switchkins-type
Hal Input pins:
xyzbc-trt-kins.x-offset
xyzbc-trt-kins.z-offset
X and Z offsets are the offsets from the center
of rotation of the B axis relative to the center
of rotation of the C axis.
Hal Input pins:
xyzbc-trt-kins.x-rot-point
xyzbc-trt-kins.y-rot-point
xyzbc-trt-kins.z-rot-point
X, Y and Z rot-point pins represent the
offsets of the center of rotation of the C axis
relative to the machine absolute zero
Hal Input pins:
xyzbc-trt-kins.conventional-directions
Pin conventional-directions is false by default. If true,
axis directions follow the conventions as defined
at https://linuxcnc.org/docs/html/gcode/machining-center.html#_rotational_axes

View File

@@ -0,0 +1,45 @@
<?xml version='1.0' encoding='UTF-8'?>
<pyvcp>
<vbox>
<relief>"ridge"</relief>
<bd>5</bd>
<label>
<text>"SWITCHKINS"</text>
<relief>RIDGE</relief>
<bd>3</bd>
</label>
<multilabel>
<legends>["0:IDENTITY", "1: XYZBC ", "2: USERK "]</legends>
<font>("Helvetica",16)</font>
<bg>"black"</bg>
<fg>"yellow"</fg>
</multilabel>
<button>
<halpin>"type0-button"</halpin>
<text>"IDENTITY"</text>
<bd>3</bd>
</button>
<button>
<halpin>"type1-button"</halpin>
<text>"TCP:XYZBC"</text>
<bd>3</bd>
</button>
<button>
<halpin>"type2-button"</halpin>
<text>"userk"</text>
<bd>3</bd>
</button>
</vbox>
<vbox>
<relief>"ridge"</relief>
<bd>5</bd>
<button>
<halpin>"vismach-clear"</halpin>
<text>"vismach-clear"</text>
<bd>3</bd>
</button>
</vbox>
</pyvcp>

View File

@@ -0,0 +1,640 @@
/********************************************************************
* Description: interp_remap.cc
*
* Remapping support
*
* Author: Michael Haberler
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2011 All rights reserved.
*
********************************************************************/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#define BOOST_PYTHON_MAX_ARITY 4
#include "pythonplugin/python_plugin.hh"
#include "interp_python.hh"
#include <boost/python/list.hpp>
namespace bp = boost::python;
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rs274ngc.hh"
#include "rs274ngc_return.hh"
#include "rs274ngc_interp.hh"
#include "interp_internal.hh"
#include <rtapi_string.h>
#include <string>
#include <string_view>
bool Interp::is_m_code_remappable(int m_code)
{
// this is overdue for a bitset
return ((m_code > 199 && m_code < 1000) ||
(m_code > 0 && m_code < 100 && ems[m_code] == -1) ||
m_code == 0 ||
m_code == 1 ||
m_code == 6 ||
m_code == 7 ||
m_code == 8 ||
m_code == 9 ||
m_code == 60 ||
m_code == 61 ||
m_code == 62 ||
m_code == 63 ||
m_code == 64 ||
m_code == 65 ||
m_code == 66 ||
m_code == 67 ||
m_code == 68);
}
bool Interp::is_any_m_code_remapped(block_pointer block, setup_pointer settings)
{
for (const int m_mode : block->m_modes) {
if (m_mode == -1)
continue;
if (is_m_code_remappable(m_mode) && settings->m_remapped[m_mode])
return true;
}
return false;
}
bool Interp::is_user_defined_m_code(block_pointer block, setup_pointer settings, int m_group)
{
const int m_code = block->m_modes[m_group];
if (m_code < 0) return false;
return (is_m_code_remappable(m_code) && settings->m_remapped[m_code]);
}
bool Interp::is_g_code_remappable(int g_code)
{ return g_code > 0 && g_code < 1000 && gees[g_code] == -1; }
bool Interp::is_user_defined_g_code(int g_code)
{ return is_g_code_remappable(g_code) && _setup.g_remapped[g_code]; }
bool Interp::remap_in_progress(const char *code)
{
remap_pointer rp = remapping(code);
if (rp == NULL)
return false;
for (int i = _setup.remap_level; i > 0; i--) {
if (_setup.blocks[i].executing_remap == rp) {
// printf("---------------- remap_in_progress(%s): TRUE level=%d\n",code,i);
return true;
}
}
// printf("---------------- remap_in_progress(%s): FALSE\n",code);
return false;
}
int Interp::convert_remapped_code(block_pointer /*block*/,
setup_pointer settings,
int phase,
char letter,
int number)
{
remap_pointer remap;
char key[2];
int status;
block_pointer cblock;
bp::list plist;
char cmd[LINELEN];
if (number == -1)
logRemap("convert_remapped_code '%c'", letter);
else
logRemap("convert_remapped_code '%c%d'", letter, number);
switch (toupper(letter)) {
case 'M':
remap = settings->m_remapped[number];
break;
case 'G':
remap = settings->g_remapped[number];
break;
default:
key[0] = letter;
key[1] = '\0';
remap = remapping((const char *)key);
}
CHKS((remap == NULL), "BUG: convert_remapped_code: no remapping");
// remapped handlers may use Python code to
// setup environment before, and finish work after doing theirs.
// That's what prolog and epilog functions are for.
// These are described in the remap descriptor as read from INI.
// Since a remap is always executed in the context of a controlling block,
// this block now contains fields which hold dynamic remap information, like
// the breadcrumbs execution trail.
// Some of these fields are initialized here -
// conceptually the block stack is also a 'remap frame stack'.
// the O_call code will pick up the static descriptor and
// dynamic information through the block and call any prolog
// function before passing control to the actual handler procedure.
// On the corresponding O_endsub/O_return, any epilog function
// will be executed, doing any work not doable in an NGC file.
// Note that even Python-remapped execution is pulled through the
// oword mechanism - so no duplication of handler calling code
// is needed.
snprintf(cmd, sizeof(cmd),"O <%s> call ", REMAP_FUNC(remap));
// the controlling block holds all dynamic remap information.
cblock = &CONTROLLING_BLOCK(*settings);
cblock->executing_remap = remap; // the current descriptor
cblock->param_cnt = 0;
if (remap->argspec && (strchr(remap->argspec, '@') != NULL)) {
// append a positional argument list instead of local variables
// if user specified '@'
// named local params are dealt with in execute_call() when
// the new call frame is fully established
CHP(add_parameters(settings, cblock, &cmd[strlen(cmd)]));
}
if ((_setup.debugmask & EMC_DEBUG_REMAP) &&
(_setup.loggingLevel > 2)) {
logRemap("convert_remapped_code(%s)", cmd);
}
// good to go, pass to o-word call handling mechanism
status = read(cmd);
block_pointer eblock = &EXECUTING_BLOCK(*settings);
eblock->call_type = CT_REMAP;
CHKS(status != INTERP_OK,
"convert_remapped_code: initial read returned %s",
interp_status(status));
return(- phase);
}
// add_parameters - a built-in prolog function
//
// handles argspec and extracts required and optional items from the
// controlling block.
//
// if preparing for an NGC file, add local variables to
// the current oword subroutine call frame
//
// if posargs == NULL:
// add the named parameters as local variables to the current call frame
// if posargs != NULL:
// create a positional argument list as per argspec order
// instead of adding local variables
//
// also, generate a kwargs style dictionary of required and optional items
// in case a Python prolog is called
//
// 1. add all required and present optional words.
// 2. error on missing but required words.
// 4. handle '>' as to require a positive feed.
// 5. handle '^' as to require a positive speed.
// 6. handle 'N' as to add the line number.
//
// return INTERP_ERROR and propagate appropriate message if any errors so far
// else return INTERP_OK
//
// handling '@' (positional params) is dealt with in the calling procedure
int Interp::add_parameters(setup_pointer settings,
block_pointer cblock,
char *posarglist)
{
const char *code;
block_pointer block;
std::string missing, optional, required;
std::string msg;
std::string tail;
bool errored = false;
bool interp_error = false;
remap_pointer rptr = cblock->executing_remap;
context_pointer active_frame = &settings->sub_context[settings->call_level];
if (!rptr) {
ERS("BUG: add_parameters: remap_frame: executing_remap == NULL ");
}
code = rptr->name;
// if any Python handlers are present, create a kwargs dict
bool pydict = rptr->remap_py || rptr->prolog_func || rptr->epilog_func;
//argspec = rptr->argspec;
CHKS((rptr->argspec == NULL),"BUG: add_parameters: argspec = NULL");
std::string_view argspec = rptr->argspec;
for (auto s : argspec) {
if (isupper(s) && required.find_first_of(s) == std::string::npos) {
required += tolower(s);
}
if (islower(s) && optional.find_first_of(s) == std::string::npos) {
optional += s;
}
if ((s == '>' || s == '^' || s == 'N' || s == 'n')
&& required.find_first_of(s) == std::string::npos) {
required += s;
}
}
block = &CONTROLLING_BLOCK((*settings));
logNP("add_parameters code=%s argspec=%s call_level=%d r=%s o=%s pydict=%d\n",
code,
argspec.data(),
settings->call_level,
required.c_str(),
optional.c_str(),
pydict);
auto STORE
{
[&](const char* name, double value) -> void {
if (pydict) {
try {
active_frame->pystuff.impl->kwargs[name] = value;
}
catch (const bp::error_already_set&) {
PyErr_Print();
PyErr_Clear();
ERM("add parameters: can't add '%s' to args", name);
interp_error = true;
return;
}
}
if (posarglist) {
char actual[LINELEN];
snprintf(actual, sizeof(actual), "[%.4lf]", value);
strcat(posarglist, actual);
cblock->param_cnt++;
}
else {
add_named_param(name, 0);
store_named_param(settings, name, value, 0);
}
}
};
auto PARAM
{
[&](char spec, const char* name, bool flag, double value) -> void {
if (flag) {
if (required.find_first_of(spec) != std::string::npos
|| optional.find_first_of(spec) != std::string::npos) {
STORE(name, value);
}
}
else {
if (required.find_first_of(spec) != std::string::npos) {
missing += spec;
errored = true;
}
}
}
};
// step through argspec in order so positional args are built
// in the correct order
for (auto s: argspec) {
switch (tolower(s)) {
case 'a' : PARAM('a',"a",block->a_flag,block->a_number); break;
case 'b' : PARAM('b',"b",block->b_flag,block->b_number); break;
case 'c' : PARAM('c',"c",block->c_flag,block->c_number); break;
case 'd' : PARAM('d',"d",block->d_flag,block->d_number_float); break;
case 'e' : PARAM('e',"e",block->e_flag,block->e_number); break;
case 'f' : PARAM('f',"f",block->f_flag,block->f_number); break;
case 'h' : PARAM('h',"h",block->h_flag,(double) block->h_number); break;
case 'i' : PARAM('i',"i",block->i_flag,block->i_number); break;
case 'j' : PARAM('j',"j",block->j_flag,block->j_number); break;
case 'k' : PARAM('k',"k",block->k_flag,block->k_number); break;
case 'l' : PARAM('l',"l",block->l_flag,(double) block->l_number); break;
case 'p' : PARAM('p',"p",block->p_flag,block->p_number); break;
case 'q' : PARAM('q',"q",block->q_flag,block->q_number); break;
case 'r' : PARAM('r',"r",block->r_flag,block->r_number); break;
case 's' : PARAM('s',"s",block->s_flag,block->s_number); break;
case 't' : PARAM('t',"t",block->t_flag, (double) block->t_number); break;
case 'u' : PARAM('u',"u",block->u_flag,block->u_number); break;
case 'v' : PARAM('v',"v",block->v_flag,block->v_number); break;
case 'w' : PARAM('w',"w",block->w_flag,block->w_number); break;
case 'x' : PARAM('x',"x",block->x_flag,block->x_number); break;
case 'y' : PARAM('y',"y",block->y_flag,block->y_number); break;
case 'z' : PARAM('z',"z",block->z_flag,block->z_number); break;
case '-' : break; // ignore - backwards compatibility
default: ;
}
if (interp_error)
return INTERP_ERROR;
}
if (!missing.empty()) {
tail = " missing: ";
errored = true;
}
bool first = true;
for (auto s : missing) {
if (first) first = false;
else tail += ',';
tail += toupper(s);
}
// special cases:
// N...add line number
if (required.find_first_of('n') != std::string::npos || required.find_first_of('N') != std::string::npos) {
STORE("n", cblock->saved_line_number);
}
// >...require positive feed
if (required.find_first_of('>') != std::string::npos) {
if (settings->feed_rate > 0.0) {
STORE("f", settings->feed_rate);
}
else {
tail += "F>0,";
errored = true;
}
}
// ^...require positive speed
// FIXME: How do we decide which spindle they want to use? (andypugh 17/7/16)
if (required.find_first_of('^') != std::string::npos) {
if (settings->speed[0] > 0.0) {
STORE("s", settings->speed[0]);
}
else {
tail += "S>0,";
errored = true;
}
}
if (errored) {
ERS("user-defined %s:%s", code, tail.c_str());
}
return INTERP_OK;
}
// this looks up a remapping by unnormalized code (like G88.1)
remap_pointer Interp::remapping(const char *code)
{
remap_iterator n = _setup.remaps.find(code);
if (n != _setup.remaps.end())
return &n->second;
else
return NULL;
}
// parse options of the form:
// REMAP= M420 modalgroup=6 argspec=pq prolog=setnamedvars ngc=m43.ngc epilog=ignore_retvalue
// REMAP= M421 modalgroup=6 argspec=- prolog=setnamedvars python=m43func epilog=ignore_retvalue
int Interp::parse_remap(const char *inistring, int lineno)
{
char iniline[LINELEN];
char *argv[MAX_REMAPOPTS];
int argc = 0;
const char *code;
remap r;
bool errored = false;
int g1 = 0, g2 = 0;
int mcode = -1;
int gcode = -1;
char *s;
memset((void *)&r, 0, sizeof(remap));
r.modal_group = -1; // mark as unset, required param for m/g
r.motion_code = INT_MIN;
rtapi_strxcpy(iniline, inistring);
// strip trailing comments
if ((s = strchr(iniline, '#')) != NULL) {
*s = '\0';
}
char* saveptr;
s = strtok_r((char *) iniline, " \t", &saveptr);
while( s != NULL && argc < MAX_REMAPOPTS - 1) {
argv[argc++] = s;
s = strtok_r( NULL, " \t", &saveptr);
}
if (argc == MAX_REMAPOPTS) {
Error("parse_remap: too many arguments (max %d)", MAX_REMAPOPTS);
goto fail;
}
argv[argc] = NULL;
code = strstore(argv[0]);
r.name = code;
for (int i = 1; i < argc; i++) {
int kwlen = 0;
char *kw = argv[i];
char *arg = strchr(argv[i],'=');
if (arg != NULL) {
kwlen = arg - argv[i];
arg++;
if (!strlen(arg)) { // 'kw='
Error("option '%s' - zero length value: %d:REMAP = %s",
kw,lineno,inistring);
errored = true;
continue;
}
} else { // 'kw'
Error("option '%s' - missing '=<value>: %d:REMAP = %s",
kw,lineno,inistring);
errored = true;
continue;;
}
if (!strncasecmp(kw,"modalgroup",kwlen)) {
r.modal_group = atoi(arg);
continue;
}
if (!strncasecmp(kw,"argspec",kwlen)) {
size_t pos = strspn (arg,
"ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijklmnpqrstuvwxyz>^@");
if (pos != strlen(arg)) {
Error("argspec: illegal word '%c' - %d:REMAP = %s",
arg[pos],lineno,inistring);
errored = true;
continue;
}
r.argspec = strstore(arg);
continue;
}
if (!strncasecmp(kw,"prolog",kwlen)) {
if (PYUSABLE) {
r.prolog_func = strstore(arg);
} else {
Error("Python plugin required for prolog=, but not available: %d:REMAP = %s",
lineno,inistring);
errored = true;
continue;
}
continue;
}
if (!strncasecmp(kw,"epilog",kwlen)) {
if (PYUSABLE) {
r.epilog_func = strstore(arg);
} else {
Error("Python plugin required for epilog=, but not available: %d:REMAP = %s",
lineno,inistring);
errored = true;
continue;
}
continue;
}
if (!strncasecmp(kw,"ngc",kwlen)) {
if (r.remap_py) {
Error("can\'t remap to an ngc file and a Python function: - %d:REMAP = %s",
lineno,inistring);
errored = true;
continue;
}
FILE *fp = find_ngc_file(&_setup,arg);
if (fp) {
r.remap_ngc = strstore(arg);
fclose(fp);
} else {
Error("INTERP_REMAP: NGC file not found: ngc=%s\nREMAP INI Line:%d = %s\n",
arg, lineno, inistring);
errored = true;
}
continue;
}
if (!strncasecmp(kw,"python",kwlen)) {
if (r.remap_ngc ) {
Error("can\'t remap to an ngc file and a Python function: - %d:REMAP = %s",
lineno,inistring);
errored = true;
continue;
}
if (!PYUSABLE) {
Error("iNTERP_REMAP: Python plugin required for python=, but not available:\nREMAP INI line:%d = %s\n",
lineno,inistring);
errored = true;
continue;
}
if (!is_pycallable(&_setup, REMAP_MODULE, arg)) {
Error("'%s' is not a Python callable function - %d:REMAP = %s",
arg,lineno,inistring);
errored = true;
continue;
}
r.remap_py = strstore(arg);
continue;
}
Error("unrecognized option '%*s' in %d:REMAP = %s",
kwlen,kw,lineno,inistring);
}
if (errored) {
goto fail;
}
if (remapping(code)) {
Error("code '%s' already remapped : %d:REMAP = %s",
code,lineno,inistring);
goto fail;
}
// it is an error not to define a remap function to call.
if ((r.remap_ngc == NULL) && (r.remap_py == NULL)) {
Error("code '%s' - no remap function given, use either 'python=<function>' or 'ngc=<basename>' : %d:REMAP = %s",
code,lineno,inistring);
goto fail;
}
#define CHECK(bad, fmt, ...) \
do { \
if (bad) { \
Log(fmt, ## __VA_ARGS__); \
goto fail; \
} \
} while(0)
switch (towlower(*code)) {
case 't':
case 's':
case 'f':
CHECK((strlen(code) > 1),"%d: %c remap - only single letter code allowed", lineno, *code);
CHECK((r.modal_group != -1), "%d: %c remap - modal group setting ignored - fixed sequencing", lineno, *code);
_setup.remaps[code] = r;
break;
case 'm':
if (sscanf(code + 1, "%d", &mcode) != 1) {
Error("parsing M-code: expecting integer like 'M420', got '%s' : %d:REMAP = %s",
code,lineno,inistring);
goto fail;
}
if (r.modal_group == -1) {
Error("warning: code '%s' : no modalgroup=<int> given, using default group %d : %d:REMAP = %s",
code, MCODE_DEFAULT_MODAL_GROUP,lineno,inistring);
r.modal_group = MCODE_DEFAULT_MODAL_GROUP;
}
if (!M_MODE_OK(r.modal_group)) {
Error("error: code '%s' : invalid modalgroup=<int> given (currently valid: 4..10) : %d:REMAP = %s",
code,lineno,inistring);
goto fail;
}
_setup.remaps[code] = r;
_setup.m_remapped[mcode] = &_setup.remaps[code];
break;
case 'g':
// code may be G88.1 or so - normalize to use 'G881' instead
// (multiply by 10, no dots)
if (sscanf(code + 1, "%d.%d", &g1, &g2) == 2) {
gcode = g1 * 10 + g2;
}
if ( gcode == -1) {
if (sscanf(code + 1, "%d", &gcode) != 1) {
Error("code '%s' : can\'t parse G-code : %d:REMAP = %s",
code, lineno, inistring);
goto fail;
}
gcode *= 10;
}
r.motion_code = gcode;
if (r.modal_group == -1) {
Error("warning: code '%s' : no modalgroup=<int> given, using default group %d : %d:REMAP = %s",
code, GCODE_DEFAULT_MODAL_GROUP, lineno, inistring);
r.modal_group = GCODE_DEFAULT_MODAL_GROUP;
}
if (!G_MODE_OK(r.modal_group)) {
Error("error: code '%s' : %s modalgroup=<int> given : %d:REMAP = %s",
argv[0],
r.modal_group == -1 ? "no" : "invalid",
lineno,
inistring);
goto fail;
}
_setup.remaps[code] = r;
_setup.g_remapped[gcode] = &_setup.remaps[code];
break;
default:
// make sure the python plugin is in a usable state if needed
if ((r.prolog_func || r.remap_py || r.epilog_func) &&
(!PYUSABLE)) {
fprintf(stderr, "fatal: REMAP requires the Python plugin, which did not initialize\n");
break;
}
Log("REMAP BUG=%s %d:REMAP = %s",
code,lineno,inistring);
}
return INTERP_OK;
fail:
return INTERP_ERROR;
}