WIP
This commit is contained in:
1 parent
1166eb808c
commit
d7049fb8b2
10 files changed
+136
-47
No files matched your search
@@ -0,0 +1,7 @@
|
||||
ioc_name: MTEST04-MTN-HEXAPOD
|
||||
ioc_host: c6025a-08
|
||||
ioc_port: 50001
|
||||
ioc_user: root
|
||||
epics_version: 7.0.10
|
||||
os: deb12
|
||||
cpu_architecture: x86_64
|
||||
@@ -0,0 +1,20 @@
|
||||
# Hexapod cpp_logic simulation IOC example.
|
||||
# Run with the hexapod project as the IOC working directory.
|
||||
# Build first: make logic ECMC_ROOT=<ecmc source> ECMCCFG_ROOT=<ecmccfg source>
|
||||
# build/libhexapod_logic.so
|
||||
# cfg/libhexapod_logic.so_cpp_logic.subs
|
||||
#
|
||||
# Axes 1..6: X, Y, Z, Rx, Ry, Rz (internal coordinate trajectories).
|
||||
# Axes 7..12: L1..L6 (external IK trajectories and ideal leg feedback).
|
||||
# No EtherCAT master or physical hardware is required.
|
||||
# The IOC launcher supplies iocInit; ecmccfg finalizes at that point.
|
||||
#
|
||||
# Useful panels after startup:
|
||||
# caqtdm -macro "IOC=HEXAPOD" ecmcCppLogicOverview.ui
|
||||
# caqtdm -macro "IOC=HEXAPOD,CPP_ID=0" ecmcCppLogic.ui
|
||||
|
||||
epicsEnvSet("IOC", "${IOC=HEXAPD}")
|
||||
require ecmccfg v11.2.0_RC1 "ECMC_VER=v11.2.0_RC1,MASTER_ID=-1,EC_RATE=1000"
|
||||
|
||||
# Load all twelve virtual axes, then the C++ transform and its status PVs.
|
||||
${SCRIPTEXEC} ./cfg/load.cmd
|
||||
@@ -1,43 +1,27 @@
|
||||
CXX ?= c++
|
||||
CXXFLAGS ?= -O2 -std=c++17 -Wall -Wextra -pedantic
|
||||
ECMC_ROOT ?= ../ecmc
|
||||
ECMCCFG_ROOT ?= ../ecmccfg
|
||||
PYTHON ?= python3
|
||||
UNAME := $(shell uname -s)
|
||||
ifeq ($(UNAME),Darwin)
|
||||
SHARED := -dynamiclib
|
||||
EXT := dylib
|
||||
else
|
||||
SHARED := -shared
|
||||
EXT := so
|
||||
include /ioc/tools/sls_ioc.makefile
|
||||
|
||||
# The offline build also creates a build/ directory. Always run the IOC
|
||||
# build recipe so the source Makefile can check its own dependencies.
|
||||
.PHONY: default build clean
|
||||
|
||||
IOC_STARTUP_FILE := $(notdir $(firstword $(wildcard *_startup.script)))
|
||||
IOC_PARAMS_FILE := $(notdir $(firstword $(wildcard *_parameters.yaml)))
|
||||
IOC_NAME ?= $(patsubst %_startup.script,%,$(IOC_STARTUP_FILE))
|
||||
ifeq ($(IOC_NAME),)
|
||||
IOC_NAME := $(patsubst %_parameters.yaml,%,$(IOC_PARAMS_FILE))
|
||||
endif
|
||||
.PHONY: all test logic pvs clean
|
||||
all: build/libhexapod.$(EXT) build/test_kinematics
|
||||
build:
|
||||
mkdir -p build
|
||||
build/libhexapod.$(EXT): src/c_api.cpp src/kinematics.hpp | build
|
||||
$(CXX) $(CXXFLAGS) -fPIC $(SHARED) -o $@ src/c_api.cpp
|
||||
build/test_kinematics: tests/test_kinematics.cpp src/kinematics.hpp | build
|
||||
$(CXX) $(CXXFLAGS) -Isrc -o $@ tests/test_kinematics.cpp
|
||||
test: all
|
||||
./build/test_kinematics
|
||||
$(PYTHON) python/viewer.py --self-test
|
||||
logic: build/libhexapod_logic.$(EXT) pvs
|
||||
build/libhexapod_logic.$(EXT): src/logic.cpp src/kinematics.hpp | build
|
||||
$(CXX) $(CXXFLAGS) -fPIC $(SHARED) -I$(ECMC_ROOT)/devEcmcSup/logic -o $@ src/logic.cpp
|
||||
|
||||
CPP_LOGIC_ROOT ?= $(abspath ../..)
|
||||
PYTHON ?= python3
|
||||
GENERATE_QT ?= 1
|
||||
IOC_QT_PANEL := qt/$(IOC_NAME)_cpp_logic.ui
|
||||
IOC_QTGEN := $(CPP_LOGIC_ROOT)/utils/cpp_logic_ioc_qtgen.py
|
||||
IOC_SUBS_FILE := cfg/libmain.so_cpp_logic.subs
|
||||
|
||||
.PHONY: pvs ui
|
||||
|
||||
pvs:
|
||||
$(PYTHON) $(ECMCCFG_ROOT)/examples/PSI/plugins/cpp_logic/utils/ecmcCppLogicSourceSubstGen.py --source src/logic.cpp --logic-name hexapod --output cfg/libhexapod_logic.so_cpp_logic.subs
|
||||
clean:
|
||||
rm -rf build
|
||||
$(MAKE) -C src stage
|
||||
|
||||
.PHONY: test-logic
|
||||
test-logic: build/test_logic
|
||||
./build/test_logic
|
||||
build/test_logic: tests/test_logic.cpp src/logic.cpp src/kinematics.hpp | build
|
||||
$(CXX) $(CXXFLAGS) -I$(ECMC_ROOT)/devEcmcSup/logic -o $@ tests/test_logic.cpp
|
||||
|
||||
.PHONY: bench
|
||||
bench: build/kinematics_bench
|
||||
./build/kinematics_bench
|
||||
build/kinematics_bench: bench/kinematics_bench.cpp src/kinematics.hpp | build
|
||||
$(CXX) $(CXXFLAGS) -Isrc -o $@ bench/kinematics_bench.cpp
|
||||
ui: pvs
|
||||
if [ "$(GENERATE_QT)" = "1" ]; then $(PYTHON) $(IOC_QTGEN) --input $(IOC_SUBS_FILE) --output $(IOC_QT_PANEL) --pv-prefix "$(IOC_NAME):" --title "$(IOC_NAME) cpp_logic PVs"; fi
|
||||
@@ -303,7 +303,17 @@ This produces `build/libhexapod_logic.so` and the generated EPICS substitutions.
|
||||
On macOS the build produces `.dylib` files for development tests; these cannot be
|
||||
loaded in a Linux IOC.
|
||||
|
||||
From an existing ecmccfg IOC startup, with this project as its working directory,
|
||||
`HEXAPD_startup.script` is the simulation IOC startup, following the ecmccfg
|
||||
`cpp_logic_motion` example. It requires `ecmccfg strucpp` with `ECMC_VER=strucpp`,
|
||||
selects a 1 kHz cycle without an EtherCAT master, and loads all twelve virtual
|
||||
axes and the C++ logic through `cfg/load.cmd`. Build the library first using
|
||||
headers matching that ecmc installation, then run `HEXAPD_startup.script` with your
|
||||
normal PSI IOC launcher and this project as its working directory. The launcher
|
||||
supplies `iocInit`; ecmccfg finalizes the configuration and enters runtime during
|
||||
initialization. The default IOC name is `HEXAPD` unless the launcher sets `IOC`.
|
||||
Axes remain disabled at startup and motor records are not loaded.
|
||||
|
||||
To integrate into an existing ecmccfg IOC startup, with this project as its working directory,
|
||||
include the following **after ecmccfg initialization and before runtime startup**:
|
||||
|
||||
```text
|
||||
@@ -346,7 +356,7 @@ prefix, including the trailing colon:
|
||||
|
||||
```sh
|
||||
.venv/bin/pip install -r python/requirements-ioc.txt
|
||||
.venv/bin/python python/viewer.py --prefix HEX:
|
||||
.venv/bin/python python/viewer.py --prefix HEXAPD:
|
||||
```
|
||||
|
||||
Use the prefix configured by `loadCppLogic.cmd` (`DB_PREFIX`, default `${IOC}:`).
|
||||
|
||||
@@ -20,7 +20,7 @@ encoder:
|
||||
numerator: 1
|
||||
denominator: 1
|
||||
bits: 32
|
||||
position: ec0.s-1.ONE
|
||||
# External feedback is supplied by C++ FK; no EtherCAT position link.
|
||||
|
||||
trajectory:
|
||||
source: 0
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ encoder:
|
||||
numerator: 1
|
||||
denominator: 1
|
||||
bits: 32
|
||||
position: ec0.s-1.ONE
|
||||
# External feedback is supplied by the C++ ideal plant; no EtherCAT position link.
|
||||
|
||||
trajectory:
|
||||
source: 1
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@
|
||||
# cfg/axes.cmd loads the two shared axis YAML templates via loadYamlAxis.cmd.
|
||||
# Axis IDs 1..12 must be free. No physical EtherCAT hardware is linked.
|
||||
${SCRIPTEXEC} ./cfg/axes.cmd
|
||||
${SCRIPTEXEC} ${ecmccfg_DIR}loadCppLogic.cmd, "DIR=./build/,FILE=libhexapod_logic.so,ASYN_PORT=HEX,REPORT=1,MACROS='COORD_FIRST=1,LEG_FIRST=7,SIMULATION=1'"
|
||||
${SCRIPTEXEC} ${ecmccfg_DIR}loadCppLogic.cmd, "ASYN_PORT=HEX,REPORT=1,MACROS='COORD_FIRST=1,LEG_FIRST=7,SIMULATION=1'"
|
||||
@@ -0,0 +1,43 @@
|
||||
CXX ?= c++
|
||||
CXXFLAGS ?= -O2 -std=c++17 -Wall -Wextra -pedantic
|
||||
ECMC_ROOT ?= ../ecmc
|
||||
ECMCCFG_ROOT ?= ../ecmccfg
|
||||
PYTHON ?= python3
|
||||
UNAME := $(shell uname -s)
|
||||
ifeq ($(UNAME),Darwin)
|
||||
SHARED := -dynamiclib
|
||||
EXT := dylib
|
||||
else
|
||||
SHARED := -shared
|
||||
EXT := so
|
||||
endif
|
||||
.PHONY: all test logic pvs clean
|
||||
all: build/libhexapod.$(EXT) build/test_kinematics
|
||||
build:
|
||||
mkdir -p build
|
||||
build/libhexapod.$(EXT): src/c_api.cpp src/kinematics.hpp | build
|
||||
$(CXX) $(CXXFLAGS) -fPIC $(SHARED) -o $@ src/c_api.cpp
|
||||
build/test_kinematics: tests/test_kinematics.cpp src/kinematics.hpp | build
|
||||
$(CXX) $(CXXFLAGS) -Isrc -o $@ tests/test_kinematics.cpp
|
||||
test: all
|
||||
./build/test_kinematics
|
||||
$(PYTHON) python/viewer.py --self-test
|
||||
logic: build/libhexapod_logic.$(EXT) pvs
|
||||
build/libhexapod_logic.$(EXT): src/logic.cpp src/kinematics.hpp | build
|
||||
$(CXX) $(CXXFLAGS) -fPIC $(SHARED) -I$(ECMC_ROOT)/devEcmcSup/logic -o $@ src/logic.cpp
|
||||
pvs:
|
||||
$(PYTHON) $(ECMCCFG_ROOT)/examples/PSI/plugins/cpp_logic/utils/ecmcCppLogicSourceSubstGen.py --source src/logic.cpp --logic-name hexapod --output cfg/libhexapod_logic.so_cpp_logic.subs
|
||||
clean:
|
||||
rm -rf build
|
||||
|
||||
.PHONY: test-logic
|
||||
test-logic: build/test_logic
|
||||
./build/test_logic
|
||||
build/test_logic: tests/test_logic.cpp src/logic.cpp src/kinematics.hpp | build
|
||||
$(CXX) $(CXXFLAGS) -I$(ECMC_ROOT)/devEcmcSup/logic -o $@ tests/test_logic.cpp
|
||||
|
||||
.PHONY: bench
|
||||
bench: build/kinematics_bench
|
||||
./build/kinematics_bench
|
||||
build/kinematics_bench: bench/kinematics_bench.cpp src/kinematics.hpp | build
|
||||
$(CXX) $(CXXFLAGS) -Isrc -o $@ bench/kinematics_bench.cpp
|
||||
@@ -0,0 +1,24 @@
|
||||
include /ioc/tools/driver.makefile
|
||||
MODULE = main
|
||||
BUILDCLASSES = Linux
|
||||
ARCH_FILTER = deb10% deb12%
|
||||
EXCLUDE_VERSIONS+=3 7.0.5 7.0.6 7.0.7
|
||||
USR_CXXFLAGS += -std=c++17
|
||||
ecmc_VERSION = v11.2.0_RC1
|
||||
DIRS+=.
|
||||
SOURCES += $(foreach d,${DIRS}, $(wildcard $d/*.c) $(wildcard $d/*.cpp))
|
||||
HEADERS += $(foreach d,${DIRS}, $(wildcard $d/*.h))
|
||||
HEADERS += $(foreach d,${DIRS}, $(wildcard $d/*.hpp))
|
||||
|
||||
CPP_LOGIC_ROOT ?= $(abspath ../../..)
|
||||
PYTHON ?= python3.9
|
||||
SUBSGEN := $(CPP_LOGIC_ROOT)/utils/ecmcCppLogicSourceSubstGen.py
|
||||
STAGE_SUBS ?= ../cfg/lib$(MODULE).so_cpp_logic.subs
|
||||
STAGE_DIR := $(dir $(STAGE_SUBS))
|
||||
LOCAL_MODULE := $(notdir $(abspath ..))
|
||||
|
||||
.PHONY: stage
|
||||
|
||||
stage:
|
||||
mkdir -p $(STAGE_DIR); \
|
||||
$(PYTHON) $(SUBSGEN) --source main.cpp --logic-name "$(LOCAL_MODULE)" --output $(STAGE_SUBS)
|
||||
+3
-2
@@ -37,8 +37,9 @@ struct HexapodLogic : ecmcCpp::LogicBase {
|
||||
model=hexapod::Model(g); geometry_home=model.inverse({});
|
||||
if(!model.withinStroke(geometry_home)) throw std::runtime_error("Home is outside leg stroke");
|
||||
for(int i=0;i<6;++i) {
|
||||
ecmc.input("ax"+std::to_string(coordFirst+i)+".traj.setpos",pose_set[i]);
|
||||
ecmc.input("ax"+std::to_string(legFirst+i)+".enc.actpos",leg_actual[i]);
|
||||
// C++ item bindings use asyn names, rather than PLC object paths.
|
||||
ecmc.input("ax"+std::to_string(coordFirst+i)+".setpos",pose_set[i]);
|
||||
ecmc.input("ax"+std::to_string(legFirst+i)+".actpos",leg_actual[i]);
|
||||
}
|
||||
epics.readOnlyArray("hex.pose_set",pose_set)
|
||||
.readOnlyArray("hex.pose_actual",pose_actual)
|
||||
|
||||
Reference in new issue
Block a user