按推荐建议,继续执行

结论:已将 LinuxCNC 5axiskins 及 switchkins 相关源码纳入 vendored manifest、native probe 和文档验证链,完整 native 验证通过。
This commit is contained in:
2026-06-07 19:08:40 +08:00
parent 55f6659993
commit 1b2f95b3d1
15 changed files with 1129 additions and 10 deletions

View File

@@ -53,6 +53,7 @@ The validation fails if:
| `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_kinematics_probe` | Validates vendored LinuxCNC `trivkins.c` plus `kins_util.c` initialize and perform identity forward/inverse mapping through the standalone HAL/RTAPI boundary. |
| `linuxcnc_5axis_kinematics_probe` | Validates vendored LinuxCNC `5axiskins.c` through `switchkins.c`, including 5-axis forward/inverse round-trip behavior and switching to identity kinematics. |
## Fixture Coverage
@@ -95,5 +96,7 @@ The current fixture expectations validate standalone behavior against the
vendored LinuxCNC source path. They do not yet run a side-by-side native
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.
The kinematics probes currently cover LinuxCNC identity/trivial kinematics and
the switchable `5axiskins` XYZBCW bridge-mill model. TRT `xyzac`/`xyzbc`,
serial, delta, SCARA, and other machine-specific kinematics still need
dedicated baselines.

View File

@@ -29,7 +29,7 @@ semantic rewrites:
| 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. |
| 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. |
| Kinematics component lifecycle | `trivkins.c` and `5axiskins.c` are initialized through LinuxCNC module entry points while HAL component init/ready/exit, HAL pin allocation, and RTAPI module metadata are handled by standalone shims. |
| Browser storage | OPFS remains outside the native core and is not yet connected. |
## Enforced Non-Drift Rules
@@ -47,10 +47,11 @@ semantic rewrites:
- No browser/WASM parity tests yet.
- No JS SDK validation yet.
- No OPFS persistence validation yet.
- Identity/trivial kinematics now have native source-probe coverage; non-trivial
and 5-axis kinematics implementation files are not yet extracted.
- Full machine baselines beyond the identity/trivial kinematics probe are not
established.
- Identity/trivial kinematics and LinuxCNC `5axiskins` now have native
source-probe coverage; TRT `xyzac`/`xyzbc`, serial, delta, SCARA, and other
machine-specific kinematics are not yet extracted.
- Full machine baselines beyond the current identity/trivial and `5axiskins`
probes are not established.
- Fixture expectations are currently checked against the standalone vendored
source path, not by running a native LinuxCNC binary for every fixture.

View File

@@ -60,5 +60,6 @@ Negative fixture coverage includes:
- missing tool length offset
Machine baseline is still limited to standalone interpreter, trajectory
planner, and LinuxCNC identity/trivial kinematics probes. Non-trivial
kinematics and 5-axis machine baselines remain future work.
planner, LinuxCNC identity/trivial kinematics, and the LinuxCNC `5axiskins`
XYZBCW bridge-mill probe. Additional non-trivial kinematics and fuller machine
baselines remain future work.

View File

@@ -36,6 +36,7 @@ Current validation is intentionally mechanical:
| 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` |
| 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` |
| 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 |
| 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 |
@@ -59,7 +60,9 @@ Current validation is intentionally mechanical:
## Known Gaps
- Full non-trivial and 5-axis kinematics implementation files are not yet extracted.
- Additional non-trivial kinematics implementation files, including TRT
`xyzac`/`xyzbc`, serial, delta, SCARA, and other machine-specific modules,
are not yet extracted.
- Browser/WASM C ABI and JS SDK layers are not yet built for the full
interpreter/planner core.
- OPFS persistence is not yet connected to INI, tool table, parameter file, or

View File

@@ -0,0 +1,108 @@
#include <cmath>
#include <iostream>
#include "emc/kinematics/kinematics.h"
#include "emc/motion/emcmotcfg.h"
int rtapi_app_main(void);
void rtapi_app_exit(void);
namespace {
int near(double actual, double expected)
{
return std::fabs(actual - expected) < 1e-9;
}
int near_pose(const EmcPose &actual, const EmcPose &expected)
{
return near(actual.tran.x, expected.tran.x) &&
near(actual.tran.y, expected.tran.y) &&
near(actual.tran.z, expected.tran.z) &&
near(actual.b, expected.b) &&
near(actual.c, expected.c) &&
near(actual.w, expected.w);
}
int near_joints(const double *actual, const double *expected)
{
for (int index = 0; index < 6; ++index) {
if (!near(actual[index], expected[index])) {
return 0;
}
}
return 1;
}
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 << "_bcw="
<< pose.b << ","
<< pose.c << ","
<< pose.w << "\n";
}
void print_joints(const char *prefix, const double *joints)
{
std::cout << prefix << "_xyzbcw="
<< joints[0] << ","
<< joints[1] << ","
<< joints[2] << ","
<< joints[3] << ","
<< joints[4] << ","
<< joints[5] << "\n";
}
} // namespace
int main()
{
const int init_rc = rtapi_app_main();
std::cout << "fiveaxis_init=" << init_rc << "\n";
std::cout << "fiveaxis_type=" << kinematicsType() << "\n";
std::cout << "fiveaxis_switchable=" << kinematicsSwitchable() << "\n";
double joints[EMCMOT_MAX_JOINTS]{};
joints[0] = 10.0;
joints[1] = 20.0;
joints[2] = 30.0;
joints[3] = 45.0;
joints[4] = 30.0;
joints[5] = 5.0;
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags = 0;
EmcPose forward_pose{};
const int forward_rc = kinematicsForward(joints, &forward_pose, &fflags, &iflags);
std::cout << "fiveaxis_forward=" << forward_rc << "\n";
print_pose("fiveaxis_forward", forward_pose);
double inverse_joints[EMCMOT_MAX_JOINTS]{};
const int inverse_rc = kinematicsInverse(&forward_pose, inverse_joints, &iflags, &fflags);
std::cout << "fiveaxis_inverse=" << inverse_rc << "\n";
print_joints("fiveaxis_inverse", inverse_joints);
std::cout << "fiveaxis_roundtrip_joints=" << near_joints(inverse_joints, joints) << "\n";
const int switch_rc = kinematicsSwitch(1);
std::cout << "fiveaxis_switch_identity=" << switch_rc << "\n";
EmcPose identity_pose{};
const int identity_forward_rc = kinematicsForward(joints, &identity_pose, &fflags, &iflags);
std::cout << "fiveaxis_identity_forward=" << identity_forward_rc << "\n";
print_pose("fiveaxis_identity", identity_pose);
EmcPose expected_identity{};
expected_identity.tran.x = joints[0];
expected_identity.tran.y = joints[1];
expected_identity.tran.z = joints[2];
expected_identity.b = joints[3];
expected_identity.c = joints[4];
expected_identity.w = joints[5];
std::cout << "fiveaxis_identity_near=" << near_pose(identity_pose, expected_identity) << "\n";
rtapi_app_exit();
return 0;
}

