结论:已将 LinuxCNC identity/trivial kinematics 源码纳入 WASM port 的 vendored manifest、native probe 和文档验证链,完整 native 验证通过。
This commit is contained in:
2026-06-07 18:56:38 +08:00
parent d5c5b0852f
commit 55f6659993
14 changed files with 702 additions and 8 deletions

View File

@@ -52,6 +52,7 @@ The validation fails if:
| `linuxcnc_interp_minimal_harness` | Runs G-code fixtures through vendored LinuxCNC parser/execution/conversion code and captures canonical events. | | `linuxcnc_interp_minimal_harness` | Runs G-code fixtures through vendored LinuxCNC parser/execution/conversion code and captures canonical events. |
| `linuxcnc_parameter_file_harness` | Validates LinuxCNC parameter file restore/save behavior and required/read-only parameter handling. | | `linuxcnc_parameter_file_harness` | Validates LinuxCNC parameter file restore/save behavior and required/read-only parameter handling. |
| `linuxcnc_tp_api_probe` | Validates vendored LinuxCNC trajectory planner calls for linear, arc, and queued motion paths. | | `linuxcnc_tp_api_probe` | Validates vendored LinuxCNC trajectory planner calls for linear, arc, and queued motion paths. |
| `linuxcnc_kinematics_probe` | Validates vendored LinuxCNC `trivkins.c` plus `kins_util.c` initialize and perform identity forward/inverse mapping through the standalone HAL/RTAPI boundary. |
## Fixture Coverage ## Fixture Coverage
@@ -93,3 +94,6 @@ machine-session validation remain future work.
The current fixture expectations validate standalone behavior against the The current fixture expectations validate standalone behavior against the
vendored LinuxCNC source path. They do not yet run a side-by-side native vendored LinuxCNC source path. They do not yet run a side-by-side native
LinuxCNC executable comparison for each fixture. LinuxCNC executable comparison for each fixture.
The kinematics probe currently covers LinuxCNC identity/trivial kinematics
only. Non-trivial and 5-axis kinematics still need dedicated machine baselines.

View File

@@ -29,6 +29,7 @@ semantic rewrites:
| Python/remap | Python/remap hooks are stubbed at the runtime edge. | | Python/remap | Python/remap hooks are stubbed at the runtime edge. |
| Dynamic interpreter path | `interp_base.cc` probe uses standalone `EMC2_HOME` compile-time path boundary. | | Dynamic interpreter path | `interp_base.cc` probe uses standalone `EMC2_HOME` compile-time path boundary. |
| Realtime scheduler | TP probes seed deterministic status/config data instead of running LinuxCNC realtime process topology. | | Realtime scheduler | TP probes seed deterministic status/config data instead of running LinuxCNC realtime process topology. |
| Kinematics component lifecycle | `trivkins.c` is initialized through its LinuxCNC module entry point while HAL component init/ready/exit and RTAPI module metadata are handled by standalone shims. |
| Browser storage | OPFS remains outside the native core and is not yet connected. | | Browser storage | OPFS remains outside the native core and is not yet connected. |
## Enforced Non-Drift Rules ## Enforced Non-Drift Rules
@@ -46,8 +47,9 @@ semantic rewrites:
- No browser/WASM parity tests yet. - No browser/WASM parity tests yet.
- No JS SDK validation yet. - No JS SDK validation yet.
- No OPFS persistence validation yet. - No OPFS persistence validation yet.
- Full kinematics implementation files are not yet extracted. - Identity/trivial kinematics now have native source-probe coverage; non-trivial
- Full 3-axis, non-trivial kinematics, and 5-axis machine baselines are not and 5-axis kinematics implementation files are not yet extracted.
- Full machine baselines beyond the identity/trivial kinematics probe are not
established. established.
- Fixture expectations are currently checked against the standalone vendored - Fixture expectations are currently checked against the standalone vendored
source path, not by running a native LinuxCNC binary for every fixture. source path, not by running a native LinuxCNC binary for every fixture.

View File

@@ -59,6 +59,6 @@ Negative fixture coverage includes:
- missing tool - missing tool
- missing tool length offset - missing tool length offset
Machine baseline is still limited to standalone interpreter and trajectory Machine baseline is still limited to standalone interpreter, trajectory
planner probes. Full 3-axis, non-trivial kinematics, and 5-axis machine planner, and LinuxCNC identity/trivial kinematics probes. Non-trivial
baselines remain future work. kinematics and 5-axis machine baselines remain future work.

View File

