Add LinuxCNC cutter compensation coverage
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
#include "cnc_sim_api.h"
|
#include "cnc_sim_api.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -25,6 +26,10 @@ bool expect(bool value, const char *message) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool near(double lhs, double rhs) {
|
||||||
|
return std::fabs(lhs - rhs) < 0.000001;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
@@ -96,6 +101,12 @@ int main() {
|
|||||||
bool saw_g64_mode = false;
|
bool saw_g64_mode = false;
|
||||||
bool saw_tool_length = false;
|
bool saw_tool_length = false;
|
||||||
bool saw_tool_length_clear = false;
|
bool saw_tool_length_clear = false;
|
||||||
|
bool saw_cutter_left_first = false;
|
||||||
|
bool saw_cutter_left_second = false;
|
||||||
|
bool saw_cutter_left_off_move = false;
|
||||||
|
bool saw_cutter_right_first = false;
|
||||||
|
bool saw_cutter_right_second = false;
|
||||||
|
bool saw_cutter_right_off_move = false;
|
||||||
for (const auto &event : events) {
|
for (const auto &event : events) {
|
||||||
saw_tool = saw_tool || event.type == CNC_SIM_EVENT_TOOL_CHANGE;
|
saw_tool = saw_tool || event.type == CNC_SIM_EVENT_TOOL_CHANGE;
|
||||||
saw_rapid = saw_rapid || event.type == CNC_SIM_EVENT_RAPID;
|
saw_rapid = saw_rapid || event.type == CNC_SIM_EVENT_RAPID;
|
||||||
@@ -341,6 +352,61 @@ int main() {
|
|||||||
ok &= expect(saw_tool_length, "expected LinuxCNC G43 H1 tool length event");
|
ok &= expect(saw_tool_length, "expected LinuxCNC G43 H1 tool length event");
|
||||||
ok &= expect(saw_tool_length_clear, "expected LinuxCNC G49 tool length clear event");
|
ok &= expect(saw_tool_length_clear, "expected LinuxCNC G49 tool length clear event");
|
||||||
|
|
||||||
|
const char cutter_comp_program[] =
|
||||||
|
"G21 G90 G17\n"
|
||||||
|
"G0 X0 Y0 Z0\n"
|
||||||
|
"F100\n"
|
||||||
|
"G41.1 D6\n"
|
||||||
|
"G1 X20 Y0\n"
|
||||||
|
"G1 X20 Y20\n"
|
||||||
|
"G40\n"
|
||||||
|
"G1 X0 Y0\n"
|
||||||
|
"G42.1 D6\n"
|
||||||
|
"G1 X20 Y0\n"
|
||||||
|
"G1 X20 Y-20\n"
|
||||||
|
"G40\n"
|
||||||
|
"G1 X0 Y0\n"
|
||||||
|
"M30\n";
|
||||||
|
events.clear();
|
||||||
|
ok &= expect(cnc_sim_parse_program(sim, cutter_comp_program, sizeof(cutter_comp_program) - 1) == 0,
|
||||||
|
cnc_sim_last_error(sim));
|
||||||
|
for (const auto &event : events) {
|
||||||
|
saw_cutter_left_first = saw_cutter_left_first ||
|
||||||
|
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||||
|
near(event.end.x, 17.0) &&
|
||||||
|
near(event.end.y, 3.0));
|
||||||
|
saw_cutter_left_second = saw_cutter_left_second ||
|
||||||
|
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||||
|
event.line == 7 &&
|
||||||
|
near(event.end.x, 17.0) &&
|
||||||
|
near(event.end.y, 20.0));
|
||||||
|
saw_cutter_left_off_move = saw_cutter_left_off_move ||
|
||||||
|
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||||
|
event.line == 8 &&
|
||||||
|
near(event.end.x, 0.0) &&
|
||||||
|
near(event.end.y, 0.0));
|
||||||
|
saw_cutter_right_first = saw_cutter_right_first ||
|
||||||
|
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||||
|
near(event.end.x, 17.0) &&
|
||||||
|
near(event.end.y, -3.0));
|
||||||
|
saw_cutter_right_second = saw_cutter_right_second ||
|
||||||
|
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||||
|
event.line == 12 &&
|
||||||
|
near(event.end.x, 17.0) &&
|
||||||
|
near(event.end.y, -20.0));
|
||||||
|
saw_cutter_right_off_move = saw_cutter_right_off_move ||
|
||||||
|
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||||
|
event.line == 13 &&
|
||||||
|
near(event.end.x, 0.0) &&
|
||||||
|
near(event.end.y, 0.0));
|
||||||
|
}
|
||||||
|
ok &= expect(saw_cutter_left_first, "expected LinuxCNC G41.1 compensated lead-in motion");
|
||||||
|
ok &= expect(saw_cutter_left_second, "expected LinuxCNC G41.1 compensated side motion");
|
||||||
|
ok &= expect(saw_cutter_left_off_move, "expected LinuxCNC G40 move after left compensation");
|
||||||
|
ok &= expect(saw_cutter_right_first, "expected LinuxCNC G42.1 compensated lead-in motion");
|
||||||
|
ok &= expect(saw_cutter_right_second, "expected LinuxCNC G42.1 compensated side motion");
|
||||||
|
ok &= expect(saw_cutter_right_off_move, "expected LinuxCNC G40 move after right compensation");
|
||||||
|
|
||||||
const char comment_program[] =
|
const char comment_program[] =
|
||||||
"G21 G90 G17\n"
|
"G21 G90 G17\n"
|
||||||
"(operator note)\n"
|
"(operator note)\n"
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ This matrix tracks LinuxCNC feature coverage for the web/WASM simulator. A featu
|
|||||||
| Kinematics switch `M428/M429/M430` | covered as simulator-owned control lines | `tests/gcode/linuxcnc_rtcp_controls.ngc` |
|
| Kinematics switch `M428/M429/M430` | covered as simulator-owned control lines | `tests/gcode/linuxcnc_rtcp_controls.ngc` |
|
||||||
| Canned cycle `G81/G80` | covered for drilling expand-to-canon path | `tests/gcode/linuxcnc_canned_cycle.ngc` |
|
| Canned cycle `G81/G80` | covered for drilling expand-to-canon path | `tests/gcode/linuxcnc_canned_cycle.ngc` |
|
||||||
| Coordinate offset Canon events | bridge-level covered | `core/tests/linuxcnc_canon_bridge_smoke.cpp` |
|
| Coordinate offset Canon events | bridge-level covered | `core/tests/linuxcnc_canon_bridge_smoke.cpp` |
|
||||||
| Cutter compensation | pending | add LinuxCNC corpus and tolerance checks |
|
| Cutter compensation | covered for explicit-radius `G41.1/G42.1/G40` through LinuxCNC native/source backends; tool-table `G41/G42 D...` remains pending | `tests/gcode/linuxcnc_cutter_comp.ngc` |
|
||||||
| O-word subroutines and calls | covered for numeric `O... sub/call/return/endsub` through LinuxCNC file mode; smoke parser also covers named `O<name>` sub/call/return/endsub | `tests/gcode/smoke_oword_subprogram.ngc` |
|
| O-word subroutines and calls | covered for numeric `O... sub/call/return/endsub` through LinuxCNC file mode; smoke parser also covers named `O<name>` sub/call/return/endsub | `tests/gcode/smoke_oword_subprogram.ngc` |
|
||||||
| Broader canned cycles `G73`, `G82`-`G89` | partially covered: `G73`, `G82`, `G83`, `G85`, `G86`, `G89` | `tests/gcode/linuxcnc_canned_cycles_extended.ngc`, smoke API regression |
|
| Broader canned cycles `G73`, `G82`-`G89` | partially covered: `G73`, `G82`, `G83`, `G85`, `G86`, `G89` | `tests/gcode/linuxcnc_canned_cycles_extended.ngc`, smoke API regression |
|
||||||
| Full source-level wasm build | pending | replace Python/HAL/INI/tooldata support dependencies |
|
| Full source-level wasm build | pending | replace Python/HAL/INI/tooldata support dependencies |
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linux
|
|||||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_tool_length.ngc >/tmp/cnc_sim_linuxcnc_tool_length.json
|
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_tool_length.ngc >/tmp/cnc_sim_linuxcnc_tool_length.json
|
||||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_canned_cycle.ngc >/tmp/cnc_sim_linuxcnc_canned_cycle.json
|
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_canned_cycle.ngc >/tmp/cnc_sim_linuxcnc_canned_cycle.json
|
||||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_canned_cycles_extended.ngc >/tmp/cnc_sim_linuxcnc_canned_cycles_extended.json
|
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_canned_cycles_extended.ngc >/tmp/cnc_sim_linuxcnc_canned_cycles_extended.json
|
||||||
|
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_cutter_comp.ngc >/tmp/cnc_sim_linuxcnc_cutter_comp.json
|
||||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_comments.ngc >/tmp/cnc_sim_linuxcnc_comments.json
|
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_comments.ngc >/tmp/cnc_sim_linuxcnc_comments.json
|
||||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_probe_no_error.ngc >/tmp/cnc_sim_linuxcnc_probe_no_error.json
|
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_probe_no_error.ngc >/tmp/cnc_sim_linuxcnc_probe_no_error.json
|
||||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/smoke_oword_subprogram.ngc >/tmp/cnc_sim_linuxcnc_oword_subprogram.json
|
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/smoke_oword_subprogram.ngc >/tmp/cnc_sim_linuxcnc_oword_subprogram.json
|
||||||
@@ -213,6 +214,28 @@ if not any(
|
|||||||
):
|
):
|
||||||
raise SystemExit("missing G83 final retract to R plane")
|
raise SystemExit("missing G83 final retract to R plane")
|
||||||
|
|
||||||
|
cutter_comp = json.loads(Path("/tmp/cnc_sim_linuxcnc_cutter_comp.json").read_text())
|
||||||
|
cutter_comp_motions = [
|
||||||
|
event
|
||||||
|
for event in cutter_comp
|
||||||
|
if event["type"] in {"rapid", "linear-feed", "arc-feed"}
|
||||||
|
]
|
||||||
|
expected_cutter_comp = [
|
||||||
|
("rapid", 2, 0, 0),
|
||||||
|
("linear-feed", 6, 17, 3),
|
||||||
|
("linear-feed", 7, 17, 20),
|
||||||
|
("linear-feed", 8, 0, 0),
|
||||||
|
("linear-feed", 11, 17, -3),
|
||||||
|
("linear-feed", 12, 17, -20),
|
||||||
|
("linear-feed", 13, 0, 0),
|
||||||
|
]
|
||||||
|
actual_cutter_comp = [
|
||||||
|
(event["type"], event["line"], event["end"]["x"], event["end"]["y"])
|
||||||
|
for event in cutter_comp_motions
|
||||||
|
]
|
||||||
|
if actual_cutter_comp != expected_cutter_comp:
|
||||||
|
raise SystemExit(f"unexpected cutter compensation path: {actual_cutter_comp!r}")
|
||||||
|
|
||||||
comments = json.loads(Path("/tmp/cnc_sim_linuxcnc_comments.json").read_text())
|
comments = json.loads(Path("/tmp/cnc_sim_linuxcnc_comments.json").read_text())
|
||||||
if not any(event["type"] == "comment" and event["line"] == 2 for event in comments):
|
if not any(event["type"] == "comment" and event["line"] == 2 for event in comments):
|
||||||
raise SystemExit("missing LinuxCNC comment line event")
|
raise SystemExit("missing LinuxCNC comment line event")
|
||||||
@@ -309,6 +332,7 @@ echo "dumped /tmp/cnc_sim_linuxcnc_motion_modes.json"
|
|||||||
echo "dumped /tmp/cnc_sim_linuxcnc_tool_length.json"
|
echo "dumped /tmp/cnc_sim_linuxcnc_tool_length.json"
|
||||||
echo "dumped /tmp/cnc_sim_linuxcnc_canned_cycle.json"
|
echo "dumped /tmp/cnc_sim_linuxcnc_canned_cycle.json"
|
||||||
echo "dumped /tmp/cnc_sim_linuxcnc_canned_cycles_extended.json"
|
echo "dumped /tmp/cnc_sim_linuxcnc_canned_cycles_extended.json"
|
||||||
|
echo "dumped /tmp/cnc_sim_linuxcnc_cutter_comp.json"
|
||||||
echo "dumped /tmp/cnc_sim_linuxcnc_comments.json"
|
echo "dumped /tmp/cnc_sim_linuxcnc_comments.json"
|
||||||
echo "dumped /tmp/cnc_sim_linuxcnc_probe_no_error.json"
|
echo "dumped /tmp/cnc_sim_linuxcnc_probe_no_error.json"
|
||||||
echo "dumped /tmp/cnc_sim_linuxcnc_oword_subprogram.json"
|
echo "dumped /tmp/cnc_sim_linuxcnc_oword_subprogram.json"
|
||||||
|
|||||||
@@ -106,6 +106,9 @@ CNC_SIM_RS274_VAR="$var_file" \
|
|||||||
CNC_SIM_RS274_VAR="$var_file" \
|
CNC_SIM_RS274_VAR="$var_file" \
|
||||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_canned_cycles_extended.ngc \
|
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_canned_cycles_extended.ngc \
|
||||||
>/tmp/cnc_sim_linuxcnc_source_canned_cycles_extended.json
|
>/tmp/cnc_sim_linuxcnc_source_canned_cycles_extended.json
|
||||||
|
CNC_SIM_RS274_VAR="$var_file" \
|
||||||
|
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_cutter_comp.ngc \
|
||||||
|
>/tmp/cnc_sim_linuxcnc_source_cutter_comp.json
|
||||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/smoke_oword_subprogram.ngc \
|
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/smoke_oword_subprogram.ngc \
|
||||||
>/tmp/cnc_sim_linuxcnc_source_oword_subprogram.json
|
>/tmp/cnc_sim_linuxcnc_source_oword_subprogram.json
|
||||||
@@ -188,6 +191,28 @@ if not any(
|
|||||||
):
|
):
|
||||||
raise SystemExit("missing source-linked G83 final retract to R plane")
|
raise SystemExit("missing source-linked G83 final retract to R plane")
|
||||||
|
|
||||||
|
cutter_comp = json.loads(Path("/tmp/cnc_sim_linuxcnc_source_cutter_comp.json").read_text())
|
||||||
|
cutter_comp_motions = [
|
||||||
|
event
|
||||||
|
for event in cutter_comp
|
||||||
|
if event["type"] in {"rapid", "linear-feed", "arc-feed"}
|
||||||
|
]
|
||||||
|
expected_cutter_comp = [
|
||||||
|
("rapid", 2, 0, 0),
|
||||||
|
("linear-feed", 6, 17, 3),
|
||||||
|
("linear-feed", 7, 17, 20),
|
||||||
|
("linear-feed", 8, 0, 0),
|
||||||
|
("linear-feed", 11, 17, -3),
|
||||||
|
("linear-feed", 12, 17, -20),
|
||||||
|
("linear-feed", 13, 0, 0),
|
||||||
|
]
|
||||||
|
actual_cutter_comp = [
|
||||||
|
(event["type"], event["line"], event["end"]["x"], event["end"]["y"])
|
||||||
|
for event in cutter_comp_motions
|
||||||
|
]
|
||||||
|
if actual_cutter_comp != expected_cutter_comp:
|
||||||
|
raise SystemExit(f"unexpected source-linked cutter compensation path: {actual_cutter_comp!r}")
|
||||||
|
|
||||||
oword = json.loads(Path("/tmp/cnc_sim_linuxcnc_source_oword_subprogram.json").read_text())
|
oword = json.loads(Path("/tmp/cnc_sim_linuxcnc_source_oword_subprogram.json").read_text())
|
||||||
if not any(
|
if not any(
|
||||||
event["type"] == "linear-feed" and
|
event["type"] == "linear-feed" and
|
||||||
@@ -219,4 +244,5 @@ echo "dumped /tmp/cnc_sim_linuxcnc_source_basic_mill.json"
|
|||||||
echo "dumped /tmp/cnc_sim_linuxcnc_source_rtcp_controls.json"
|
echo "dumped /tmp/cnc_sim_linuxcnc_source_rtcp_controls.json"
|
||||||
echo "dumped /tmp/cnc_sim_linuxcnc_source_canned_cycle.json"
|
echo "dumped /tmp/cnc_sim_linuxcnc_source_canned_cycle.json"
|
||||||
echo "dumped /tmp/cnc_sim_linuxcnc_source_canned_cycles_extended.json"
|
echo "dumped /tmp/cnc_sim_linuxcnc_source_canned_cycles_extended.json"
|
||||||
|
echo "dumped /tmp/cnc_sim_linuxcnc_source_cutter_comp.json"
|
||||||
echo "dumped /tmp/cnc_sim_linuxcnc_source_oword_subprogram.json"
|
echo "dumped /tmp/cnc_sim_linuxcnc_source_oword_subprogram.json"
|
||||||
|
|||||||
14
tests/gcode/linuxcnc_cutter_comp.ngc
Normal file
14
tests/gcode/linuxcnc_cutter_comp.ngc
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
G21 G90 G17
|
||||||
|
G0 X0 Y0 Z0
|
||||||
|
F100
|
||||||
|
G41.1 D6
|
||||||
|
G1 X20 Y0
|
||||||
|
G1 X20 Y20
|
||||||
|
G40
|
||||||
|
G1 X0 Y0
|
||||||
|
G42.1 D6
|
||||||
|
G1 X20 Y0
|
||||||
|
G1 X20 Y-20
|
||||||
|
G40
|
||||||
|
G1 X0 Y0
|
||||||
|
M30
|
||||||
Reference in New Issue
Block a user