View File

@@ -1,7 +1,11 @@
#include "linuxcnc_hal_adapter.hh"
#include <cstdarg>
#include <cstdio>
#include <new>
#include <string>
#include <unordered_map>
#include <vector>
namespace {
@@ -29,6 +33,12 @@ std::unordered_map<std::string, HalEntry> &params()
return values;
}
std::vector<void *> &hal_allocations()
{
static std::vector<void *> values;
return values;
}
std::unordered_map<std::string, HalEntry> &values_for(standalone::HalValueKind kind)
{
switch (kind) {
@@ -96,6 +106,150 @@ int hal_exit(int)
return 0;
}
void *hal_malloc(long int size)
{
if (size <= 0) {
return nullptr;
}
void *ptr = ::operator new(static_cast<std::size_t>(size), std::nothrow);
if (ptr) {
hal_allocations().push_back(ptr);
}
return ptr;
}
int hal_pin_bit_new(const char *, hal_pin_dir_t, hal_bit_t **data_ptr_addr, int)
{
if (!data_ptr_addr) {
return -1;
}
*data_ptr_addr = new hal_bit_t{};
return 0;
}
int hal_pin_float_new(const char *, hal_pin_dir_t, hal_float_t **data_ptr_addr, int)
{
if (!data_ptr_addr) {
return -1;
}
*data_ptr_addr = new hal_float_t{};
return 0;
}
int hal_pin_u32_new(const char *, hal_pin_dir_t, hal_u32_t **data_ptr_addr, int)
{
if (!data_ptr_addr) {
return -1;
}
*data_ptr_addr = new hal_u32_t{};
return 0;
}
int hal_pin_s32_new(const char *, hal_pin_dir_t, hal_s32_t **data_ptr_addr, int)
{
if (!data_ptr_addr) {
return -1;
}
*data_ptr_addr = new hal_s32_t{};
return 0;
}
int hal_pin_u64_new(const char *, hal_pin_dir_t, hal_u64_t **data_ptr_addr, int)
{
if (!data_ptr_addr) {
return -1;
}
*data_ptr_addr = new hal_u64_t{};
return 0;
}
int hal_pin_s64_new(const char *, hal_pin_dir_t, hal_s64_t **data_ptr_addr, int)
{
if (!data_ptr_addr) {
return -1;
}
*data_ptr_addr = new hal_s64_t{};
return 0;
}
template <typename T, int (*Create)(const char *, hal_pin_dir_t, T **, int)>
int hal_pin_newf_impl(hal_pin_dir_t dir, T **data_ptr_addr, int comp_id, const char *fmt,
va_list ap)
{
if (!fmt) {
return -1;
}
char name[HAL_NAME_LEN * 2]{};
vsnprintf(name, sizeof(name), fmt, ap);
return Create(name, dir, data_ptr_addr, comp_id);
}
int hal_pin_bit_newf(hal_pin_dir_t dir, hal_bit_t **data_ptr_addr, int comp_id,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
const int rc = hal_pin_newf_impl<hal_bit_t, hal_pin_bit_new>(
dir, data_ptr_addr, comp_id, fmt, ap);
va_end(ap);
return rc;
}
int hal_pin_float_newf(hal_pin_dir_t dir, hal_float_t **data_ptr_addr, int comp_id,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
const int rc = hal_pin_newf_impl<hal_float_t, hal_pin_float_new>(
dir, data_ptr_addr, comp_id, fmt, ap);
va_end(ap);
return rc;
}
int hal_pin_u32_newf(hal_pin_dir_t dir, hal_u32_t **data_ptr_addr, int comp_id,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
const int rc = hal_pin_newf_impl<hal_u32_t, hal_pin_u32_new>(
dir, data_ptr_addr, comp_id, fmt, ap);
va_end(ap);
return rc;
}
int hal_pin_s32_newf(hal_pin_dir_t dir, hal_s32_t **data_ptr_addr, int comp_id,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
const int rc = hal_pin_newf_impl<hal_s32_t, hal_pin_s32_new>(
dir, data_ptr_addr, comp_id, fmt, ap);
va_end(ap);
return rc;
}
int hal_pin_u64_newf(hal_pin_dir_t dir, hal_u64_t **data_ptr_addr, int comp_id,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
const int rc = hal_pin_newf_impl<hal_u64_t, hal_pin_u64_new>(
dir, data_ptr_addr, comp_id, fmt, ap);
va_end(ap);
return rc;
}
int hal_pin_s64_newf(hal_pin_dir_t dir, hal_s64_t **data_ptr_addr, int comp_id,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
const int rc = hal_pin_newf_impl<hal_s64_t, hal_pin_s64_new>(
dir, data_ptr_addr, comp_id, fmt, ap);
va_end(ap);
return rc;
}
int hal_get_pin_value_by_name(const char *name, hal_type_t *type, hal_data_u **ptr,
bool *connected)
{

View File

@@ -2,6 +2,8 @@
#include <stdbool.h>
#include "rtapi.h"
#define HAL_NAME_LEN 64
typedef enum {
@@ -14,6 +16,13 @@ typedef enum {
HAL_U64
} hal_type_t;
typedef enum {
HAL_DIR_UNSPECIFIED = -1,
HAL_IN = 16,
HAL_OUT = 32,
HAL_IO = (HAL_IN | HAL_OUT),
} hal_pin_dir_t;
typedef union {
bool b;
double f;
@@ -33,6 +42,19 @@ typedef unsigned long long hal_u64_t;
int hal_init(const char *);
int hal_ready(int);
int hal_exit(int);
void *hal_malloc(long int);
int hal_pin_bit_new(const char *, hal_pin_dir_t, hal_bit_t **, int);
int hal_pin_float_new(const char *, hal_pin_dir_t, hal_float_t **, int);
int hal_pin_u32_new(const char *, hal_pin_dir_t, hal_u32_t **, int);
int hal_pin_s32_new(const char *, hal_pin_dir_t, hal_s32_t **, int);
int hal_pin_u64_new(const char *, hal_pin_dir_t, hal_u64_t **, int);
int hal_pin_s64_new(const char *, hal_pin_dir_t, hal_s64_t **, int);
int hal_pin_bit_newf(hal_pin_dir_t, hal_bit_t **, int, const char *, ...);
int hal_pin_float_newf(hal_pin_dir_t, hal_float_t **, int, const char *, ...);
int hal_pin_u32_newf(hal_pin_dir_t, hal_u32_t **, int, const char *, ...);
int hal_pin_s32_newf(hal_pin_dir_t, hal_s32_t **, int, const char *, ...);
int hal_pin_u64_newf(hal_pin_dir_t, hal_u64_t **, int, const char *, ...);
int hal_pin_s64_newf(hal_pin_dir_t, hal_s64_t **, int, const char *, ...);
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_param_value_by_name(const char *, hal_type_t *, hal_data_u **);

View File

@@ -81,6 +81,8 @@ check_exitcode linuxcnc_tp_api_probe
check_exitcode linuxcnc_tp_api_probe.run
check_exitcode linuxcnc_kinematics_probe
check_exitcode linuxcnc_kinematics_probe.run
check_exitcode linuxcnc_5axis_kinematics_probe
check_exitcode linuxcnc_5axis_kinematics_probe.run
for name in \
linuxcnc_tp_tp_source_probe \
linuxcnc_tp_tc_source_probe \
@@ -123,6 +125,9 @@ check_exitcode linuxcnc_parameter_file_harness.run
check_exitcode linuxcnc_rs274_compile_probe
check_exitcode linuxcnc_kins_util_source_probe
check_exitcode linuxcnc_trivkins_source_probe
check_exitcode linuxcnc_switchkins_source_probe
check_exitcode linuxcnc_userkfuncs_source_probe
check_exitcode linuxcnc_5axiskins_source_probe
check_exitcode linuxcnc_interp_convert_source_probe
check_exitcode linuxcnc_interp_read_source_probe
check_exitcode linuxcnc_interp_check_source_probe
@@ -218,6 +223,17 @@ 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"
FIVEAXIS_KINEMATICS_STDOUT="$BUILD_DIR/linuxcnc_5axis_kinematics_probe.run.stdout.log"
grep -Fq "fiveaxis_init=0" "$FIVEAXIS_KINEMATICS_STDOUT"
grep -Fq "fiveaxis_type=4" "$FIVEAXIS_KINEMATICS_STDOUT"
grep -Fq "fiveaxis_switchable=1" "$FIVEAXIS_KINEMATICS_STDOUT"
grep -Fq "fiveaxis_forward=0" "$FIVEAXIS_KINEMATICS_STDOUT"
grep -Fq "fiveaxis_inverse=0" "$FIVEAXIS_KINEMATICS_STDOUT"
grep -Fq "fiveaxis_roundtrip_joints=1" "$FIVEAXIS_KINEMATICS_STDOUT"
grep -Fq "fiveaxis_switch_identity=0" "$FIVEAXIS_KINEMATICS_STDOUT"
grep -Fq "fiveaxis_identity_forward=0" "$FIVEAXIS_KINEMATICS_STDOUT"
grep -Fq "fiveaxis_identity_near=1" "$FIVEAXIS_KINEMATICS_STDOUT"
check_fixture_output() {
local fixture="$1"
local expected="$2"

View File

@@ -353,6 +353,15 @@ KINEMATICS_PROBE_SOURCES=(
"$WRAP_DIR/linuxcnc_kinematics_probe.cpp"
)
FIVEAXIS_KINEMATICS_PROBE_SOURCES=(
"$VENDOR_DIR/src/emc/kinematics/kins_util.c"
"$VENDOR_DIR/src/emc/kinematics/switchkins.c"
"$VENDOR_DIR/src/emc/kinematics/userkfuncs.c"
"$VENDOR_DIR/src/emc/kinematics/5axiskins.c"
"$WRAP_DIR/linuxcnc_hal_adapter.cpp"
"$WRAP_DIR/linuxcnc_5axis_kinematics_probe.cpp"
)
TP_CORE_SOURCES=(
"$VENDOR_DIR/src/emc/tp/tp.c"
"$VENDOR_DIR/src/emc/tp/tc.c"
@@ -533,6 +542,13 @@ build_binary_target \
KINEMATICS_PROBE_SOURCES \
NO_LINK_FLAGS
build_binary_target \
linuxcnc_5axis_kinematics_probe \
"$BUILD_DIR/linuxcnc_5axis_kinematics_probe" \
TP_FLAGS \
FIVEAXIS_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" \
@@ -548,6 +564,21 @@ else
"$BUILD_DIR/linuxcnc_kinematics_probe.run.stderr.log"
fi
if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_5axis_kinematics_probe.exitcode")" == "0" ]]; then
set +e
"$BUILD_DIR/linuxcnc_5axis_kinematics_probe" \
>"$BUILD_DIR/linuxcnc_5axis_kinematics_probe.run.stdout.log" \
2>"$BUILD_DIR/linuxcnc_5axis_kinematics_probe.run.stderr.log"
FIVEAXIS_KINEMATICS_RUN_RC=$?
set -e
echo "$FIVEAXIS_KINEMATICS_RUN_RC" > "$BUILD_DIR/linuxcnc_5axis_kinematics_probe.run.exitcode"
else
rm -f \
"$BUILD_DIR/linuxcnc_5axis_kinematics_probe.run.exitcode" \
"$BUILD_DIR/linuxcnc_5axis_kinematics_probe.run.stdout.log" \
"$BUILD_DIR/linuxcnc_5axis_kinematics_probe.run.stderr.log"
fi
if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_tp_api_probe.exitcode")" == "0" ]]; then
set +e
"$BUILD_DIR/linuxcnc_tp_api_probe" \
@@ -658,6 +689,24 @@ build_object_target \
"$VENDOR_DIR/src/emc/kinematics/trivkins.c" \
TP_FLAGS
build_object_target \
linuxcnc_switchkins_source_probe \
"$BUILD_DIR/linuxcnc_switchkins_source_probe.o" \
"$VENDOR_DIR/src/emc/kinematics/switchkins.c" \
TP_FLAGS
build_object_target \
linuxcnc_userkfuncs_source_probe \
"$BUILD_DIR/linuxcnc_userkfuncs_source_probe.o" \
"$VENDOR_DIR/src/emc/kinematics/userkfuncs.c" \
TP_FLAGS
build_object_target \
linuxcnc_5axiskins_source_probe \
"$BUILD_DIR/linuxcnc_5axiskins_source_probe.o" \
"$VENDOR_DIR/src/emc/kinematics/5axiskins.c" \
TP_FLAGS
build_object_target \
linuxcnc_interp_convert_source_probe \
"$BUILD_DIR/linuxcnc_interp_convert_source_probe.o" \

View File

@@ -11,6 +11,7 @@ src/rtapi/rtapi_gfp.h
src/rtapi/rtapi_math.h
src/rtapi/rtapi_byteorder.h
src/rtapi/rtapi_app.h
src/rtapi/rtapi_ctype.h
src/emc/nml_intf/emcpos.h
src/emc/nml_intf/emcpose.h
src/emc/nml_intf/emcpose.c
@@ -32,6 +33,10 @@ src/emc/kinematics/kinematics.h
src/emc/kinematics/cubic.h
src/emc/kinematics/kins_util.c
src/emc/kinematics/trivkins.c
src/emc/kinematics/switchkins.h
src/emc/kinematics/switchkins.c
src/emc/kinematics/userkfuncs.c
src/emc/kinematics/5axiskins.c
src/emc/tp/tp.h
src/emc/tp/tp_types.h
src/emc/tp/tc.h

View File

@@ -0,0 +1,272 @@
/********************************************************************
* Description: 5axiskins.c
* kinematics for XYZBC 5 axis bridge mill
*
* Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2007 Chris Radek
*
* Notes:
* 1) pivot_length hal pin must agree with mechanical
* design (including vismach simulation) and augmented
* with current tool z offset
* (typ: mechanical_pivot_length + motion.tooloffset.z)
* 2) C axis: spherical coordinates aziumthal angle (t or theta)
* projection of radius to xy plane
* 3) B axis: spherical coordinates polar angle (p or phi)
* wrt z axis
* 4) W axis: tool motion. Negative values increase tool radial
* motion example: drilling into body at b,c angles
* 5) W axis motion is incorporated into the motion of the
* joints used for X,Y,Z positioning and no motor or
* hal pin connections are required for the joint specified
* as JW. However, a joint must be configured for W to
* support display of the W axis letter value for
* complicated reasons. (motion/control.c computes joint
* positions only for the number of configured kinematic
* joints (NO_OF_KINS_JOINTS) and the joint positions
* are needed to display axis letters via inverse
* kinematics.
* 6) If no coordinates module parameter is supplied, kins
* will use the required coordinates XYZBCW mapped
* to joints 0..5 in sequence.
* 7) Multiple joints may be assigned to an axis letter
* with the module coordinates parameter
* 8) If a coordinates module parameter is supplied,
* the kins will map coordinate letters in sequence
* to joint numbers beginning with joint 0.
* 9) Coordinates XYZBCW are required, AUV may be used
* if specified with the coordinates parameter and will
* be mapped one-to-one with the assigned joint.
* 10) The direction of the tilt axis is the opposite of the
* conventional axis direction. See
* https://linuxcnc.org/docs/html/gcode/machining-center.html
********************************************************************/
// non-required coordinates (A,U,V) can be set by using
// the module coordinates parameter
#define REQUIRED_COORDINATES "XYZBCW"
#define DEFAULT_PIVOT_LENGTH 250
#include <rtapi.h>
#include <rtapi_math.h>
#include <rtapi_string.h>
#include <rtapi_ctype.h>
#include <hal.h>
#include <emcmotcfg.h>
#include <kinematics.h>
#include "switchkins.h"
struct haldata {
hal_float_t *pivot_length;
} *haldata;
static int fiveaxis_max_joints;
static PmCartesian s2r(double r, double t, double p) {
// s2r: spherical coordinates to cartesian coordinates
// r = length of vector
// p=phi = angle of vector wrt z axis
// t=theta = angle of vector projected onto xy plane
// (projection length in xy plane is r*sin(p)
PmCartesian c;
t = TO_RAD*t; p = TO_RAD*p; // degrees to radians
c.x = r * sin(p) * cos(t);
c.y = r * sin(p) * sin(t);
c.z = r * cos(p);
return c;
} //s2r()
// assignments of principal joints to axis letters:
// (-1 means not defined (yet))
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;
static int fiveaxis_KinematicsForward(const double *joints,
EmcPose * pos,
const KINEMATICS_FORWARD_FLAGS * fflags,
KINEMATICS_INVERSE_FLAGS * iflags)
{
(void)fflags;
(void)iflags;
PmCartesian r = s2r(*(haldata->pivot_length) + joints[JW],
joints[JC],
180.0 - joints[JB]);
// Note: 'principal' joints are used
pos->tran.x = joints[JX] + r.x;
pos->tran.y = joints[JY] + r.y;
pos->tran.z = joints[JZ] + *(haldata->pivot_length) + r.z;
pos->b = joints[JB];
pos->c = joints[JC];
pos->w = joints[JW];
// optional letters (specify with coordinates module parameter)
pos->a = (JA != -1)? joints[JA] : 0;
pos->u = (JU != -1)? joints[JU] : 0;
pos->v = (JV != -1)? joints[JV] : 0;
return 0;
} //fiveaxis_KinematicsForward()
static int fiveaxis_KinematicsInverse(const EmcPose * pos,
double *joints,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
(void)iflags;
(void)fflags;
PmCartesian r = s2r(*(haldata->pivot_length) + pos->w,
pos->c,
180.0 - pos->b);
EmcPose P; // computed position
P.tran.x = pos->tran.x - r.x;
P.tran.y = pos->tran.y - r.y;
P.tran.z = pos->tran.z - *(haldata->pivot_length) - r.z;
P.b = pos->b;
P.c = pos->c;
P.w = pos->w;
// optional letters (specify with coordinates module parameter)
P.a = (JA != -1)? pos->a : 0;
P.u = (JU != -1)? pos->u : 0;
P.v = (JV != -1)? pos->v : 0;
// update joints with support for
// multiple-joints per-coordinate letter:
// based on computed position
position_to_mapped_joints(fiveaxis_max_joints,
&P,
joints);
return 0;
} // fiveaxis_kinematicsInverse()
int fiveaxis_KinematicsSetup(const int comp_id,
const char* coordinates,
kparms* kp)
{
int result=0;
int i,jno;
int axis_idx_for_jno[EMCMOT_MAX_JOINTS];
int minjoints = strlen(kp->required_coordinates);
fiveaxis_max_joints = strlen(coordinates); // allow for dup coords
if (fiveaxis_max_joints > kp->max_joints) {
rtapi_print_msg(RTAPI_MSG_ERR,
"ERROR %s: coordinates=%s requires %d joints, max joints=%d\n",
kp->kinsname,
coordinates,
fiveaxis_max_joints,
kp->max_joints);
goto error;
}
if (map_coordinates_to_jnumbers(coordinates,
kp->max_joints,
kp->allow_duplicates,
axis_idx_for_jno)) {
goto error;
}
// require all chars in reqd_coordinates (order doesn't matter)
for (i=0; i < minjoints; i++) {
char reqd_char;
reqd_char = *(kp->required_coordinates + i);
if ( !strchr(coordinates,toupper(reqd_char))
&& !strchr(coordinates,tolower(reqd_char)) ) {
rtapi_print_msg(RTAPI_MSG_ERR,
"ERROR %s:\nrequired coordinates:%s\n"
"specified coordinates:%s\n",
kp->kinsname, kp->required_coordinates, coordinates);
goto error;
}
}
// assign principal joint numbers (first found in coordinates map)
// duplicates are handled by position_to_mapped_joints()
for (jno=0; jno<EMCMOT_MAX_JOINTS; jno++) {
if (axis_idx_for_jno[jno] == 0) {if (JX == -1) JX=jno;}
if (axis_idx_for_jno[jno] == 1) {if (JY == -1) JY=jno;}
if (axis_idx_for_jno[jno] == 2) {if (JZ == -1) JZ=jno;}
if (axis_idx_for_jno[jno] == 3) {if (JA == -1) JA=jno;}
if (axis_idx_for_jno[jno] == 4) {if (JB == -1) JB=jno;}
if (axis_idx_for_jno[jno] == 5) {if (JC == -1) JC=jno;}
if (axis_idx_for_jno[jno] == 6) {if (JU == -1) JU=jno;}
if (axis_idx_for_jno[jno] == 7) {if (JV == -1) JV=jno;}
if (axis_idx_for_jno[jno] == 8) {if (JW == -1) JW=jno;}
}
haldata = hal_malloc(sizeof(struct haldata));
result = hal_pin_float_newf(HAL_IN,&(haldata->pivot_length),comp_id,
"%s.pivot-length",kp->halprefix);
if(result < 0) goto error;
*haldata->pivot_length = DEFAULT_PIVOT_LENGTH;
rtapi_print("Kinematics Module %s\n",__FILE__);
rtapi_print(" module name = %s\n"
" coordinates = %s Requires: [KINS]JOINTS>=%d\n"
" sparm = %s\n",
kp->kinsname,
coordinates,fiveaxis_max_joints,
kp->sparm?kp->sparm:"NOTSPECIFIED");
rtapi_print(" default pivot-length = %.3f\n",*haldata->pivot_length);
return 0;
error:
return -1;
} // fiveaxis_KinematicsSetup()
int switchkinsSetup(kparms* kp,
KS* kset0, KS* kset1, KS* kset2,
KF* kfwd0, KF* kfwd1, KF* kfwd2,
KI* kinv0, KI* kinv1, KI* kinv2
)
{
kp->kinsname = "5axiskins"; // !!! must agree with filename
kp->halprefix = "5axiskins"; // hal pin names
kp->required_coordinates = REQUIRED_COORDINATES;
kp->allow_duplicates = 1;
kp->max_joints = EMCMOT_MAX_JOINTS;
if (kp->sparm && strstr(kp->sparm,"identityfirst")) {
rtapi_print("\n!!! switchkins-type 0 is IDENTITY\n");
*kset0 = identityKinematicsSetup;
*kfwd0 = identityKinematicsForward;
*kinv0 = identityKinematicsInverse;
*kset1 = fiveaxis_KinematicsSetup;
*kfwd1 = fiveaxis_KinematicsForward;
*kinv1 = fiveaxis_KinematicsInverse;
} else {
rtapi_print("\n!!! switchkins-type 0 is %s\n",kp->kinsname);
*kset0 = fiveaxis_KinematicsSetup;
*kfwd0 = fiveaxis_KinematicsForward;
*kinv0 = fiveaxis_KinematicsInverse;
*kset1 = identityKinematicsSetup;
*kfwd1 = identityKinematicsForward;
*kinv1 = identityKinematicsInverse;
}
*kset2 = userkKinematicsSetup;
*kfwd2 = userkKinematicsForward;
*kinv2 = userkKinematicsInverse;
return 0;
} // switchkinsSetup()

View File

@@ -0,0 +1,342 @@
/*
Copyright 2019 Dewey Garrett <dgarrett@panix.com>
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.
*/
/* switchkins.c provide functions for switchable kins modules:
* rtapi_app()
* rtapi_exit()
* kinematicsType()
* kinematicsForward()
* kinematicsInverse()
* kinematicsSwitch()
* kinematicsSwitchable()
* Using modules must supply function: switchkinsSetup()
*/
#include <rtapi.h>
#include <rtapi_app.h>
#include <hal.h>
#include <emcmotcfg.h>
#include <kinematics.h>
#include "switchkins.h"
//*********************************************************************
// kinematic functions (default=0 for err detection):
static kparms kp; // kinematics parms (common all types)
static KF kfwd0 = 0; // 0==switchkins_type kinematics forward
static KF kfwd1 = 0; // 1
static KF kfwd2 = 0; // 2
static KI kinv0 = 0; // 0==switchkins_type kinematics inverse
static KI kinv1 = 0; // 1
static KI kinv2 = 0; // 2
static hal_u32_t switchkins_type;
static struct swdata {
hal_bit_t *kinstype_is_0;
hal_bit_t *kinstype_is_1;
hal_bit_t *kinstype_is_2;
hal_float_t *gui_x;
hal_float_t *gui_y;
hal_float_t *gui_z;
hal_float_t *gui_a;
hal_float_t *gui_b;
hal_float_t *gui_c;
} *swdata;
// Note: parallel kinematics (like genhexkins) often
// use iterative method for Forward algorithm
// and require an initial EmcPose.
// If fwd_iterates_mask is set
// then save/use the lastpose
static int fwd_iterates[SWITCHKINS_MAX_TYPES] = {0};
static bool use_lastpose[SWITCHKINS_MAX_TYPES] = {0};
static EmcPose lastpose[SWITCHKINS_MAX_TYPES];
static void save_lastpose(int ktype, EmcPose* pos)
{
lastpose[ktype].tran.x = pos->tran.x;
lastpose[ktype].tran.y = pos->tran.y;
lastpose[ktype].tran.z = pos->tran.z;
lastpose[ktype].a = pos->a;
lastpose[ktype].b = pos->b;
lastpose[ktype].c = pos->c;
lastpose[ktype].u = pos->u;
lastpose[ktype].v = pos->v;
lastpose[ktype].w = pos->w;
} // save_lastpose()
static void get_lastpose(int ktype, EmcPose* pos)
{
pos->tran.x = lastpose[ktype].tran.x;
pos->tran.y = lastpose[ktype].tran.y;
pos->tran.z = lastpose[ktype].tran.z;
pos->a = lastpose[ktype].a;
pos->b = lastpose[ktype].b;
pos->c = lastpose[ktype].c;
pos->u = lastpose[ktype].u;
pos->v = lastpose[ktype].v;
pos->w = lastpose[ktype].w;
} // get_lastpose()
static int gui_forward_kins(const double *joints)
{
// the hexapod vismach gui uses these hal pins to
// display platform position/orientation in both
// genhexkins and identity kinematic types
// (similar needs for many parallel kinemtic machines)
int res;
KINEMATICS_FORWARD_FLAGS fflags = 0;
KINEMATICS_INVERSE_FLAGS iflags;
switch (kp.gui_kinstype) {
case 0: res = kfwd0(joints, &lastpose[0], &fflags, &iflags);break;
case 1: res = kfwd1(joints, &lastpose[1], &fflags, &iflags);break;
case 2: res = kfwd2(joints, &lastpose[2], &fflags, &iflags);break;
default: rtapi_print_msg(RTAPI_MSG_ERR,
"gui_forward_kins BAD gui_kinstype <%d>\n",
kp.gui_kinstype);
return -1;
}
*swdata->gui_x = lastpose[kp.gui_kinstype].tran.x;
*swdata->gui_y = lastpose[kp.gui_kinstype].tran.y;
*swdata->gui_z = lastpose[kp.gui_kinstype].tran.z;
*swdata->gui_a = lastpose[kp.gui_kinstype].a;
*swdata->gui_b = lastpose[kp.gui_kinstype].b;
*swdata->gui_c = lastpose[kp.gui_kinstype].c;
return res;
} // gui_forward_kins
//*********************************************************************
int kinematicsSwitchable() {return 1;}
int kinematicsSwitch(int new_switchkins_type)
{
int k;
for (k=0; k< SWITCHKINS_MAX_TYPES; k++) { use_lastpose[k] = 0;}
switchkins_type = new_switchkins_type;
switch (switchkins_type) {
case 0: rtapi_print_msg(RTAPI_MSG_INFO,
"kinematicsSwitch:TYPE0\n");
*swdata->kinstype_is_0 = 1;
*swdata->kinstype_is_1 = 0;
*swdata->kinstype_is_2 = 0;
break;
case 1: rtapi_print_msg(RTAPI_MSG_INFO,
"kinematicsSwitch:TYPE1\n");
*swdata->kinstype_is_0 = 0;
*swdata->kinstype_is_1 = 1;
*swdata->kinstype_is_2 = 0;
break;
case 2: rtapi_print_msg(RTAPI_MSG_INFO,
"kinematicsSwitch:TYPE2\n");
*swdata->kinstype_is_0 = 0;
*swdata->kinstype_is_1 = 0;
*swdata->kinstype_is_2 = 1;
break;
default: rtapi_print_msg(RTAPI_MSG_ERR,
"kinematicsSwitch:BAD VALUE <%d>\n",
switchkins_type);
*swdata->kinstype_is_1 = 0;
*swdata->kinstype_is_0 = 0;
*swdata->kinstype_is_2 = 0;
return -1; // FAIL
}
if (fwd_iterates[switchkins_type]) {
use_lastpose[switchkins_type] = 1; // restarting a kins types
}
return 0; // 0==> no error
} // kinematicsSwitch()
int kinematicsForward(const double *joint,
EmcPose * pos,
const KINEMATICS_FORWARD_FLAGS * fflags,
KINEMATICS_INVERSE_FLAGS * iflags)
{
int r;
if (fwd_iterates[switchkins_type] && use_lastpose[switchkins_type]) {
// initialize iterative forward kins (ok for identity too)
get_lastpose(switchkins_type,pos);
use_lastpose[switchkins_type] = 0;
}
switch (switchkins_type) {
case 0: r = kfwd0(joint, pos, fflags, iflags); break;
case 1: r = kfwd1(joint, pos, fflags, iflags); break;
case 2: r = kfwd2(joint, pos, fflags, iflags); break;
default: rtapi_print_msg(RTAPI_MSG_ERR,
"switchkins: Forward BAD switchkins_type </%d>\n",
switchkins_type);
return -1;
}
if (fwd_iterates[switchkins_type]) {save_lastpose(switchkins_type,pos);}
if (r) return r;
// gui.* pins created only if gui_kinstype>=0
// consider alternate implementations for gui_forward_kins():
// a) always call and use -1 to select default 0 type
if (kp.gui_kinstype >=0) {
// create gui pins for a vismach gui using the
// kins type specified by kp.gui_kinstype;
// currently the skgui pins are only needed for
// the hexagui vismach program (as it needs
// world coords for switchkin-types
r = gui_forward_kins(joint);
}
return r;
} // kinematicsForward()
int kinematicsInverse(const EmcPose * pos,
double *joint,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
int r;
switch (switchkins_type) {
case 0: r = kinv0(pos, joint, iflags, fflags); break;
case 1: r = kinv1(pos, joint, iflags, fflags); break;
case 2: r = kinv2(pos, joint, iflags, fflags); break;
default: rtapi_print_msg(RTAPI_MSG_ERR,
"switchkins: Inverse BAD switchkins_type </%d>\n",
switchkins_type);
return -1;
}
return r;
} // kinematicsInverse()
KINEMATICS_TYPE kinematicsType()
{
return KINEMATICS_BOTH;
}
//*********************************************************************
static char *coordinates;
RTAPI_MP_STRING(coordinates, "Axes-to-joints-ordering");
static char *sparm;
RTAPI_MP_STRING(sparm, "switchkins module-specific parameter");
EXPORT_SYMBOL(kinematicsSwitchable);
EXPORT_SYMBOL(kinematicsSwitch);
EXPORT_SYMBOL(kinematicsType);
EXPORT_SYMBOL(kinematicsForward);
EXPORT_SYMBOL(kinematicsInverse);
MODULE_LICENSE("GPL");
static int comp_id;
//*********************************************************************
int rtapi_app_main(void)
{
int i,res;
char* emsg="other";
// defaults prior to switchkinsSetup() call
kp.kinsname = NULL;
kp.halprefix = NULL;
kp.required_coordinates = "";
kp.max_joints = 0; // Setup must supply
kp.allow_duplicates = 0;
kp.fwd_iterates_mask = 0;
kp.gui_kinstype = -1; // negative means: not used
kp.sparm = sparm; // module parm passed to kins
KS ksetup0 = 0;
KS ksetup1 = 0;
KS ksetup2 = 0;
res = switchkinsSetup(&kp,
&ksetup0, &ksetup1, &ksetup2,
&kfwd0, &kfwd1, &kfwd2,
&kinv0, &kinv1, &kinv2);
if (res) {emsg="switchkinsSetp FAIL"; goto error;}
for (i=0; i < SWITCHKINS_MAX_TYPES; i++) {
if (kp.fwd_iterates_mask & (1<<i)) {
fwd_iterates[i] = 1;
rtapi_print("switchkins-type %d: fwd_iterates\n",i);
}
}
if (!kp.kinsname) { emsg = "Missing kinsname"; goto error; }
if (!kp.halprefix) {
kp.halprefix = kp.kinsname;
rtapi_print("Missing halprefix, using \"%s\"\n",kp.halprefix);
}
if (kp.max_joints <= 0 || kp.max_joints > EMCMOT_MAX_JOINTS) {
emsg = "bogus max_joints"; goto error;
}
if (kp.gui_kinstype >= SWITCHKINS_MAX_TYPES) {
emsg = "bogus gui_kinstype"; goto error;
}
if (!ksetup0 || !ksetup1 || !ksetup2) {
emsg = "Missing setup function"; goto error;
}
if (!kfwd0 || !kfwd1 || !kfwd2) {
emsg = "Missing fwd functionn"; goto error;
}
if (!kinv0 || !kinv1 || !kinv2) {
emsg = "Missing inv function"; goto error;
}
comp_id = hal_init(kp.kinsname);
if(comp_id < 0) goto error;
swdata = hal_malloc(sizeof(struct swdata));
if (!swdata) goto error;
res += hal_pin_bit_new("kinstype.is-0", HAL_OUT, &(swdata->kinstype_is_0), comp_id);
res += hal_pin_bit_new("kinstype.is-1", HAL_OUT, &(swdata->kinstype_is_1), comp_id);
res += hal_pin_bit_new("kinstype.is-2", HAL_OUT, &(swdata->kinstype_is_2), comp_id);
if (kp.gui_kinstype >=0) {
res += hal_pin_float_newf(HAL_IN, &swdata->gui_x, comp_id, "skgui.x");
res += hal_pin_float_newf(HAL_IN, &swdata->gui_y, comp_id, "skgui.y");
res += hal_pin_float_newf(HAL_IN, &swdata->gui_z, comp_id, "skgui.z");
res += hal_pin_float_newf(HAL_IN, &swdata->gui_a, comp_id, "skgui.a");
res += hal_pin_float_newf(HAL_IN, &swdata->gui_b, comp_id, "skgui.b");
res += hal_pin_float_newf(HAL_IN, &swdata->gui_c, comp_id, "skgui.c");
if (res) {emsg = "hal pin create fail";goto error;}
}
switchkins_type = 0; // startup with default type
kinematicsSwitch(switchkins_type);
if (!coordinates) {coordinates = kp.required_coordinates;}
ksetup0(comp_id,coordinates,&kp);
ksetup1(comp_id,coordinates,&kp);
ksetup2(comp_id,coordinates,&kp);
hal_ready(comp_id);
return 0;
error:
rtapi_print_msg(RTAPI_MSG_ERR,
"\nSwitchkins FAIL %s:<%s>\n",kp.kinsname,emsg);
hal_exit(comp_id);
return -1;
} // rtapi_app_main()
void rtapi_app_exit(void) { hal_exit(comp_id); }

View File

@@ -0,0 +1,36 @@
/*
** License GPL Version 2
*/
#ifndef SWITCHKINS_H // {
#define SWITCHKINS_H
#include <kinematics.h>
//hardcoded number of switchkins types (KS,KF,KI):
#define SWITCHKINS_MAX_TYPES 3
// KinematicsFORWARD functions
typedef int (*KF)(const double *joint,
EmcPose * pos,
const KINEMATICS_FORWARD_FLAGS * fflags,
KINEMATICS_INVERSE_FLAGS * iflags);
// KinematicsINVERSE functions
typedef int (*KI)(const struct EmcPose * world,
double *joint,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags);
// KinematicsSETUP functions
typedef int (*KS)(const int comp_id, // halpins
const char* coordinates, // module parameter
kparms* ksetup_parms //
);
//*********************************************************************
extern int switchkinsSetup(kparms* ksetup_parms,
KS* kset0, KS* kset1, KS* kset2,
KF* kfwd0, KF* kfwd1, KF* kfwd2,
KI* kinv0, KI* kinv1, KI* kinv2
);
#endif // }

View File

@@ -0,0 +1,83 @@
/* userkfuncs.c: template file for a user set of
** switchable kinematics functions.
** License GPL Version 2
**
** Example Usage (for customizing the genser-switchkins module):
** (works with rtpreempt only rtai --> Makefile needs work)
**
** LDIR is LinuxCNC git root directory
** UDIR is user directory (not in LinuxCNC git tree)
** 1) $ cp LDIR/src/emc/kinematics/userkfuncs.c UDIR/my_userk.c
** 2) $ edit UDIR/my_userk.c as required
** 3) $ source LDIR/scripts/rip-environment
** 4) For genser-switchkins module use make command line option:
** $ cd LDIR/src
** $ userkfuncs=UDIR/my_userk.c make && sudo make setuid
*/
// typical includes:
//#include <rtapi_math.h> // if reqd
#include <hal.h>
#include <kinematics.h>
// Add for kins based on genserkins:
// #include "genserkins.h" //includes gomath,hal
//**********************************************************************
// static local variables and functions go here
static int userk_inited = 0;
static struct udata {
hal_s32_t *fct;
hal_s32_t *ict;
} *udata;
//**********************************************************************
int userkKinematicsSetup(const int comp_id,
const char* coordinates,
kparms* kp)
{
int res=0;
rtapi_print("\nuserkKinematicsSetup:\n"
" %s <%s> max_joints=%d allow_duplicates=%d\n\n",
__FILE__,coordinates,
kp->max_joints,kp->allow_duplicates);
udata = hal_malloc(sizeof(struct udata));
if (!udata) goto error;
// HAL_IO used to allow resetting demo pins:
res += hal_pin_s32_new("userk.fct", HAL_IO, &(udata->fct), comp_id);
res += hal_pin_s32_new("userk.ict", HAL_IO, &(udata->ict), comp_id);
if (res) goto error;
userk_inited = 1;
return 0; // 0 ==> OK
error:
return -1;
}
int userkKinematicsForward(const double *joint,
struct EmcPose * world,
const KINEMATICS_FORWARD_FLAGS * fflags,
KINEMATICS_INVERSE_FLAGS * iflags)
{
if (!userk_inited) {
rtapi_print_msg(RTAPI_MSG_ERR,
"userkKinematics: not initialized\n");
return -1;
}
(*udata->fct)++;
return identityKinematicsForward(joint,world,fflags,iflags);
}
int userkKinematicsInverse(const EmcPose * pos,
double *joint,
const KINEMATICS_INVERSE_FLAGS * iflags,
KINEMATICS_FORWARD_FLAGS * fflags)
{
(*udata->ict)++;
return identityKinematicsInverse(pos,joint,iflags,fflags);
}

View File

@@ -0,0 +1,24 @@
#ifndef __LINUXCNC_RTAPI_CTYPE_H
#define __LINUXCNC_RTAPI_CTYPE_H
// Copyright 2006 Jeff Epler
//
// 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.
#ifdef MODULE
#include <linux/ctype.h>
#else
#include <ctype.h>
#endif
#endif