@@ -35,7 +35,7 @@ Current validation is intentionally mechanical:
| RTAPI compatibility headers | `src/rtapi/rtapi_*.h` in the manifest | Copy unchanged plus standalone shim include path | `runtime/core/shims/rtapi.h` supplies the minimal standalone RTAPI surface needed by vendored code | Vendor byte sync, compile coverage through dependent source probes | | RTAPI compatibility headers | `src/rtapi/rtapi_*.h` in the manifest | Copy unchanged plus standalone shim include path | `runtime/core/shims/rtapi.h` supplies the minimal standalone RTAPI surface needed by vendored code | Vendor byte sync, compile coverage through dependent source probes |
| Canon/NML-facing interpreter types | `src/emc/nml_intf/canon*.hh`, `emctool.h`, `interp_return.hh`, `motion_types.h`, `emcpose.*`, `emcpos.h`, `debugflags.h`, `src/emc/linuxcnc.h` | Copy unchanged | NML transport is not ported; wrappers provide only the status/type edges needed by standalone probes | Vendor byte sync, dependent source probes, `linuxcnc_tp_api_probe`, interpreter harnesses | | Canon/NML-facing interpreter types | `src/emc/nml_intf/canon*.hh`, `emctool.h`, `interp_return.hh`, `motion_types.h`, `emcpose.*`, `emcpos.h`, `debugflags.h`, `src/emc/linuxcnc.h` | Copy unchanged | NML transport is not ported; wrappers provide only the status/type edges needed by standalone probes | Vendor byte sync, dependent source probes, `linuxcnc_tp_api_probe`, interpreter harnesses |
| Motion state headers | `src/emc/motion/state_tag.h`, `emcmotcfg.h`, `simple_tp.h`, `motion.h`, `mot_priv.h`, `axis.h` | Copy unchanged | Realtime motion process is not ported; standalone probes seed the small motion status/config state required by TP calls | Vendor byte sync, `linuxcnc_tp_api_probe` | | Motion state headers | `src/emc/motion/state_tag.h`, `emcmotcfg.h`, `simple_tp.h`, `motion.h`, `mot_priv.h`, `axis.h` | Copy unchanged | Realtime motion process is not ported; standalone probes seed the small motion status/config state required by TP calls | Vendor byte sync, `linuxcnc_tp_api_probe` |
| Kinematics headers | `src/emc/kinematics/kinematics.h`, `cubic.h` | Copy unchanged | Kinematics implementation modules are not yet extracted; current use is type/interface support | Vendor byte sync, dependent compile coverage | | 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` |
| 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 | Vendor byte sync, per-file source probes, `linuxcnc_tp_api_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 | Vendor byte sync, per-file source probes, `linuxcnc_tp_api_probe` |
| 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 | | 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 |
| Posemath | `src/libnml/posemath/posemath.cc`, `_posemath.c`, `gomath.c`, `sincos.c`, and matching headers | Copy unchanged | `gomath.c` is compiled as C; `rtapi.h` shim is C/C++ compatible for this boundary | Vendor byte sync, per-file source probes, TP probe | | Posemath | `src/libnml/posemath/posemath.cc`, `_posemath.c`, `gomath.c`, `sincos.c`, and matching headers | Copy unchanged | `gomath.c` is compiled as C; `rtapi.h` shim is C/C++ compatible for this boundary | Vendor byte sync, per-file source probes, TP probe |
@@ -51,7 +51,7 @@ Current validation is intentionally mechanical:
| Native file IO | `inifile.cc`, `rs274ngc_pre.cc`, parameter file paths | Allowed in native probes; browser OPFS remains a host-side future adapter | | Native file IO | `inifile.cc`, `rs274ngc_pre.cc`, parameter file paths | Allowed in native probes; browser OPFS remains a host-side future adapter |
| 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 structs/types needed by vendored compute code are used | | NML transport | `emc.hh`, motion/NML type headers | Transport is not ported; only structs/types needed by vendored compute code are used |
| HAL runtime | named parameter lookup 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 | Stubbed at runtime boundary; no Python CNC semantics are reimplemented |
| 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 |
@@ -59,7 +59,7 @@ Current validation is intentionally mechanical:
## Known Gaps ## Known Gaps
- Full kinematics implementation files are not yet extracted. - Full non-trivial and 5-axis kinematics implementation files are not yet extracted.
- Browser/WASM C ABI and JS SDK layers are not yet built for the full - Browser/WASM C ABI and JS SDK layers are not yet built for the full
interpreter/planner core. interpreter/planner core.
- OPFS persistence is not yet connected to INI, tool table, parameter file, or - OPFS persistence is not yet connected to INI, tool table, parameter file, or

View File

