Add ABB120 demo suite and docs
This commit is contained in:
19
kdl-wasm/web/tests/fixtures/abb120/spec-programs/error/W2_E30_MotionDiagnostics.grl
vendored
Normal file
19
kdl-wasm/web/tests/fixtures/abb120/spec-programs/error/W2_E30_MotionDiagnostics.grl
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
language grl 0.1
|
||||
module W2MotionDiagnostics
|
||||
const speed v = joint(30 %)
|
||||
const speed vl = linear(100 mm/s)
|
||||
const zone zf = fine
|
||||
target too_far_joint = joint_target { joints: [220 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
target unreachable_pose = pose_target { pose: pose(2000 mm, 0 mm, 2000 mm, 0 deg, 0 deg, 0 deg) }
|
||||
target arc_a = pose_target { pose: pose(500 mm, 0 mm, 0 mm, 0 deg, 0 deg, 0 deg) }
|
||||
target arc_b = pose_target { pose: pose(550 mm, 0 mm, 0 mm, 0 deg, 0 deg, 0 deg) }
|
||||
target arc_c = pose_target { pose: pose(600 mm, 0 mm, 0 mm, 0 deg, 0 deg, 0 deg) }
|
||||
path empty_path {
|
||||
}
|
||||
proc main()
|
||||
movej too_far_joint speed v zone zf
|
||||
movel unreachable_pose speed vl zone zf
|
||||
movec via arc_b target arc_c speed vl zone zf
|
||||
run_path empty_path
|
||||
end
|
||||
end
|
||||
14
kdl-wasm/web/tests/fixtures/abb120/spec-programs/error/W2_E50_RuntimeTimeout.grl
vendored
Normal file
14
kdl-wasm/web/tests/fixtures/abb120/spec-programs/error/W2_E50_RuntimeTimeout.grl
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
language grl 0.1
|
||||
module W2RuntimeTimeout
|
||||
const speed v = joint(30 %)
|
||||
const zone zf = fine
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
proc on_timeout_recover()
|
||||
alarm TIMEOUT_RECOVER "timeout recover" severity warning
|
||||
end
|
||||
proc main()
|
||||
wait io.di[99] == true timeout 100 ms on_timeout alarm "DI99 timeout"
|
||||
wait io.di[98] == true timeout 100 ms on_timeout call on_timeout_recover()
|
||||
movej home speed v zone zf
|
||||
end
|
||||
end
|
||||
52
kdl-wasm/web/tests/fixtures/abb120/spec-programs/manifest.json
vendored
Normal file
52
kdl-wasm/web/tests/fixtures/abb120/spec-programs/manifest.json
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"suite_id": "working2-abb120-spec",
|
||||
"robot_id": "abb_irb120_3_58",
|
||||
"spec_source": "work/doc/通用机器人编程语法规范.md",
|
||||
"program_root": "kdl-wasm/web/tests/fixtures/abb120/spec-programs",
|
||||
"runtime_commands": ["loadProgram", "start", "stepInto", "hold", "resume", "stepMotion", "stop", "resetFault"],
|
||||
"programs": [
|
||||
{ "program_id": "W2_00_MinimalModule", "file": "runtime/W2_00_MinimalModule.grl", "coverage_level": "Runtime", "spec_sections": [4, 5, 6, 9, 10, 23], "expected_status": "pass", "expected_diagnostics": [] },
|
||||
{ "program_id": "W2_10_DataTargetToolFrame", "file": "runtime/W2_10_DataTargetToolFrame.grl", "coverage_level": "Runtime", "spec_sections": [6, 8, 9], "expected_status": "pass", "expected_diagnostics": [] },
|
||||
{ "program_id": "W2_20_ExpressionMath", "file": "runtime/W2_20_ExpressionMath.grl", "coverage_level": "Runtime", "spec_sections": [7, 9, 13], "expected_status": "pass", "expected_diagnostics": [] },
|
||||
{ "program_id": "W2_30_MotionAllTypes", "file": "runtime/W2_30_MotionAllTypes.grl", "coverage_level": "Runtime", "spec_sections": [8, 9, 10], "expected_status": "pass", "expected_diagnostics": [] },
|
||||
{ "program_id": "W2_40_PathEvents", "file": "runtime/W2_40_PathEvents.grl", "coverage_level": "Runtime", "spec_sections": [11, 13, 19], "expected_status": "pass", "expected_diagnostics": [] },
|
||||
{ "program_id": "W2_50_OperationProcess", "file": "runtime/W2_50_OperationProcess.grl", "coverage_level": "Runtime", "spec_sections": [12, 13], "expected_status": "pass", "expected_diagnostics": [] },
|
||||
{ "program_id": "W2_60_IOWaitPulse", "file": "runtime/W2_60_IOWaitPulse.grl", "coverage_level": "Runtime", "spec_sections": [13], "expected_status": "pass", "expected_diagnostics": [] },
|
||||
{ "program_id": "W2_70_ControlFlow", "file": "runtime/W2_70_ControlFlow.grl", "coverage_level": "Runtime", "spec_sections": [14], "expected_status": "pass", "expected_diagnostics": [] },
|
||||
{ "program_id": "W2_80_ProcFuncCall", "file": "runtime/W2_80_ProcFuncCall.grl", "coverage_level": "Runtime", "spec_sections": [15], "expected_status": "pass", "expected_diagnostics": [] },
|
||||
{ "program_id": "W2_90_ExceptionAlarm", "file": "runtime/W2_90_ExceptionAlarm.grl", "coverage_level": "Runtime", "spec_sections": [16, 17], "expected_status": "pass", "expected_diagnostics": ["GRL_P1_UNIMPLEMENTED"] },
|
||||
{ "program_id": "W2_99_FullSpecExample", "file": "runtime/W2_99_FullSpecExample.grl", "coverage_level": "Runtime", "spec_sections": [24], "expected_status": "pass", "expected_diagnostics": [] },
|
||||
{ "program_id": "W2_E10_ExpressionDiagnostics", "file": "static/W2_E10_ExpressionDiagnostics.grl", "coverage_level": "Static", "spec_sections": [7, 22], "expected_status": "diagnostic", "expected_diagnostics": ["GRL_EXPR_UNKNOWN_SYMBOL", "GRL_EXPR_UNKNOWN_FUNCTION", "GRL_EXPR_ARITY", "GRL_EXPR_DOMAIN", "GRL_EXPR_DIV_ZERO", "GRL_EXPR_UNIT_MISMATCH"] },
|
||||
{ "program_id": "W2_E20_SemanticDiagnostics", "file": "static/W2_E20_SemanticDiagnostics.grl", "coverage_level": "Static", "spec_sections": [6, 15, 22], "expected_status": "diagnostic", "expected_diagnostics": ["GRL_SYMBOL_DUPLICATE", "GRL_ARGUMENT_NOT_LVALUE", "GRL_CALL_TARGET_NOT_FOUND", "GRL_FUNC_SIDE_EFFECT", "GRL_TARGET_NOT_FOUND"] },
|
||||
{ "program_id": "W2_E30_MotionDiagnostics", "file": "error/W2_E30_MotionDiagnostics.grl", "coverage_level": "Static", "spec_sections": [8, 9, 10, 11, 22], "expected_status": "diagnostic", "expected_diagnostics": ["KDL_JOINT_LIMIT", "KDL_TARGET_UNREACHABLE", "GRL_PATH_EMPTY"] },
|
||||
{ "program_id": "W2_E40_ControlFlowDiagnostics", "file": "static/W2_E40_ControlFlowDiagnostics.grl", "coverage_level": "Static", "spec_sections": [14, 22], "expected_status": "diagnostic", "expected_diagnostics": ["GRL_BREAK_OUTSIDE_FLOW", "GRL_CONTINUE_OUTSIDE_LOOP", "GRL_JUMP_INTO_BLOCK", "GRL_SWITCH_CASE_DUPLICATE", "GRL_SWITCH_CASE_NOT_CONSTANT", "GRL_LABEL_NOT_FOUND"] },
|
||||
{ "program_id": "W2_E50_RuntimeTimeout", "file": "error/W2_E50_RuntimeTimeout.grl", "coverage_level": "Runtime", "spec_sections": [13, 16], "expected_status": "diagnostic", "expected_diagnostics": ["VC_WAIT_TIMEOUT"] },
|
||||
{ "program_id": "W2_P10_BrandHints", "file": "post/W2_P10_BrandHints.grl", "coverage_level": "Post", "spec_sections": [18, 20], "expected_status": "pass", "expected_diagnostics": ["GRL_POST_HINT_IGNORED"] },
|
||||
{ "program_id": "W2_P20_CrossBrandMotion", "file": "post/W2_P20_CrossBrandMotion.grl", "coverage_level": "Post", "spec_sections": [20], "expected_status": "pass", "expected_diagnostics": [] },
|
||||
{ "program_id": "W2_P30_Roundtrip", "file": "post/W2_P30_Roundtrip.grl", "coverage_level": "Post", "spec_sections": [19, 20, 21], "expected_status": "pass", "expected_diagnostics": [] }
|
||||
],
|
||||
"coverage_matrix": [
|
||||
{ "spec_section": 4, "coverage_level": "Runtime/Static", "program_ids": ["W2_00_MinimalModule"] },
|
||||
{ "spec_section": 5, "coverage_level": "Runtime", "program_ids": ["W2_00_MinimalModule"] },
|
||||
{ "spec_section": 6, "coverage_level": "Runtime/Static", "program_ids": ["W2_10_DataTargetToolFrame", "W2_E20_SemanticDiagnostics"] },
|
||||
{ "spec_section": 7, "coverage_level": "Runtime/Static/Post", "program_ids": ["W2_20_ExpressionMath", "W2_E10_ExpressionDiagnostics", "W2_P20_CrossBrandMotion"] },
|
||||
{ "spec_section": 8, "coverage_level": "Runtime/Static", "program_ids": ["W2_10_DataTargetToolFrame", "W2_E30_MotionDiagnostics"] },
|
||||
{ "spec_section": 9, "coverage_level": "Runtime/Post", "program_ids": ["W2_20_ExpressionMath", "W2_30_MotionAllTypes", "W2_P20_CrossBrandMotion"] },
|
||||
{ "spec_section": 10, "coverage_level": "Runtime/Static/Post", "program_ids": ["W2_30_MotionAllTypes", "W2_E30_MotionDiagnostics", "W2_P20_CrossBrandMotion"] },
|
||||
{ "spec_section": 11, "coverage_level": "Runtime/Static", "program_ids": ["W2_40_PathEvents", "W2_E30_MotionDiagnostics"] },
|
||||
{ "spec_section": 12, "coverage_level": "Runtime/Post", "program_ids": ["W2_50_OperationProcess", "W2_P30_Roundtrip"] },
|
||||
{ "spec_section": 13, "coverage_level": "Runtime", "program_ids": ["W2_60_IOWaitPulse", "W2_E50_RuntimeTimeout"] },
|
||||
{ "spec_section": 14, "coverage_level": "Runtime/Static", "program_ids": ["W2_70_ControlFlow", "W2_E40_ControlFlowDiagnostics"] },
|
||||
{ "spec_section": 15, "coverage_level": "Runtime/Static", "program_ids": ["W2_80_ProcFuncCall", "W2_E20_SemanticDiagnostics"] },
|
||||
{ "spec_section": 16, "coverage_level": "Runtime/Static", "program_ids": ["W2_90_ExceptionAlarm", "W2_E50_RuntimeTimeout"] },
|
||||
{ "spec_section": 17, "coverage_level": "Runtime/Static", "program_ids": ["W2_90_ExceptionAlarm"] },
|
||||
{ "spec_section": 18, "coverage_level": "Post", "program_ids": ["W2_P10_BrandHints"] },
|
||||
{ "spec_section": 19, "coverage_level": "Post", "program_ids": ["W2_P30_Roundtrip"] },
|
||||
{ "spec_section": 20, "coverage_level": "Post", "program_ids": ["W2_P20_CrossBrandMotion"] },
|
||||
{ "spec_section": 21, "coverage_level": "Runtime/Static", "program_ids": ["W2_00_MinimalModule", "W2_E10_ExpressionDiagnostics"] },
|
||||
{ "spec_section": 22, "coverage_level": "Runtime/Static", "program_ids": ["W2_E10_ExpressionDiagnostics", "W2_E20_SemanticDiagnostics", "W2_E30_MotionDiagnostics", "W2_E40_ControlFlowDiagnostics", "W2_E50_RuntimeTimeout"] },
|
||||
{ "spec_section": 23, "coverage_level": "Runtime/Static", "program_ids": ["W2_00_MinimalModule"] },
|
||||
{ "spec_section": 24, "coverage_level": "Runtime/Post", "program_ids": ["W2_99_FullSpecExample", "W2_P30_Roundtrip"] },
|
||||
{ "spec_section": 25, "coverage_level": "Runtime/Static/Post", "program_ids": ["W2_00_MinimalModule", "W2_10_DataTargetToolFrame", "W2_20_ExpressionMath", "W2_30_MotionAllTypes", "W2_40_PathEvents", "W2_50_OperationProcess", "W2_60_IOWaitPulse", "W2_70_ControlFlow", "W2_80_ProcFuncCall", "W2_90_ExceptionAlarm", "W2_P20_CrossBrandMotion"] }
|
||||
]
|
||||
}
|
||||
12
kdl-wasm/web/tests/fixtures/abb120/spec-programs/post/W2_P10_BrandHints.grl
vendored
Normal file
12
kdl-wasm/web/tests/fixtures/abb120/spec-programs/post/W2_P10_BrandHints.grl
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
language grl 0.1
|
||||
module W2BrandHints
|
||||
post_hint abb
|
||||
post_hint fanuc
|
||||
post_hint kuka
|
||||
const speed v = joint(40 %)
|
||||
const zone zf = fine
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
proc main()
|
||||
movej home speed v zone zf
|
||||
end
|
||||
end
|
||||
20
kdl-wasm/web/tests/fixtures/abb120/spec-programs/post/W2_P20_CrossBrandMotion.grl
vendored
Normal file
20
kdl-wasm/web/tests/fixtures/abb120/spec-programs/post/W2_P20_CrossBrandMotion.grl
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
language grl 0.1
|
||||
module W2CrossBrandMotion
|
||||
post_hint abb
|
||||
const speed vj = joint(50 %)
|
||||
const speed vl = linear(200 mm/s)
|
||||
const zone z10 = z(10 mm)
|
||||
const zone zcnt = cnt(50)
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
target pick = pose_target { pose: pose(500 mm, 0 mm, 0 mm, 0 deg, 0 deg, 0 deg) }
|
||||
target mid = pose_target { pose: pose(550 mm, 50 mm, 0 mm, 0 deg, 0 deg, 0 deg) }
|
||||
target place = pose_target { pose: pose(600 mm, 0 mm, 0 mm, 0 deg, 0 deg, 0 deg) }
|
||||
proc main()
|
||||
movej home speed vj zone fine
|
||||
movel pick speed vl zone z10
|
||||
movec via mid target place speed vl zone zcnt
|
||||
io.do[1] = true
|
||||
wait io.di[1] == true timeout 1 s
|
||||
pulse io.do[2] duration 100 ms
|
||||
end
|
||||
end
|
||||
24
kdl-wasm/web/tests/fixtures/abb120/spec-programs/post/W2_P30_Roundtrip.grl
vendored
Normal file
24
kdl-wasm/web/tests/fixtures/abb120/spec-programs/post/W2_P30_Roundtrip.grl
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
language grl 0.1
|
||||
module W2Roundtrip
|
||||
const speed vj = joint(40 %)
|
||||
const speed vl = linear(150 mm/s)
|
||||
const zone z10 = z(10 mm)
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
target pick = pose_target { pose: pose(500 mm, 0 mm, 0 mm, 0 deg, 0 deg, 0 deg) }
|
||||
path roundtrip_path {
|
||||
defaults { speed: vj, zone: z10 }
|
||||
point p0 movej home zone fine
|
||||
point p1 movel pick speed vl zone z10
|
||||
}
|
||||
operation roundtrip_op {
|
||||
kind: handling
|
||||
path: roundtrip_path
|
||||
process {
|
||||
generator: "working2"
|
||||
}
|
||||
}
|
||||
proc main()
|
||||
run_operation roundtrip_op
|
||||
movej home speed vj zone fine
|
||||
end
|
||||
end
|
||||
9
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_00_MinimalModule.grl
vendored
Normal file
9
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_00_MinimalModule.grl
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
language grl 0.1
|
||||
module W2MinimalModule
|
||||
const speed v_joint = joint(40 %)
|
||||
const zone zf = fine
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
proc main()
|
||||
movej home speed v_joint zone zf
|
||||
end
|
||||
end
|
||||
45
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_10_DataTargetToolFrame.grl
vendored
Normal file
45
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_10_DataTargetToolFrame.grl
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
language grl 0.1
|
||||
module W2DataTargetToolFrame
|
||||
persistent tool gripper = tool {
|
||||
tcp: pose(0 mm, 0 mm, 100 mm, 0 deg, 0 deg, 0 deg),
|
||||
mass: 1.25 kg,
|
||||
cog: [0 mm, 0 mm, 40 mm]
|
||||
}
|
||||
persistent frame fixture = frame { origin: pose(800 mm, 0 mm, 0 mm, 0 deg, 0 deg, 0 deg) }
|
||||
const bool use_fixture = true
|
||||
const int slot_count = 2
|
||||
const real blend_scale = 1.5
|
||||
const string recipe = "w2"
|
||||
const time settle = 250 ms
|
||||
const length lift = 80 mm
|
||||
const angle face = 90 deg
|
||||
const percent safe_percent = 40 %
|
||||
const speed vj = joint(safe_percent)
|
||||
const speed vl = linear(120 mm/s)
|
||||
const zone z5 = z(5 mm)
|
||||
const pose safe_pose = pose(500 mm, 0 mm, 100 mm, 0 deg, 0 deg, face)
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
target approach = joint_target {
|
||||
joints: [0 deg, -22.918312 deg, 28.647890 deg, 0 deg, 11.459156 deg, 0 deg]
|
||||
}
|
||||
target pick = pose_target {
|
||||
pose: pose(500 mm, 0 mm, 0 mm, 0 deg, 0 deg, 90 deg),
|
||||
config: robot_config(0, 0, 1),
|
||||
tool: gripper,
|
||||
frame: fixture
|
||||
}
|
||||
target pick_q = pose_target {
|
||||
pose: poseq(500 mm, 30 mm, 0 mm, 0, 0, 0, 1),
|
||||
tool: gripper,
|
||||
frame: fixture
|
||||
}
|
||||
proc main()
|
||||
set_tool gripper
|
||||
set_frame fixture
|
||||
set_speed vl
|
||||
set_zone z5
|
||||
movej home speed vj zone fine
|
||||
movej approach speed vj zone z5 tool gripper frame fixture
|
||||
movel pick_q speed vl zone z5 tool gripper frame fixture
|
||||
end
|
||||
end
|
||||
20
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_20_ExpressionMath.grl
vendored
Normal file
20
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_20_ExpressionMath.grl
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
language grl 0.1
|
||||
module W2ExpressionMath
|
||||
const real blend_base = 5 + 5
|
||||
const real trig_value = sin(30 deg)
|
||||
const bool math_ok = (10 mm + 5 mm) > 12 mm and not false
|
||||
const speed v_pick = linear(100 + 50 mm/s)
|
||||
const speed v_safe = linear(max(50 mm/s, 200 mm/s / 2))
|
||||
const zone z_app = z(clamp(blend_base mm, 1 mm, 50 mm))
|
||||
target home = joint_target {
|
||||
joints: [0 deg, (10 + 5) deg, -30 deg, 0 deg, abs(-15) deg, round(pi) deg]
|
||||
}
|
||||
target pick = pose_target {
|
||||
pose: pose(400 + 50 mm, 20 * 2 mm, sqrt(90000) mm, 0 deg, 0 deg, atan2(1, 1))
|
||||
}
|
||||
proc main()
|
||||
movej home speed v_safe zone z_app
|
||||
movel pick speed v_pick zone z_app
|
||||
wait io.ai[2] > 0.5 timeout 1 + 1 s
|
||||
end
|
||||
end
|
||||
21
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_30_MotionAllTypes.grl
vendored
Normal file
21
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_30_MotionAllTypes.grl
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
language grl 0.1
|
||||
module W2MotionAllTypes
|
||||
persistent tool gripper = tool { tcp: pose(0 mm, 0 mm, 80 mm, 0 deg, 0 deg, 0 deg), mass: 1 kg }
|
||||
persistent frame fixture = frame { origin: pose(800 mm, 0 mm, 0 mm, 0 deg, 0 deg, 0 deg) }
|
||||
const speed vj = joint(45 %)
|
||||
const speed vl = linear(150 mm/s)
|
||||
const zone z10 = z(10 mm)
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
target start = pose_target { pose: pose(500 mm, 0 mm, 0 mm, 0 deg, 0 deg, 0 deg), tool: gripper, frame: fixture }
|
||||
target mid = pose_target { pose: pose(550 mm, 50 mm, 0 mm, 0 deg, 0 deg, 0 deg), tool: gripper, frame: fixture }
|
||||
target finish = pose_target { pose: pose(600 mm, 0 mm, 0 mm, 0 deg, 0 deg, 0 deg), tool: gripper, frame: fixture }
|
||||
proc main()
|
||||
set_tool gripper
|
||||
set_frame fixture
|
||||
set_speed vl
|
||||
set_zone z10
|
||||
movej home speed vj zone fine
|
||||
movel start
|
||||
movec via mid target finish speed linear(100 mm/s) zone fine
|
||||
end
|
||||
end
|
||||
26
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_40_PathEvents.grl
vendored
Normal file
26
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_40_PathEvents.grl
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
language grl 0.1
|
||||
module W2PathEvents
|
||||
const speed vj = joint(35 %)
|
||||
const speed vl = linear(120 mm/s)
|
||||
const zone z10 = z(10 mm)
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
target pick = joint_target { joints: [11.459156 deg, -20.053523 deg, 25.783101 deg, 5.729578 deg, -11.459156 deg, 17.188734 deg] }
|
||||
target place = joint_target { joints: [-20.053523 deg, -14.323945 deg, 20.053523 deg, -14.323945 deg, 8.594367 deg, -22.918312 deg] }
|
||||
path generated_path {
|
||||
source {
|
||||
type: "cad_curve",
|
||||
id: "edge_032",
|
||||
sample_distance: 5 mm
|
||||
}
|
||||
defaults { speed: vj, zone: z10 }
|
||||
point p_home movej home zone fine
|
||||
event before p_pick io.do[10] = true
|
||||
point p_pick movej pick speed vj
|
||||
event after p_pick wait io.di[10] == true timeout 2 s on_timeout alarm "pick sensor timeout"
|
||||
point p_place movej place speed vj
|
||||
event at p_place distance 10 mm pulse io.do[11] duration 100 ms
|
||||
}
|
||||
proc main()
|
||||
run_path generated_path
|
||||
end
|
||||
end
|
||||
26
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_50_OperationProcess.grl
vendored
Normal file
26
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_50_OperationProcess.grl
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
language grl 0.1
|
||||
module W2OperationProcess
|
||||
const speed v = joint(35 %)
|
||||
const zone zf = fine
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
path op_path {
|
||||
defaults { speed: v, zone: zf }
|
||||
point p0 movej home
|
||||
}
|
||||
operation pick_op {
|
||||
kind: handling
|
||||
path: op_path
|
||||
process {
|
||||
gripper: "main_clamp",
|
||||
dwell_ms: 50 + 50 ms,
|
||||
clamp_force: max(20, 10)
|
||||
}
|
||||
start_action:
|
||||
io.do[1] = true
|
||||
end_action:
|
||||
io.do[1] = false
|
||||
}
|
||||
proc main()
|
||||
run_operation pick_op
|
||||
end
|
||||
end
|
||||
23
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_60_IOWaitPulse.grl
vendored
Normal file
23
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_60_IOWaitPulse.grl
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
language grl 0.1
|
||||
module W2IOWaitPulse
|
||||
const speed v = joint(35 %)
|
||||
const zone zf = fine
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
path io_path {
|
||||
defaults { speed: v, zone: zf }
|
||||
point p0 movej home
|
||||
event at p0 distance 5 + 5 mm pulse io.do[20] duration 50 + 50 ms
|
||||
}
|
||||
proc main()
|
||||
io.do[1] = true
|
||||
io.ao[1] = 0.75
|
||||
io.go[1] = 3
|
||||
wait all(io.di[1] == true, io.di[2] == false) timeout 1 s on_timeout alarm "all timeout"
|
||||
wait any(io.di[3] == true, io.di[4] == true) timeout 1 s
|
||||
wait rising(io.di[5]) timeout 1 s
|
||||
wait falling(io.di[6]) timeout 1 s
|
||||
wait changed(io.di[7]) timeout 1 s
|
||||
pulse io.do[2] duration 50 + 50 ms
|
||||
run_path io_path
|
||||
end
|
||||
end
|
||||
35
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_70_ControlFlow.grl
vendored
Normal file
35
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_70_ControlFlow.grl
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
language grl 0.1
|
||||
module W2ControlFlow
|
||||
const speed v = joint(30 %)
|
||||
const zone zf = fine
|
||||
var bool ready = true
|
||||
var bool fault = false
|
||||
var int mode = 2
|
||||
var int retry = 0
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
proc main()
|
||||
if ready == true
|
||||
movej home speed v zone zf
|
||||
elseif fault == true
|
||||
alarm FAULT "fault"
|
||||
else
|
||||
alarm NOT_READY "not ready"
|
||||
end
|
||||
while retry < 1
|
||||
retry = 1
|
||||
continue
|
||||
end
|
||||
for i = 1 to 2 step 1
|
||||
movej home speed v zone zf
|
||||
end
|
||||
switch mode
|
||||
case 1
|
||||
alarm MODE1 "mode 1"
|
||||
break
|
||||
case 2
|
||||
movej home speed v zone zf
|
||||
default
|
||||
alarm MODE_OTHER "mode other"
|
||||
end
|
||||
end
|
||||
end
|
||||
26
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_80_ProcFuncCall.grl
vendored
Normal file
26
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_80_ProcFuncCall.grl
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
language grl 0.1
|
||||
module W2ProcFuncCall
|
||||
const speed v = joint(30 %)
|
||||
const zone zf = fine
|
||||
var int global_count = 0
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
proc read_part(out bool ok)
|
||||
ok = true
|
||||
end
|
||||
proc increment_retry(inout int retry)
|
||||
retry = 1
|
||||
end
|
||||
func bool can_run(in int retry, in int max_retry)
|
||||
return retry < max_retry
|
||||
end
|
||||
proc main()
|
||||
var bool ok = false
|
||||
var int retry = 0
|
||||
call read_part(ok)
|
||||
call increment_retry(retry)
|
||||
if retry < 3
|
||||
movej home speed v zone zf
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
25
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_90_ExceptionAlarm.grl
vendored
Normal file
25
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_90_ExceptionAlarm.grl
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
language grl 0.1
|
||||
module W2ExceptionAlarm
|
||||
const speed v = joint(30 %)
|
||||
const zone zf = fine
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
trap recover_trap()
|
||||
raise E_STOP
|
||||
end
|
||||
task background cycle 20 ms
|
||||
alarm TASK_MONITOR "task boundary"
|
||||
end
|
||||
proc main()
|
||||
alarm START "start" severity info
|
||||
try
|
||||
movej home speed v zone zf
|
||||
raise E_PICK_FAILED
|
||||
catch E_PICK_FAILED
|
||||
alarm RECOVER "recovering" severity warning
|
||||
finally
|
||||
alarm CLEANUP "cleanup"
|
||||
end
|
||||
enable interrupt guard
|
||||
disable interrupt guard
|
||||
end
|
||||
end
|
||||
80
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_99_FullSpecExample.grl
vendored
Normal file
80
kdl-wasm/web/tests/fixtures/abb120/spec-programs/runtime/W2_99_FullSpecExample.grl
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
language grl 0.1
|
||||
module W2FullSpecExample
|
||||
persistent tool gripper = tool {
|
||||
tcp: pose(0 mm, 0 mm, 120 mm, 0 deg, 0 deg, 0 deg),
|
||||
mass: 1.5 kg
|
||||
}
|
||||
persistent frame fixture = frame {
|
||||
origin: pose(800 mm, 0 mm, 200 mm, 0 deg, 0 deg, 0 deg)
|
||||
}
|
||||
const speed v_fast = joint(55 %)
|
||||
const speed v_pick = linear(180 mm/s)
|
||||
const zone z_pick = z(10 mm)
|
||||
target home = joint_target {
|
||||
joints: [0 deg, -20 deg, 40 deg, 0 deg, 30 deg, 0 deg]
|
||||
}
|
||||
target pick = pose_target {
|
||||
pose: pose(500 mm, 120 mm, 300 mm, 180 deg, 0 deg, 90 deg),
|
||||
config: robot_config(0, 0, 1),
|
||||
tool: gripper,
|
||||
frame: fixture
|
||||
}
|
||||
target place = pose_target {
|
||||
pose: pose(650 mm, -100 mm, 320 mm, 180 deg, 0 deg, 90 deg),
|
||||
config: robot_config(0, 0, 1),
|
||||
tool: gripper,
|
||||
frame: fixture
|
||||
}
|
||||
path pick_path {
|
||||
source {
|
||||
type: "generated_example",
|
||||
id: "pick_path"
|
||||
}
|
||||
defaults {
|
||||
tool: gripper,
|
||||
frame: fixture,
|
||||
speed: v_pick,
|
||||
zone: z_pick
|
||||
}
|
||||
point approach movej home speed v_fast zone fine
|
||||
point above_pick movel pick offset z 100 mm
|
||||
point at_pick movel pick zone fine
|
||||
event after at_pick io.do[1] = true
|
||||
event after at_pick wait io.di[1] == true timeout 2 s on_timeout alarm "Clamp close timeout"
|
||||
point leave_pick movel pick offset z 100 mm
|
||||
}
|
||||
path place_path {
|
||||
defaults {
|
||||
tool: gripper,
|
||||
frame: fixture,
|
||||
speed: v_pick,
|
||||
zone: z_pick
|
||||
}
|
||||
point above_place movel place offset z 100 mm
|
||||
point at_place movel place zone fine
|
||||
event after at_place io.do[1] = false
|
||||
event after at_place wait io.di[2] == true timeout 2 s on_timeout alarm "Clamp open timeout"
|
||||
point leave_place movel place offset z 100 mm
|
||||
}
|
||||
operation pick_op {
|
||||
kind: handling
|
||||
path: pick_path
|
||||
process {
|
||||
gripper: "main_clamp"
|
||||
}
|
||||
}
|
||||
operation place_op {
|
||||
kind: handling
|
||||
path: place_path
|
||||
process {
|
||||
gripper: "main_clamp"
|
||||
}
|
||||
}
|
||||
proc main()
|
||||
set_tool gripper
|
||||
set_frame fixture
|
||||
run_operation pick_op
|
||||
run_operation place_op
|
||||
movej home speed v_fast zone fine
|
||||
end
|
||||
end
|
||||
14
kdl-wasm/web/tests/fixtures/abb120/spec-programs/static/W2_E10_ExpressionDiagnostics.grl
vendored
Normal file
14
kdl-wasm/web/tests/fixtures/abb120/spec-programs/static/W2_E10_ExpressionDiagnostics.grl
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
language grl 0.1
|
||||
module W2ExpressionDiagnostics
|
||||
const speed v_ok = linear(100 mm/s)
|
||||
const speed v_unknown_symbol = linear(missing_symbol mm/s)
|
||||
const speed v_unknown_function = linear(no_such_function(1) mm/s)
|
||||
const speed v_bad_arity = linear(atan2(1) mm/s)
|
||||
const speed v_domain = linear(sqrt(-1) mm/s)
|
||||
const speed v_div_zero = linear(100 mm/s / 0)
|
||||
const zone z_unit = z(10 mm + 1 s)
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
proc main()
|
||||
movej home speed v_ok zone fine
|
||||
end
|
||||
end
|
||||
19
kdl-wasm/web/tests/fixtures/abb120/spec-programs/static/W2_E20_SemanticDiagnostics.grl
vendored
Normal file
19
kdl-wasm/web/tests/fixtures/abb120/spec-programs/static/W2_E20_SemanticDiagnostics.grl
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
language grl 0.1
|
||||
module W2SemanticDiagnostics
|
||||
const speed v = joint(30 %)
|
||||
const speed v = joint(40 %)
|
||||
const zone zf = fine
|
||||
target home = joint_target { joints: [0 deg, 0 deg, 0 deg, 0 deg, 0 deg, 0 deg] }
|
||||
proc set_done(out bool done)
|
||||
done = true
|
||||
end
|
||||
func bool bad_func()
|
||||
wait io.di[1] == true
|
||||
return true
|
||||
end
|
||||
proc main()
|
||||
call set_done(true)
|
||||
call missing_proc()
|
||||
movej missing_target speed v zone zf
|
||||
end
|
||||
end
|
||||
21
kdl-wasm/web/tests/fixtures/abb120/spec-programs/static/W2_E40_ControlFlowDiagnostics.grl
vendored
Normal file
21
kdl-wasm/web/tests/fixtures/abb120/spec-programs/static/W2_E40_ControlFlowDiagnostics.grl
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
language grl 0.1
|
||||
module W2ControlFlowDiagnostics
|
||||
var int mode = 1
|
||||
proc main()
|
||||
break
|
||||
continue
|
||||
jump inner
|
||||
if mode == 1
|
||||
label inner
|
||||
end
|
||||
switch mode
|
||||
case 1
|
||||
break
|
||||
case 1
|
||||
break
|
||||
case mode + 1
|
||||
break
|
||||
end
|
||||
jump missing
|
||||
end
|
||||
end
|
||||
132
kdl-wasm/web/tests/integration/abb120SpecSuite.test.ts
Normal file
132
kdl-wasm/web/tests/integration/abb120SpecSuite.test.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
runAbb120SpecSuite,
|
||||
type Abb120SpecManifest,
|
||||
type Abb120SpecProgramSource
|
||||
} from "../../src/suites/abb120SpecSuite.js";
|
||||
|
||||
const WEB_ROOT = join(dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const SPEC_ROOT = join(WEB_ROOT, "tests", "fixtures", "abb120", "spec-programs");
|
||||
|
||||
function loadManifest(): Abb120SpecManifest {
|
||||
return JSON.parse(readFileSync(join(SPEC_ROOT, "manifest.json"), "utf8")) as Abb120SpecManifest;
|
||||
}
|
||||
|
||||
function loadPrograms(manifest = loadManifest()): Abb120SpecProgramSource[] {
|
||||
return manifest.programs.map((entry) => ({
|
||||
program_id: entry.program_id,
|
||||
file: entry.file,
|
||||
text: readFileSync(join(SPEC_ROOT, entry.file), "utf8")
|
||||
}));
|
||||
}
|
||||
|
||||
describe("working2 ABB120 GRL spec suite", () => {
|
||||
it("maps grammar sections 4 through 25 to concrete Runtime, Static, or Post programs", () => {
|
||||
const manifest = loadManifest();
|
||||
const sections = manifest.coverage_matrix.map((item) => item.spec_section);
|
||||
expect(sections).toEqual(Array.from({ length: 22 }, (_value, index) => index + 4));
|
||||
expect(manifest.programs).toHaveLength(19);
|
||||
expect(manifest.programs.filter((program) => program.coverage_level === "Runtime")).toHaveLength(12);
|
||||
expect(manifest.programs.filter((program) => program.coverage_level === "Static")).toHaveLength(4);
|
||||
expect(manifest.programs.filter((program) => program.coverage_level === "Post")).toHaveLength(3);
|
||||
|
||||
const programById = new Map(manifest.programs.map((program) => [program.program_id, program]));
|
||||
for (const item of manifest.coverage_matrix) {
|
||||
expect(item.program_ids.length).toBeGreaterThan(0);
|
||||
for (const programId of item.program_ids) {
|
||||
const program = programById.get(programId);
|
||||
expect(program, `${item.spec_section} references missing ${programId}`).toBeDefined();
|
||||
expect(
|
||||
item.coverage_level.split("/"),
|
||||
`${item.spec_section} coverage level must include ${programId}`
|
||||
).toContain(program!.coverage_level);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("builds a W2 job with compile, controller, queue, trace, IO, post, and roundtrip evidence", () => {
|
||||
const manifest = loadManifest();
|
||||
const job = runAbb120SpecSuite(manifest, loadPrograms(manifest), {
|
||||
now: "2026-06-28T01:30:00.000Z",
|
||||
gitRevision: "test-revision"
|
||||
});
|
||||
|
||||
expect(job.job_id).toMatch(/^W2-JOB-20260628013000-[a-f0-9]{8}$/);
|
||||
expect(job.suite_id).toBe("working2-abb120-spec");
|
||||
expect(job.robot_id).toBe("abb_irb120_3_58");
|
||||
expect(job.coverage.missingSections).toEqual([]);
|
||||
expect(job.programs.map((program) => program.program_id)).toEqual(manifest.programs.map((program) => program.program_id));
|
||||
|
||||
const runtime = job.programs.filter((program) => program.coverage_level === "Runtime");
|
||||
expect(runtime.every((program) => program.compile.parsed)).toBe(true);
|
||||
expect(runtime.every((program) => program.compile.sourceMapEntries > 0)).toBe(true);
|
||||
expect(runtime.every((program) => program.controller?.commands.map((command) => command.command).includes("loadProgram"))).toBe(true);
|
||||
expect(runtime.every((program) => program.controller?.commands.map((command) => command.command).includes("resetFault"))).toBe(true);
|
||||
expect(runtime.some((program) => program.program_id === "W2_60_IOWaitPulse" && Object.keys(program.io?.image ?? {}).length > 0)).toBe(true);
|
||||
expect(runtime.some((program) => (program.trace ?? []).some((event) => event.kind === "wait"))).toBe(true);
|
||||
expect(runtime.some((program) => (program.motionQueue?.items.length ?? 0) > 0)).toBe(true);
|
||||
expect(runtime.some((program) =>
|
||||
program.program_id === "W2_99_FullSpecExample" &&
|
||||
program.compile.pathCount === 2 &&
|
||||
program.compile.operationCount === 2 &&
|
||||
(program.motionQueue?.items.some((item) => item.source.kind === "path" && item.source.operationId === "pick_op") ?? false)
|
||||
)).toBe(true);
|
||||
expect(runtime.every((program) => (program.trajectory?.sampleCount ?? 0) >= 0)).toBe(true);
|
||||
expect(runtime.some((program) =>
|
||||
(program.trajectory?.frames ?? []).some((frame) =>
|
||||
frame.joints.length === 6 &&
|
||||
frame.tcp.position.length === 3 &&
|
||||
frame.tcp.quaternion.length === 4
|
||||
)
|
||||
)).toBe(true);
|
||||
|
||||
for (const program of job.programs) {
|
||||
const expected = manifest.programs.find((entry) => entry.program_id === program.program_id)!;
|
||||
expect(program.status, program.program_id).toBe(expected.expected_status);
|
||||
const codes = program.diagnostics.map((diagnostic) => diagnostic.code);
|
||||
for (const code of expected.expected_diagnostics) {
|
||||
expect(codes, program.program_id).toContain(code);
|
||||
}
|
||||
expect(codes, program.program_id).not.toContain("W2_EXPECTED_DIAGNOSTIC_MISSING");
|
||||
expect(codes, program.program_id).not.toContain("W2_EXPECTED_STATUS_MISMATCH");
|
||||
}
|
||||
|
||||
const diagnostics = Object.fromEntries(job.programs.map((program) => [
|
||||
program.program_id,
|
||||
program.diagnostics.map((diagnostic) => diagnostic.code)
|
||||
]));
|
||||
expect(diagnostics.W2_E10_ExpressionDiagnostics).toEqual(expect.arrayContaining([
|
||||
"GRL_EXPR_UNKNOWN_SYMBOL",
|
||||
"GRL_EXPR_UNKNOWN_FUNCTION",
|
||||
"GRL_EXPR_ARITY",
|
||||
"GRL_EXPR_DOMAIN",
|
||||
"GRL_EXPR_DIV_ZERO",
|
||||
"GRL_EXPR_UNIT_MISMATCH"
|
||||
]));
|
||||
expect(diagnostics.W2_E20_SemanticDiagnostics).toEqual(expect.arrayContaining([
|
||||
"GRL_SYMBOL_DUPLICATE",
|
||||
"GRL_ARGUMENT_NOT_LVALUE"
|
||||
]));
|
||||
expect(diagnostics.W2_E30_MotionDiagnostics).toEqual(expect.arrayContaining([
|
||||
"GRL_PATH_EMPTY",
|
||||
"KDL_JOINT_LIMIT",
|
||||
"KDL_TARGET_UNREACHABLE"
|
||||
]));
|
||||
expect(diagnostics.W2_E40_ControlFlowDiagnostics).toEqual(expect.arrayContaining([
|
||||
"GRL_BREAK_OUTSIDE_FLOW"
|
||||
]));
|
||||
expect(diagnostics.W2_E50_RuntimeTimeout).toEqual(expect.arrayContaining([
|
||||
"VC_WAIT_TIMEOUT"
|
||||
]));
|
||||
|
||||
const post = job.programs.filter((program) => program.coverage_level === "Post");
|
||||
expect(post.every((program) => program.post?.filenames.some((filename) => filename.endsWith(".mod")))).toBe(true);
|
||||
expect(post.every((program) => program.post?.filenames.some((filename) => filename.endsWith(".ls")))).toBe(true);
|
||||
expect(post.every((program) => program.post?.filenames.some((filename) => filename.endsWith(".src")))).toBe(true);
|
||||
expect(post.every((program) => program.roundtrip?.status.match(/pass|warn/))).toBe(true);
|
||||
expect(job.artifacts.jobJson).toContain(job.job_id);
|
||||
});
|
||||
});
|
||||
@@ -69,6 +69,8 @@ describe("ABB120 suite artifacts", () => {
|
||||
|
||||
expect(html).toContain("ABB120 Station");
|
||||
expect(html).toContain("Path: pick_place");
|
||||
expect(html).toContain("W2-JOB-latest");
|
||||
expect(html).toContain("working2-abb120-spec");
|
||||
expect(html).toContain("Controller");
|
||||
expect(html).toContain("Motion Queue");
|
||||
expect(html).toContain("Reports");
|
||||
|
||||
Reference in New Issue
Block a user