fixed axis 4 warning
This commit is contained in:
@@ -0,0 +1,112 @@
|
|||||||
|
|
||||||
|
'*******************************************************ECAT总线初始化
|
||||||
|
'''''''''
|
||||||
|
|
||||||
|
global CONST BUS_TYPE = 0 '总线类型。用于上位机区分当前模式
|
||||||
|
global CONST MAX_AXISNUM = 32 '最大轴数
|
||||||
|
global CONST Bus_Slot = 0 '槽位号0
|
||||||
|
global CONST Bus_AxisStart = 0 '总线轴起始轴号
|
||||||
|
|
||||||
|
global Bus_InitStatus '总线初始化完成状态
|
||||||
|
Bus_InitStatus = -1
|
||||||
|
global Bus_TotalAxisnum '检查扫描的总轴数
|
||||||
|
|
||||||
|
delay(3000) '延时3S等待驱动器上电
|
||||||
|
'**********************初始化ECAT总线
|
||||||
|
Ecat_Init()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
global sub Ecat_Init()
|
||||||
|
for i=0 to MAX_AXISNUM - 1 '初始化还原轴类型
|
||||||
|
AXIS_ENABLE(i) = 0
|
||||||
|
atype(i)=0
|
||||||
|
next
|
||||||
|
|
||||||
|
Bus_InitStatus = -1
|
||||||
|
Bus_TotalAxisnum = 0
|
||||||
|
SLOT_STOP(Bus_Slot)
|
||||||
|
delay(200)
|
||||||
|
slot_scan(Bus_Slot) '开始扫描
|
||||||
|
if return then
|
||||||
|
|
||||||
|
?"总线扫描成功","连接设备数:"NODE_COUNT(Bus_Slot)
|
||||||
|
?
|
||||||
|
?"开始映射轴号"
|
||||||
|
for i=0 to NODE_COUNT(Bus_Slot)-1 '遍历总线下所有从站节点
|
||||||
|
|
||||||
|
if NODE_AXIS_COUNT(Bus_Slot,i) <>0 then '判断当前节点是否有电机
|
||||||
|
for j=0 to NODE_AXIS_COUNT(Bus_Slot,i)-1
|
||||||
|
AXIS_ADDRESS(Bus_AxisStart+i)=Bus_TotalAxisnum+1 '映射轴号
|
||||||
|
ATYPE(Bus_AxisStart+i)=65 '设置控制模式 65-位置 66-速度 67-转矩
|
||||||
|
DRIVE_PROFILE(Bus_AxisStart+i)= 4 '设置PROFILE功能
|
||||||
|
disable_group(Bus_AxisStart+i) '每轴单独分组
|
||||||
|
|
||||||
|
DRIVE_IO(Bus_AxisStart+i) = 128 + (Bus_AxisStart+i)*16 '映射驱动器上的IO状态
|
||||||
|
REV_IN(Bus_AxisStart+i) = 128 + (Bus_AxisStart+i)*16
|
||||||
|
FWD_IN(Bus_AxisStart+i) = 129 + (Bus_AxisStart+i)*16
|
||||||
|
DATUM_IN(Bus_AxisStart+i) = 130 + (Bus_AxisStart+i)*16
|
||||||
|
INVERT_IN(128 + (Bus_AxisStart+i)*16,ON)
|
||||||
|
INVERT_IN(129 + (Bus_AxisStart+i)*16,ON)
|
||||||
|
INVERT_IN(130 + (Bus_AxisStart+i)*16,ON)
|
||||||
|
|
||||||
|
Bus_TotalAxisnum=Bus_TotalAxisnum+1 '总轴数+1
|
||||||
|
next
|
||||||
|
endif
|
||||||
|
|
||||||
|
next
|
||||||
|
|
||||||
|
|
||||||
|
' Axis 4 is a Panasonic MINAS A6 servo, not a Leadshine CL3B stepper:
|
||||||
|
' its limit/datum inputs are active-high as the ZMC reads them, so they
|
||||||
|
' must NOT be inverted like the steppers above. Override the loop for
|
||||||
|
' that one axis only: Bus_TotalAxisnum-1 is the last axis the scan found,
|
||||||
|
' which on this machine is the servo and never a stepper.
|
||||||
|
INVERT_IN(128 + (Bus_AxisStart + Bus_TotalAxisnum - 1)*16,OFF)
|
||||||
|
INVERT_IN(129 + (Bus_AxisStart + Bus_TotalAxisnum - 1)*16,OFF)
|
||||||
|
INVERT_IN(130 + (Bus_AxisStart + Bus_TotalAxisnum - 1)*16,OFF)
|
||||||
|
?"轴号映射完成","连接总轴数:"Bus_TotalAxisnum
|
||||||
|
wa 2000
|
||||||
|
|
||||||
|
SLOT_START(Bus_Slot) '启动总线
|
||||||
|
if return then
|
||||||
|
?"总线开启成功"
|
||||||
|
|
||||||
|
?"开始清除驱动器错误(根据驱动器数据字典设置)"
|
||||||
|
for i= Bus_AxisStart to Bus_AxisStart + Bus_TotalAxisnum - 1
|
||||||
|
|
||||||
|
DRIVE_CONTROLWORD(i)=128 '根据驱动器数据字典
|
||||||
|
wa 100
|
||||||
|
DRIVE_CONTROLWORD(i)=6
|
||||||
|
wa 100
|
||||||
|
DRIVE_CONTROLWORD(i)=15
|
||||||
|
wa 100
|
||||||
|
next
|
||||||
|
|
||||||
|
?"驱动器错误清除完成"
|
||||||
|
wa 100
|
||||||
|
|
||||||
|
?"清除控制器错误"
|
||||||
|
datum(0)
|
||||||
|
DRIVE_CLEAR(0)
|
||||||
|
?"控制器错误清除完成"
|
||||||
|
wa 100
|
||||||
|
|
||||||
|
?"轴使能准备"
|
||||||
|
for i= Bus_AxisStart to Bus_AxisStart + Bus_TotalAxisnum - 1
|
||||||
|
base(i)
|
||||||
|
AXIS_ENABLE=1
|
||||||
|
next
|
||||||
|
wdog=1 '使能总开关
|
||||||
|
Bus_InitStatus = 1
|
||||||
|
?"轴使能完成"
|
||||||
|
else
|
||||||
|
?"总线开启失败"
|
||||||
|
Bus_InitStatus = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
else
|
||||||
|
?"总线扫描失败"
|
||||||
|
Bus_InitStatus = 0
|
||||||
|
endif
|
||||||
|
end sub
|
||||||
@@ -103,6 +103,8 @@
|
|||||||
"state_pending": "Not started",
|
"state_pending": "Not started",
|
||||||
"state_running": "Initialising…",
|
"state_running": "Initialising…",
|
||||||
"state_ok": "Initialised",
|
"state_ok": "Initialised",
|
||||||
|
"state_unverified": "Init not confirmed",
|
||||||
|
"unverified_hint": "The controller still holds the initialisation flag from its last run; this power-up has not re-scanned the bus. If the platform will not move, download the BAS file and re-initialise.",
|
||||||
"state_failed": "Initialisation failed",
|
"state_failed": "Initialisation failed",
|
||||||
"state_timeout": "Initialisation timed out",
|
"state_timeout": "Initialisation timed out",
|
||||||
"nodes": "Nodes",
|
"nodes": "Nodes",
|
||||||
|
|||||||
@@ -103,6 +103,8 @@
|
|||||||
"state_pending": "未完成",
|
"state_pending": "未完成",
|
||||||
"state_running": "正在初始化…",
|
"state_running": "正在初始化…",
|
||||||
"state_ok": "初始化成功",
|
"state_ok": "初始化成功",
|
||||||
|
"state_unverified": "未确认初始化",
|
||||||
|
"unverified_hint": "控制器保留了上次的总线初始化标志,本次开机尚未重新扫描;如无法运动,请先下载 BAS 文件并重新初始化。",
|
||||||
"state_failed": "初始化失败",
|
"state_failed": "初始化失败",
|
||||||
"state_timeout": "初始化超时",
|
"state_timeout": "初始化超时",
|
||||||
"nodes": "节点数量",
|
"nodes": "节点数量",
|
||||||
|
|||||||
@@ -111,7 +111,16 @@ class AxisState:
|
|||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class BusStatus:
|
class BusStatus:
|
||||||
"""Bus-level state, from the ``.bas`` program's globals."""
|
"""Bus-level state, from the ``.bas`` program's globals.
|
||||||
|
|
||||||
|
``verified_this_session`` exists because ``BUS_TYPE``, ``Bus_InitStatus``
|
||||||
|
and ``Bus_TotalAxisnum`` are ZBasic **globals**: they live in controller
|
||||||
|
memory and survive the program finishing, a reconnect, and (with the ROM
|
||||||
|
program reloading) a reboot. ``Bus_InitStatus == 1`` therefore means "a scan
|
||||||
|
completed at some point", not "this bus is live now". A controller that was
|
||||||
|
power-cycled but not re-initialised still reports 1, and reporting that as
|
||||||
|
初始化成功 is what made a bus which had never been set up look ready.
|
||||||
|
"""
|
||||||
|
|
||||||
bus_type: BusType = "unknown"
|
bus_type: BusType = "unknown"
|
||||||
init_status: int = INIT_RUNNING
|
init_status: int = INIT_RUNNING
|
||||||
@@ -121,6 +130,14 @@ class BusStatus:
|
|||||||
bas_loaded: bool = False
|
bas_loaded: bool = False
|
||||||
init_started_at: float | None = None
|
init_started_at: float | None = None
|
||||||
message: str = ""
|
message: str = ""
|
||||||
|
#: False until this session has seen the state machine through a run it
|
||||||
|
#: started (a download or a re-init). An adopted latch starts False.
|
||||||
|
verified_this_session: bool = False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def adopted_unverified(self) -> bool:
|
||||||
|
"""The latch says initialised, but nothing here has confirmed it."""
|
||||||
|
return self.init_status == INIT_OK and not self.verified_this_session
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def initialized(self) -> bool:
|
def initialized(self) -> bool:
|
||||||
|
|||||||
@@ -401,7 +401,9 @@ class MotionService:
|
|||||||
self._spec = spec
|
self._spec = spec
|
||||||
logger.info("Connected: %s via %s", spec.describe(), self._transport.source)
|
logger.info("Connected: %s via %s", spec.describe(), self._transport.source)
|
||||||
# A controller may already have a BAS program running from a previous
|
# A controller may already have a BAS program running from a previous
|
||||||
# session; adopt it rather than claiming the bus is uninitialised.
|
# session; adopt it rather than claiming the bus is uninitialised. The
|
||||||
|
# adopted state is *not* marked verified: its globals are a latch, and
|
||||||
|
# nothing in this session has yet seen a scan happen.
|
||||||
self._adopt_existing_bas(bas_path=bas_path)
|
self._adopt_existing_bas(bas_path=bas_path)
|
||||||
return MotionResult.success(f"已连接 {spec.describe()}" if self._is_zh else f"Connected {spec.describe()}")
|
return MotionResult.success(f"已连接 {spec.describe()}" if self._is_zh else f"Connected {spec.describe()}")
|
||||||
|
|
||||||
@@ -469,12 +471,14 @@ class MotionService:
|
|||||||
|
|
||||||
self._bas_loaded = True
|
self._bas_loaded = True
|
||||||
self._init_started_at = time.monotonic()
|
self._init_started_at = time.monotonic()
|
||||||
|
# A download is a run this session owns, so its outcome can be trusted.
|
||||||
self._bus = BusStatus(
|
self._bus = BusStatus(
|
||||||
bus_type=self._bus.bus_type,
|
bus_type=self._bus.bus_type,
|
||||||
init_status=INIT_RUNNING,
|
init_status=INIT_RUNNING,
|
||||||
bas_path=filename,
|
bas_path=filename,
|
||||||
bas_loaded=True,
|
bas_loaded=True,
|
||||||
init_started_at=self._init_started_at,
|
init_started_at=self._init_started_at,
|
||||||
|
verified_this_session=True,
|
||||||
)
|
)
|
||||||
# Read BUS_TYPE so the SDO/RTEX panels enable for the right family.
|
# Read BUS_TYPE so the SDO/RTEX panels enable for the right family.
|
||||||
try:
|
try:
|
||||||
@@ -541,6 +545,7 @@ class MotionService:
|
|||||||
bas_path=self._bus.bas_path,
|
bas_path=self._bus.bas_path,
|
||||||
bas_loaded=True,
|
bas_loaded=True,
|
||||||
init_started_at=self._init_started_at,
|
init_started_at=self._init_started_at,
|
||||||
|
verified_this_session=True,
|
||||||
)
|
)
|
||||||
# Re-read BUS_TYPE now: the program may be a different family than the
|
# Re-read BUS_TYPE now: the program may be a different family than the
|
||||||
# one the previous session left behind.
|
# one the previous session left behind.
|
||||||
@@ -662,7 +667,13 @@ class MotionService:
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
verified = bus.verified_this_session
|
||||||
if init_status != INIT_RUNNING:
|
if init_status != INIT_RUNNING:
|
||||||
|
# A run this session owned has just settled: that is the only
|
||||||
|
# evidence available that the state machine actually moved, rather
|
||||||
|
# than the globals having been left at their last values.
|
||||||
|
if self._init_started_at is not None:
|
||||||
|
verified = True
|
||||||
self._init_started_at = None
|
self._init_started_at = None
|
||||||
try:
|
try:
|
||||||
node_count = self._transport.bus_node_count(0)
|
node_count = self._transport.bus_node_count(0)
|
||||||
@@ -679,6 +690,7 @@ class MotionService:
|
|||||||
bas_loaded=True,
|
bas_loaded=True,
|
||||||
init_started_at=self._init_started_at,
|
init_started_at=self._init_started_at,
|
||||||
message=message,
|
message=message,
|
||||||
|
verified_this_session=verified,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _read_axis(self, axis: int) -> AxisState:
|
def _read_axis(self, axis: int) -> AxisState:
|
||||||
@@ -967,4 +979,7 @@ def _replace_bus_type(bus: BusStatus, bus_type: BusType) -> BusStatus:
|
|||||||
bas_loaded=bus.bas_loaded,
|
bas_loaded=bus.bas_loaded,
|
||||||
init_started_at=bus.init_started_at,
|
init_started_at=bus.init_started_at,
|
||||||
message=bus.message,
|
message=bus.message,
|
||||||
|
# Carried, not reset: re-reading BUS_TYPE is incidental, and dropping
|
||||||
|
# this would make a just-verified init look unverified again.
|
||||||
|
verified_this_session=bus.verified_this_session,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ _STATE_KEYS = {
|
|||||||
_STATE_TONES = {
|
_STATE_TONES = {
|
||||||
"bus.state_running": "warn",
|
"bus.state_running": "warn",
|
||||||
"bus.state_ok": "ok",
|
"bus.state_ok": "ok",
|
||||||
|
"bus.state_unverified": "warn",
|
||||||
"bus.state_failed": "error",
|
"bus.state_failed": "error",
|
||||||
"bus.state_timeout": "error",
|
"bus.state_timeout": "error",
|
||||||
}
|
}
|
||||||
@@ -140,10 +141,19 @@ class BusPanel(QGroupBox):
|
|||||||
self.choose_button.setEnabled(True)
|
self.choose_button.setEnabled(True)
|
||||||
|
|
||||||
def set_status(self, bus: BusStatus, *, now: float | None = None) -> None:
|
def set_status(self, bus: BusStatus, *, now: float | None = None) -> None:
|
||||||
"""Render the bus state, including the vendor's timeout case."""
|
"""Render the bus state, including the vendor's timeout case.
|
||||||
|
|
||||||
|
An *adopted* ``Bus_InitStatus == 1`` is shown as unverified rather than
|
||||||
|
as success. The value is a ZBasic global that survives the program and a
|
||||||
|
reboot, so it proves a scan happened at some point, not that this bus is
|
||||||
|
live now — and calling that 初始化成功 is what made a machine which had
|
||||||
|
never been set up look ready to move.
|
||||||
|
"""
|
||||||
key = _STATE_KEYS.get(bus.init_status, "bus.state_pending")
|
key = _STATE_KEYS.get(bus.init_status, "bus.state_pending")
|
||||||
if bus.init_status == INIT_FAILED and bus.message and "超时" in bus.message:
|
if bus.init_status == INIT_FAILED and bus.message and "超时" in bus.message:
|
||||||
key = "bus.state_timeout"
|
key = "bus.state_timeout"
|
||||||
|
elif bus.adopted_unverified:
|
||||||
|
key = "bus.state_unverified"
|
||||||
self._state_text = t(key)
|
self._state_text = t(key)
|
||||||
self._state_tone = _STATE_TONES.get(key, "muted")
|
self._state_tone = _STATE_TONES.get(key, "muted")
|
||||||
self.state_value.setText(self._state_text)
|
self.state_value.setText(self._state_text)
|
||||||
@@ -156,7 +166,7 @@ class BusPanel(QGroupBox):
|
|||||||
self.type_value.setText(t(type_keys.get(bus.bus_type, "bus.type_unknown")))
|
self.type_value.setText(t(type_keys.get(bus.bus_type, "bus.type_unknown")))
|
||||||
self.nodes_value.setText(str(bus.node_count))
|
self.nodes_value.setText(str(bus.node_count))
|
||||||
self.axes_value.setText(str(bus.total_axes))
|
self.axes_value.setText(str(bus.total_axes))
|
||||||
self.message_label.setText(bus.message)
|
self.message_label.setText(bus.message or (t("bus.unverified_hint") if bus.adopted_unverified else ""))
|
||||||
|
|
||||||
# ------------------------------------------------------------- translations
|
# ------------------------------------------------------------- translations
|
||||||
|
|
||||||
|
|||||||
@@ -224,6 +224,12 @@ class StatusStrip(QFrame):
|
|||||||
if not connected:
|
if not connected:
|
||||||
self.chip_init.setText(t("bus.state_pending"))
|
self.chip_init.setText(t("bus.state_pending"))
|
||||||
self.chip_init.set_tone("muted")
|
self.chip_init.set_tone("muted")
|
||||||
|
elif snapshot.bus.adopted_unverified:
|
||||||
|
# The controller's initialisation global is a latch that survives the
|
||||||
|
# program and a reboot; without a run this session, "initialised" is
|
||||||
|
# not something this process has seen. Say so rather than claim it.
|
||||||
|
self.chip_init.setText(t("bus.state_unverified"))
|
||||||
|
self.chip_init.set_tone("warn")
|
||||||
elif snapshot.bus.initialized:
|
elif snapshot.bus.initialized:
|
||||||
self.chip_init.setText(t("bus.state_ok"))
|
self.chip_init.setText(t("bus.state_ok"))
|
||||||
self.chip_init.set_tone("ok")
|
self.chip_init.set_tone("ok")
|
||||||
|
|||||||
@@ -878,7 +878,9 @@ class AutoCalMainWindow(QMainWindow):
|
|||||||
t("status.poll_paused") if self.status_strip.paused else t("status.poll_ok"),
|
t("status.poll_paused") if self.status_strip.paused else t("status.poll_ok"),
|
||||||
t("status.poll_every", ms=self.poller.interval_ms),
|
t("status.poll_every", ms=self.poller.interval_ms),
|
||||||
]
|
]
|
||||||
if snapshot.bus.init_status == 1:
|
if snapshot.bus.adopted_unverified:
|
||||||
|
parts.append(t("bus.state_unverified"))
|
||||||
|
elif snapshot.bus.init_status == 1:
|
||||||
parts.append(t("bus.state_ok"))
|
parts.append(t("bus.state_ok"))
|
||||||
if self._last_error:
|
if self._last_error:
|
||||||
parts.append(f"{t('status.last_error')}: {self._last_error}")
|
parts.append(f"{t('status.last_error')}: {self._last_error}")
|
||||||
|
|||||||
Reference in New Issue
Block a user