@@ -91,6 +91,11 @@ int hal_ready(int)
return 0; return 0;
} }
int hal_exit(int)
{
return 0;
}
int hal_get_pin_value_by_name(const char *name, hal_type_t *type, hal_data_u **ptr, int hal_get_pin_value_by_name(const char *name, hal_type_t *type, hal_data_u **ptr,
bool *connected) bool *connected)
{ {

View File

@@ -0,0 +1,81 @@
#include <iostream>
#include "emc/kinematics/kinematics.h"
#include "emc/motion/emcmotcfg.h"
int rtapi_app_main(void);
void rtapi_app_exit(void);
namespace {
void print_pose(const char *prefix, const EmcPose &pose)
{
std::cout << prefix << "_xyz="
<< pose.tran.x << ","
<< pose.tran.y << ","
<< pose.tran.z << "\n";
std::cout << prefix << "_abcuvw="
<< pose.a << ","
<< pose.b << ","
<< pose.c << ","
<< pose.u << ","
<< pose.v << ","
<< pose.w << "\n";
}
void print_joints(const char *prefix, const double *joints)
{
std::cout << prefix << "_xyz="
<< joints[0] << ","
<< joints[1] << ","
<< joints[2] << "\n";
std::cout << prefix << "_abcuvw="
<< joints[3] << ","
<< joints[4] << ","
<< joints[5] << ","
<< joints[6] << ","
<< joints[7] << ","
<< joints[8] << "\n";
}
} // namespace
int main()
{
const int init_rc = rtapi_app_main();
std::cout << "kinematics_init=" << init_rc << "\n";
std::cout << "kinematics_type=" << kinematicsType() << "\n";
std::cout << "kinematics_switchable=" << kinematicsSwitchable() << "\n";
std::cout << "kinematics_switch=" << kinematicsSwitch(0) << "\n";
double joints[EMCMOT_MAX_JOINTS]{};
for (int index = 0; index < 9; ++index) {
joints[index] = index + 1;
}
EmcPose forward_pose{};
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
const int forward_rc = kinematicsForward(joints, &forward_pose, &fflags, &iflags);
std::cout << "kinematics_forward=" << forward_rc << "\n";
print_pose("kinematics_forward", forward_pose);
EmcPose inverse_pose{};
inverse_pose.tran.x = 10.0;
inverse_pose.tran.y = 20.0;
inverse_pose.tran.z = 30.0;
inverse_pose.a = 40.0;
inverse_pose.b = 50.0;
inverse_pose.c = 60.0;
inverse_pose.u = 70.0;
inverse_pose.v = 80.0;
inverse_pose.w = 90.0;
double inverse_joints[EMCMOT_MAX_JOINTS]{};
const int inverse_rc = kinematicsInverse(&inverse_pose, inverse_joints, &iflags, &fflags);
std::cout << "kinematics_inverse=" << inverse_rc << "\n";
print_joints("kinematics_inverse", inverse_joints);
rtapi_app_exit();
return 0;
}

View File

@@ -32,6 +32,7 @@ typedef unsigned long long hal_u64_t;
int hal_init(const char *); int hal_init(const char *);
int hal_ready(int); int hal_ready(int);
int hal_exit(int);
int hal_get_pin_value_by_name(const char *, hal_type_t *, hal_data_u **, bool *); int hal_get_pin_value_by_name(const char *, hal_type_t *, hal_data_u **, bool *);
int hal_get_signal_value_by_name(const char *, hal_type_t *, hal_data_u **, bool *); int hal_get_signal_value_by_name(const char *, hal_type_t *, hal_data_u **, bool *);
int hal_get_param_value_by_name(const char *, hal_type_t *, hal_data_u **); int hal_get_param_value_by_name(const char *, hal_type_t *, hal_data_u **);

View File

@@ -30,6 +30,58 @@
#define EXPORT_SYMBOL(symbol) #define EXPORT_SYMBOL(symbol)
#endif #endif
#ifndef EXPORT_SYMBOL_GPL
#define EXPORT_SYMBOL_GPL(symbol)
#endif
#ifndef MODULE_LICENSE
#define MODULE_LICENSE(value)
#endif
#ifndef MODULE_AUTHOR
#define MODULE_AUTHOR(value)
#endif
#ifndef MODULE_DESCRIPTION
#define MODULE_DESCRIPTION(value)
#endif
#ifndef MODULE_SUPPORTED_DEVICE
#define MODULE_SUPPORTED_DEVICE(value)
#endif
#ifndef MODULE_DEVICE_TABLE
#define MODULE_DEVICE_TABLE(type, name)
#endif
#ifndef MODULE_INFO
#define MODULE_INFO(tag, value)
#endif
#ifndef RTAPI_MP_INT
#define RTAPI_MP_INT(var, descr)
#endif
#ifndef RTAPI_MP_LONG
#define RTAPI_MP_LONG(var, descr)
#endif
#ifndef RTAPI_MP_STRING
#define RTAPI_MP_STRING(var, descr)
#endif
#ifndef RTAPI_MP_ARRAY_INT
#define RTAPI_MP_ARRAY_INT(var, num, descr)
#endif
#ifndef RTAPI_MP_ARRAY_LONG
#define RTAPI_MP_ARRAY_LONG(var, num, descr)
#endif
#ifndef RTAPI_MP_ARRAY_STRING
#define RTAPI_MP_ARRAY_STRING(var, num, descr)
#endif
typedef enum { typedef enum {
RTAPI_MSG_NONE = 0, RTAPI_MSG_NONE = 0,
RTAPI_MSG_ERR, RTAPI_MSG_ERR,

View File

@@ -79,6 +79,8 @@ check_exitcode linuxcnc_interp_state_probe
check_exitcode linuxcnc_inifile_source_probe check_exitcode linuxcnc_inifile_source_probe
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.run
for name in \ for name in \
linuxcnc_tp_tp_source_probe \ linuxcnc_tp_tp_source_probe \
linuxcnc_tp_tc_source_probe \ linuxcnc_tp_tc_source_probe \
@@ -119,6 +121,8 @@ check_exitcode linuxcnc_interp_minimal_harness.run
check_exitcode linuxcnc_parameter_file_harness check_exitcode linuxcnc_parameter_file_harness
check_exitcode linuxcnc_parameter_file_harness.run check_exitcode linuxcnc_parameter_file_harness.run
check_exitcode linuxcnc_rs274_compile_probe check_exitcode linuxcnc_rs274_compile_probe
check_exitcode linuxcnc_kins_util_source_probe
check_exitcode linuxcnc_trivkins_source_probe
check_exitcode linuxcnc_interp_convert_source_probe check_exitcode linuxcnc_interp_convert_source_probe
check_exitcode linuxcnc_interp_read_source_probe check_exitcode linuxcnc_interp_read_source_probe
check_exitcode linuxcnc_interp_check_source_probe check_exitcode linuxcnc_interp_check_source_probe
@@ -202,6 +206,18 @@ grep -Fq "tp_done_after_queued_lines=1" "$TP_API_STDOUT"
grep -Fq "tp_queue_final_depth=0" "$TP_API_STDOUT" grep -Fq "tp_queue_final_depth=0" "$TP_API_STDOUT"
grep -Fq "tp_queue_final_pos_near_end=1" "$TP_API_STDOUT" grep -Fq "tp_queue_final_pos_near_end=1" "$TP_API_STDOUT"
KINEMATICS_STDOUT="$BUILD_DIR/linuxcnc_kinematics_probe.run.stdout.log"
grep -Fq "kinematics_init=0" "$KINEMATICS_STDOUT"
grep -Fq "kinematics_type=1" "$KINEMATICS_STDOUT"
grep -Fq "kinematics_switchable=0" "$KINEMATICS_STDOUT"
grep -Fq "kinematics_switch=0" "$KINEMATICS_STDOUT"
grep -Fq "kinematics_forward=0" "$KINEMATICS_STDOUT"
grep -Fq "kinematics_forward_xyz=1,2,3" "$KINEMATICS_STDOUT"
grep -Fq "kinematics_forward_abcuvw=4,5,6,7,8,9" "$KINEMATICS_STDOUT"
grep -Fq "kinematics_inverse=0" "$KINEMATICS_STDOUT"
grep -Fq "kinematics_inverse_xyz=10,20,30" "$KINEMATICS_STDOUT"
grep -Fq "kinematics_inverse_abcuvw=40,50,60,70,80,90" "$KINEMATICS_STDOUT"
check_fixture_output() { check_fixture_output() {
local fixture="$1" local fixture="$1"
local expected="$2" local expected="$2"

View File

@@ -346,6 +346,13 @@ TP_API_PROBE_SOURCES=(
"$WRAP_DIR/linuxcnc_tp_api_probe.cpp" "$WRAP_DIR/linuxcnc_tp_api_probe.cpp"
) )
KINEMATICS_PROBE_SOURCES=(
"$VENDOR_DIR/src/emc/kinematics/kins_util.c"
"$VENDOR_DIR/src/emc/kinematics/trivkins.c"
"$WRAP_DIR/linuxcnc_hal_adapter.cpp"
"$WRAP_DIR/linuxcnc_kinematics_probe.cpp"
)
TP_CORE_SOURCES=( TP_CORE_SOURCES=(
"$VENDOR_DIR/src/emc/tp/tp.c" "$VENDOR_DIR/src/emc/tp/tp.c"
"$VENDOR_DIR/src/emc/tp/tc.c" "$VENDOR_DIR/src/emc/tp/tc.c"
@@ -519,6 +526,28 @@ build_binary_target \
TP_RUNTIME_PROBE_SOURCES \ TP_RUNTIME_PROBE_SOURCES \
NO_LINK_FLAGS NO_LINK_FLAGS
build_binary_target \
linuxcnc_kinematics_probe \
"$BUILD_DIR/linuxcnc_kinematics_probe" \
TP_FLAGS \
KINEMATICS_PROBE_SOURCES \
NO_LINK_FLAGS
if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_kinematics_probe.exitcode")" == "0" ]]; then
set +e
"$BUILD_DIR/linuxcnc_kinematics_probe" \
>"$BUILD_DIR/linuxcnc_kinematics_probe.run.stdout.log" \
2>"$BUILD_DIR/linuxcnc_kinematics_probe.run.stderr.log"
KINEMATICS_RUN_RC=$?
set -e
echo "$KINEMATICS_RUN_RC" > "$BUILD_DIR/linuxcnc_kinematics_probe.run.exitcode"
else
rm -f \
"$BUILD_DIR/linuxcnc_kinematics_probe.run.exitcode" \
"$BUILD_DIR/linuxcnc_kinematics_probe.run.stdout.log" \
"$BUILD_DIR/linuxcnc_kinematics_probe.run.stderr.log"
fi
if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_tp_api_probe.exitcode")" == "0" ]]; then if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_tp_api_probe.exitcode")" == "0" ]]; then
set +e set +e
"$BUILD_DIR/linuxcnc_tp_api_probe" \ "$BUILD_DIR/linuxcnc_tp_api_probe" \
@@ -617,6 +646,18 @@ build_object_target \
"$WRAP_DIR/linuxcnc_rs274_compile_probe.cpp" \ "$WRAP_DIR/linuxcnc_rs274_compile_probe.cpp" \
COMMON_FLAGS COMMON_FLAGS
build_object_target \
linuxcnc_kins_util_source_probe \
"$BUILD_DIR/linuxcnc_kins_util_source_probe.o" \
"$VENDOR_DIR/src/emc/kinematics/kins_util.c" \
TP_FLAGS
build_object_target \
linuxcnc_trivkins_source_probe \
"$BUILD_DIR/linuxcnc_trivkins_source_probe.o" \
"$VENDOR_DIR/src/emc/kinematics/trivkins.c" \
TP_FLAGS
build_object_target \ build_object_target \
linuxcnc_interp_convert_source_probe \ linuxcnc_interp_convert_source_probe \
"$BUILD_DIR/linuxcnc_interp_convert_source_probe.o" \ "$BUILD_DIR/linuxcnc_interp_convert_source_probe.o" \

View File

@@ -10,6 +10,7 @@ src/rtapi/rtapi_string.h
src/rtapi/rtapi_gfp.h src/rtapi/rtapi_gfp.h
src/rtapi/rtapi_math.h src/rtapi/rtapi_math.h
src/rtapi/rtapi_byteorder.h src/rtapi/rtapi_byteorder.h
src/rtapi/rtapi_app.h
src/emc/nml_intf/emcpos.h src/emc/nml_intf/emcpos.h
src/emc/nml_intf/emcpose.h src/emc/nml_intf/emcpose.h
src/emc/nml_intf/emcpose.c src/emc/nml_intf/emcpose.c
@@ -29,6 +30,8 @@ src/emc/motion/mot_priv.h
src/emc/motion/axis.h src/emc/motion/axis.h
src/emc/kinematics/kinematics.h src/emc/kinematics/kinematics.h
src/emc/kinematics/cubic.h src/emc/kinematics/cubic.h
src/emc/kinematics/kins_util.c
src/emc/kinematics/trivkins.c
src/emc/tp/tp.h src/emc/tp/tp.h
src/emc/tp/tp_types.h src/emc/tp/tp_types.h
src/emc/tp/tc.h src/emc/tp/tc.h

View File

@@ -0,0 +1,366 @@
/* Utility routines for kinematics modules
** License GPL Version 2
**
** utilities for use with switchkins.c
**---------------------------------------------------------------------
** identityKinematicsSetup()
** identityKinematicsForward()
** identityKinematicsInverse()
**
** Routines for identity kinematics using mapping created by
** map_coordinates_to_jnumbers()
**
**---------------------------------------------------------------------
** map_coordinates_to_jnumbers()
**
** Map a string of coordinate letters to joint numbers sequentially.
** If allow_duplicates==1, a coordinate letter may be specified more
** than once to assign it to multiple joint numbers (the kinematics
** module must support such usage).
**
** Default mapping if coordinates==NULL is:
** X:0 Y:1 Z:2 A:3 B:4 C:5 U:6 V:7 W:8
**
** Example coordinates-to-joints mappings:
** coordinates=XYZ X:0 Y:1 Z:2
** coordinates=ZYX Z:0 Y:1 X:2
** coordinates=XYZZZZ x:0 Y:1 Z:2,3,4,5
** coordinates=XXYZ X:0,1 Y:2 Z:3
**---------------------------------------------------------------------
**
** mapped_joints_to_position()
**
** Update position based mapping created by map_coordinates_to_jnumbers()
** (used for identity-based forward kinematics)
**---------------------------------------------------------------------
**
** position_to_mapped_joints()
**
** Update joints (including joints for duplicate letters)
** based on mapping created by map_coordinates_to_jnumbers()
** (used for identity-based inverse kinematics)
**
**---------------------------------------------------------------------
*/
#include <rtapi.h>
#include <rtapi_string.h>
#include <emcmotcfg.h>
#include <emcpos.h>
#include <kinematics.h>
// principal joint numbers based on module 'coordinates' parameter
static int JX = -1;
static int JY = -1;
static int JZ = -1;
static int JA = -1;
static int JB = -1;
static int JC = -1;
static int JU = -1;
static int JV = -1;
static int JW = -1;
// bitmaps indicate joints used for each axis letter
static int X_joints_bitmap;
static int Y_joints_bitmap;
static int Z_joints_bitmap;
static int A_joints_bitmap;
static int B_joints_bitmap;
static int C_joints_bitmap;
static int U_joints_bitmap;
static int V_joints_bitmap;
static int W_joints_bitmap;
static int map_initialized = 0;
#define MAX_COORDINATES_CHARS 32
static char used_coordinates[MAX_COORDINATES_CHARS+1];
int map_coordinates_to_jnumbers(const char *coordinates,
const int max_joints,
const int allow_duplicates,
int axis_idx_for_jno[] ) //result
{
char* errtag="map_coordinates_to_jnumbers: ERROR:\n ";
int jno=0;
bool found=0;
int dups[EMCMOT_MAX_AXIS];
const char *coords = coordinates;
char coord_letter[] = {'X','Y','Z','A','B','C','U','V','W'};
int i;
if (strlen(coordinates) > MAX_COORDINATES_CHARS) {
rtapi_print_msg(RTAPI_MSG_ERR,
"%s: map_coordinates_to_jnumbers too many chars:%s\n"
,__FILE__,coordinates);
return -1;
}
// Note: may be called multiple times for different switchkins
// types but coordinates must agree
if (used_coordinates[0] == 0) {
strcpy(used_coordinates,coordinates);
} else {
if (strcasecmp(coordinates,used_coordinates)) {
rtapi_print_msg(RTAPI_MSG_ERR,
"%s: map_coordinates_to_jnumbers altered:%s %s\n"
,__FILE__,used_coordinates,coordinates);
return -1;
}
}
for (i=0; i<EMCMOT_MAX_AXIS; i++) {dups[i] = 0;}
if ( (max_joints <= 0) || (max_joints > EMCMOT_MAX_JOINTS) ) {
rtapi_print_msg(RTAPI_MSG_ERR,"%s bogus max_joints=%d\n",
errtag,max_joints);
return -1;
}
// init all axis_idx_for_jno[] (-1 means unspecified)
for(jno=0; jno<EMCMOT_MAX_JOINTS; jno++) { axis_idx_for_jno[jno] = -1; }
if (coords == NULL) { coords = "XYZABCUVW"; }
jno = 0; // begin: assign joint numbers at 0th coords position
while (*coords) {
found = 0;
switch(*coords) {
case 'x': case 'X': axis_idx_for_jno[jno]= 0;dups[0]++;found=1;break;
case 'y': case 'Y': axis_idx_for_jno[jno]= 1;dups[1]++;found=1;break;
case 'z': case 'Z': axis_idx_for_jno[jno]= 2;dups[2]++;found=1;break;
case 'a': case 'A': axis_idx_for_jno[jno]= 3;dups[3]++;found=1;break;
case 'b': case 'B': axis_idx_for_jno[jno]= 4;dups[4]++;found=1;break;
case 'c': case 'C': axis_idx_for_jno[jno]= 5;dups[5]++;found=1;break;
case 'u': case 'U': axis_idx_for_jno[jno]= 6;dups[6]++;found=1;break;
case 'v': case 'V': axis_idx_for_jno[jno]= 7;dups[7]++;found=1;break;
case 'w': case 'W': axis_idx_for_jno[jno]= 8;dups[8]++;found=1;break;
case ' ': case '\t': coords++;continue; //whitespace
}
if (found) {
coords++; // next coordinates letter
jno++; // next joint number
} else {
rtapi_print_msg(RTAPI_MSG_ERR,
"%s Invalid character '%c' in coordinates '%s'\n",
errtag,*coords,coordinates);
return -1;
}
if (jno > max_joints) {
rtapi_print_msg(RTAPI_MSG_ERR,
"%s too many coordinates <%s> for max_joints=%d\n",
errtag,coordinates,max_joints);
return -1;
}
} // while
if (!found) {
rtapi_print_msg(RTAPI_MSG_ERR,"%s missing coordinates '%s'\n",
errtag,coordinates);
return -1;
}
if (!allow_duplicates) {
int ano;
for(ano=0; ano<EMCMOT_MAX_AXIS; ano++) {
if (dups[ano] > 1) {
rtapi_print_msg(RTAPI_MSG_ERR,
"%s duplicates not allowed in coordinates=%s, letter=%c\n",
errtag,coordinates,coord_letter[ano]);
return -1;
}
}
}
for (jno=0; jno < max_joints; jno++) {
int bitnumber = 1<<jno;
/* Assign principal joint (first joint listed for a coordinate letter
** (using the coordinates module parameter) and use for forward
** kinematics.
** Assign a bitmap for duplicate joints listed and use for inverse
** kinematics.
**
** example: coordinates=xyzbcwy (duplicate y)
** JX=0 X_joints_bitmap=0x01 joints: 0
** JY=1 Y_joints_bitmap=0x42 joints: 1 and 6
** JZ=2 Z_joints_bitmap=0x04 joints: 2
** JB=3 C_joints_bitmap=0x10 joints: 3
** JC=4 C_joints_bitmap=0x10 joints: 4
** JW=5 C_joints_bitmap=0x10 joints: 5
**
** xyzabcuvw letters
** 012345678 indices
*/
if (axis_idx_for_jno[jno] == 0) {
if (JX == -1) JX=jno;
X_joints_bitmap |= bitnumber;
}
if (axis_idx_for_jno[jno] == 1) {
if (JY == -1) JY=jno;
Y_joints_bitmap |= bitnumber;
}
if (axis_idx_for_jno[jno] == 2) {
if (JZ == -1) JZ=jno;
Z_joints_bitmap |= bitnumber;
}
if (axis_idx_for_jno[jno] == 3) {
if (JA == -1) JA=jno;
A_joints_bitmap |= bitnumber;
}
if (axis_idx_for_jno[jno] == 4) {
if (JB == -1) JB=jno;
B_joints_bitmap |= bitnumber;
}
if (axis_idx_for_jno[jno] == 5) {
if (JC == -1) JC=jno;
C_joints_bitmap |= bitnumber;
}
if (axis_idx_for_jno[jno] == 6) {
if (JU == -1) JU=jno;
U_joints_bitmap |= bitnumber;
}
if (axis_idx_for_jno[jno] == 7) {
if (JV == -1) JV=jno;
V_joints_bitmap |= bitnumber;
}
if (axis_idx_for_jno[jno] == 8) {
if (JW == -1) JW=jno;
W_joints_bitmap |= bitnumber;
}
}
map_initialized = 1;
return 0;
} //map_coordinates_to_jnumbers()
int mapped_joints_to_position(const int max_joints,
const double * joints,
EmcPose * pos)
{
int jno;
if (!map_initialized) {
rtapi_print_msg(RTAPI_MSG_ERR,
"mapped_joints_to_position() before map_initialized\n");
return -1;
}
for (jno=0; jno < max_joints; jno++) {
int bit = 1<<jno;
if ( bit & X_joints_bitmap ) pos->tran.x = joints[JX];
if ( bit & Y_joints_bitmap ) pos->tran.y = joints[JY];
if ( bit & Z_joints_bitmap ) pos->tran.z = joints[JZ];
if ( bit & A_joints_bitmap ) pos->a = joints[JA];
if ( bit & B_joints_bitmap ) pos->b = joints[JB];
if ( bit & C_joints_bitmap ) pos->c = joints[JC];
if ( bit & U_joints_bitmap ) pos->u = joints[JU];
if ( bit & V_joints_bitmap ) pos->v = joints[JV];
if ( bit & W_joints_bitmap ) pos->w = joints[JW];
}
return 0;
} // mapped_joints_to_position()
int position_to_mapped_joints(const int max_joints,
const EmcPose * pos,
double* joints)
{
int jno;
if (!map_initialized) {
rtapi_print_msg(RTAPI_MSG_ERR,
"position_to_mapped_joints before map_initialized\n");
return -1;
}
for (jno=0; jno < max_joints; jno++) {
int bit = 1<<jno;
if ( bit & X_joints_bitmap ) joints[jno] = pos->tran.x;
if ( bit & Y_joints_bitmap ) joints[jno] = pos->tran.y;
if ( bit & Z_joints_bitmap ) joints[jno] = pos->tran.z;
if ( bit & A_joints_bitmap ) joints[jno] = pos->a;
if ( bit & B_joints_bitmap ) joints[jno] = pos->b;
if ( bit & C_joints_bitmap ) joints[jno] = pos->c;
if ( bit & U_joints_bitmap ) joints[jno] = pos->u;
if ( bit & V_joints_bitmap ) joints[jno] = pos->v;
if ( bit & W_joints_bitmap ) joints[jno] = pos->w;
}
return 0;
} // position_to_mapped_joints()
static int identity_kinematics_initialized = 0;
static int identity_max_joints;
int identityKinematicsSetup(const int comp_id,
const char* coordinates,
kparms* kp)
{
(void)comp_id;
int axis_idx_for_jno[EMCMOT_MAX_JOINTS];
int jno;
int show=0;
bool islathe;
identity_max_joints = strlen(coordinates);
if (map_coordinates_to_jnumbers(coordinates,
kp->max_joints,
kp->allow_duplicates,
axis_idx_for_jno)) {
return -1; //mapping failed
}
/* print message for unconventional ordering;
** a) duplicate coordinate letters
** b) letters not ordered by "XYZABCUVW" sequence
** (use kinstype=both works best for these)
*/
for (jno=0; jno<identity_max_joints; jno++) {
if (axis_idx_for_jno[jno] == -1) break; //fini
if (axis_idx_for_jno[jno] != jno) { show++; } //not default order
}
islathe = !strcasecmp(coordinates,"xz"); // no show if simple lathe
if (show && !islathe) {
rtapi_print("\nidentityKinematicsSetup: coordinates:%s\n", coordinates);
char *p="XYZABCUVW";
for (jno=0; jno<identity_max_joints; jno++) {
if (axis_idx_for_jno[jno] == -1) break; //fini
rtapi_print(" Joint %d ==> Axis %c\n",
jno,*(p+axis_idx_for_jno[jno]));
}
if (kinematicsType() != KINEMATICS_BOTH) {
rtapi_print("identityKinematicsSetup: Recommend: kinstype=both\n");
}
rtapi_print("\n");
}
identity_kinematics_initialized = 1;
return 0;
} // identityKinematicsSetup()
int identityKinematicsForward(const double *joints,
EmcPose * pos,
const KINEMATICS_FORWARD_FLAGS * fflags,
KINEMATICS_INVERSE_FLAGS * iflags)
{
(void)fflags;
(void)iflags;
if (!identity_kinematics_initialized) {
rtapi_print_msg(RTAPI_MSG_ERR,
"identityKinematicsForward: not initialized\n");
return -1;
}
// support multiple-joint-per-coordinate-letter assignments:
mapped_joints_to_position(identity_max_joints,joints,pos);
return 0;
} // identityKinematicsForward()
int identityKinematicsInverse(const EmcPose * pos,
double *joints,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
(void)iflags;
(void)fflags;
if (!identity_kinematics_initialized) {
rtapi_print_msg(RTAPI_MSG_ERR,
"identityKinematicsInverse: not initialized\n");
return -1;
}
// support multiple-joint-per-coordinate-letter assignments:
position_to_mapped_joints(identity_max_joints,pos,joints);
return 0;
} // identityKinematicsInverse()

View File

@@ -0,0 +1,87 @@
/********************************************************************
* Description: trivkins.c
* general trivkins for 3 axis Cartesian machine
*
* Derived from a work by Fred Proctor & Will Shackleford
*
* License: GPL Version 2
*
* Copyright (c) 2009 All rights reserved.
*
********************************************************************/
#include <rtapi.h>
#include <rtapi.h> /* RTAPI realtime OS API */
#include <rtapi_app.h> /* RTAPI realtime module decls */
#include <rtapi_math.h>
#include <rtapi_string.h>
#include <hal.h>
#include <emcmotcfg.h>
#include <kinematics.h>
#define SET(f) pos->f = joints[i]
int kinematicsForward(const double *joints,
EmcPose * pos,
const KINEMATICS_FORWARD_FLAGS * fflags,
KINEMATICS_INVERSE_FLAGS * iflags)
{
return identityKinematicsForward(joints, pos, fflags, iflags);
}
int kinematicsInverse(const EmcPose * pos,
double *joints,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
return identityKinematicsInverse(pos, joints, iflags, fflags);
}
static KINEMATICS_TYPE ktype = -1;
KINEMATICS_TYPE kinematicsType()
{
return ktype;
}
#define TRIVKINS_DEFAULT_COORDINATES "XYZABCUVW"
static char *coordinates = TRIVKINS_DEFAULT_COORDINATES;
RTAPI_MP_STRING(coordinates, "Existing Axes");
static char *kinstype = "1"; // use KINEMATICS_IDENTITY
RTAPI_MP_STRING(kinstype, "Kinematics Type (Identity,Both)");
KINS_NOT_SWITCHABLE
EXPORT_SYMBOL(kinematicsType);
EXPORT_SYMBOL(kinematicsForward);
EXPORT_SYMBOL(kinematicsInverse);
MODULE_LICENSE("GPL");
static int comp_id;
int rtapi_app_main(void) {
kparms ksetup;
switch (*kinstype) {
case 'b': case 'B': ktype = KINEMATICS_BOTH; break;
case 'f': case 'F': ktype = KINEMATICS_FORWARD_ONLY; break;
case 'i': case 'I': ktype = KINEMATICS_INVERSE_ONLY; break;
case '1': default: ktype = KINEMATICS_IDENTITY;
}
comp_id = hal_init("trivkins");
if(comp_id < 0) return comp_id;
// see typedef for KS KinematicsSETUP:
ksetup.max_joints = EMCMOT_MAX_JOINTS;
ksetup.allow_duplicates = 1;
if (identityKinematicsSetup(comp_id, coordinates, &ksetup)) {
return -1; //setup failed
}
hal_ready(comp_id);
return 0;
}
void rtapi_app_exit(void) { hal_exit(comp_id); }

View File

@@ -0,0 +1,36 @@
// Copyright 2003-2007, various authors
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#ifndef __LINUXCNC_RTAPI_APP_H
#define __LINUXCNC_RTAPI_APP_H
/*
for Linux kernel modules, exactly one file needs to
include <linux/module.h>. We put this in this header.
If we ever support non-Linux platforms, this file will
get full of ifdefs.
*/
#if !defined(__KERNEL__)
EXPORT_SYMBOL(rtapi_app_main);
EXPORT_SYMBOL(rtapi_app_exit);
#else
#include <linux/module.h>
#define rtapi_app_main(a) init_module(a)
#define rtapi_app_exit(a) cleanup_module(a)
#endif
#endif /* RTAPI_APP_H */