thingsboard-client-demo/src/main/java/com/tuoheng/machine/config/DroneMachineConfig.java

393 lines
16 KiB
Java
Raw Normal View History

package com.tuoheng.machine.config;
2025-12-16 13:47:32 +08:00
import com.tuoheng.machine.events.DroneEvent;
import com.tuoheng.machine.platform.factory.PlatformStrategyFactory;
import com.tuoheng.machine.platform.strategy.DronePlatformStrategy;
import com.tuoheng.machine.status.DroneState;
2025-12-16 17:40:31 +08:00
import lombok.extern.slf4j.Slf4j;
2025-12-16 13:47:32 +08:00
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineBuilder;
import org.springframework.statemachine.config.StateMachineFactory;
import java.util.EnumSet;
import java.util.UUID;
/**
* 无人机状态机配置多平台支持版本
* 通过PlatformStrategyFactory动态获取平台特定的GuardAction和Listener
*/
@Configuration
2025-12-16 17:40:31 +08:00
@Slf4j
2025-12-16 13:47:32 +08:00
public class DroneMachineConfig {
@Bean(name = "droneStateMachineFactory")
2025-12-16 15:01:38 +08:00
public StateMachineFactory<DroneState, DroneEvent> droneStateMachineFactory(
PlatformStrategyFactory platformStrategyFactory) throws Exception {
2025-12-16 13:47:32 +08:00
return new StateMachineFactory<DroneState, DroneEvent>() {
@Override
public StateMachine<DroneState, DroneEvent> getStateMachine() {
return null;
}
@Override
public StateMachine<DroneState, DroneEvent> getStateMachine(String machineId) {
try {
// 根据无人机SN获取平台策略
DronePlatformStrategy strategy = platformStrategyFactory.getDroneStrategy(machineId);
StateMachineBuilder.Builder<DroneState, DroneEvent> builder = StateMachineBuilder.builder();
configureStateMachine(builder, strategy);
configureStates(builder);
configureTransitions(builder, strategy);
StateMachine<DroneState, DroneEvent> stateMachine = builder.build();
stateMachine.getExtendedState().getVariables().put("machineId", machineId);
return stateMachine;
} catch (Exception e) {
2025-12-16 17:40:31 +08:00
log.error("创建DRONE状态机失败 - 机器ID: {}", machineId, e);
2025-12-16 13:47:32 +08:00
throw new RuntimeException("Failed to create drone state machine for: " + machineId, e);
}
}
@Override
public StateMachine<DroneState, DroneEvent> getStateMachine(UUID uuid) {
return null;
}
};
}
private void configureStateMachine(
StateMachineBuilder.Builder<DroneState, DroneEvent> builder,
DronePlatformStrategy strategy) throws Exception {
builder.configureConfiguration()
.withConfiguration()
.autoStartup(true)
.listener(strategy.getListener());
}
private void configureStates(StateMachineBuilder.Builder<DroneState, DroneEvent> builder) throws Exception {
builder.configureStates()
.withStates()
.initial(DroneState.UNKNOWN)
.states(EnumSet.of(
DroneState.UNKNOWN,
DroneState.OFFLINE,
DroneState.PREPARING,
DroneState.FLYING_PARENT,
DroneState.RETURNING_PARENT,
DroneState.POINTING_PARENT
))
// 飞行阶段子状态
.and()
.withStates()
.parent(DroneState.FLYING_PARENT)
.initial(DroneState.FLYING)
.states(EnumSet.of(
DroneState.FLYING,
DroneState.EMERGENCY_STOP,
DroneState.ARRIVED
))
// 返航阶段子状态
.and()
.withStates()
.parent(DroneState.RETURNING_PARENT)
.initial(DroneState.RETURNING)
.states(EnumSet.of(
DroneState.RETURNING,
DroneState.RETURN_EMERGENCY_STOP,
DroneState.RETURN_COMPLETED
))
// 指点操作子状态
.and()
.withStates()
.parent(DroneState.POINTING_PARENT)
.initial(DroneState.POINT_PREPARING)
.states(EnumSet.of(
DroneState.POINT_PREPARING,
DroneState.POINT_FLYING,
DroneState.POINT_COMPLETED,
DroneState.POINT_CANCELLED
));
}
private void configureTransitions(
StateMachineBuilder.Builder<DroneState, DroneEvent> builder,
DronePlatformStrategy strategy) throws Exception {
builder.configureTransitions()
// ========== 从 UNKNOWN 到所有状态的转换(服务器重启后状态同步) ==========
// UNKNOWN -> OFFLINE
.withExternal()
.source(DroneState.UNKNOWN)
.target(DroneState.OFFLINE)
.event(DroneEvent.DRONE_OFFLINE)
.and()
// UNKNOWN -> PREPARING
.withExternal()
.source(DroneState.UNKNOWN)
.target(DroneState.PREPARING)
.event(DroneEvent.START_PREPARE)
.and()
// UNKNOWN -> FLYING_PARENT
.withExternal()
.source(DroneState.UNKNOWN)
.target(DroneState.FLYING_PARENT)
.event(DroneEvent.START_FLYING)
.and()
// UNKNOWN -> RETURNING_PARENT
.withExternal()
.source(DroneState.UNKNOWN)
.target(DroneState.RETURNING_PARENT)
.event(DroneEvent.START_RETURN)
.and()
// ========== 基本状态转换 ==========
// OFFLINE -> PREPARING
.withExternal()
.source(DroneState.OFFLINE)
.target(DroneState.PREPARING)
.event(DroneEvent.START_PREPARE)
.action(strategy.getStartPrepareAction())
.and()
// PREPARING -> FLYING_PARENT
.withExternal()
.source(DroneState.PREPARING)
.target(DroneState.FLYING_PARENT)
.event(DroneEvent.PREPARE_COMPLETED)
.action(strategy.getPrepareCompletedAction())
.and()
// ========== 飞行阶段内部转换 ==========
// FLYING -> EMERGENCY_STOP
.withExternal()
.source(DroneState.FLYING)
.target(DroneState.EMERGENCY_STOP)
.event(DroneEvent.EMERGENCY_STOP)
.action(strategy.getEmergencyStopAction())
.and()
// EMERGENCY_STOP -> FLYING (恢复飞行)
.withExternal()
.source(DroneState.EMERGENCY_STOP)
.target(DroneState.FLYING)
.event(DroneEvent.RESUME_FLYING)
.action(strategy.getResumeFlyingAction())
.and()
// FLYING -> ARRIVED
.withExternal()
.source(DroneState.FLYING)
.target(DroneState.ARRIVED)
.event(DroneEvent.ARRIVE)
.action(strategy.getArriveAction())
.and()
// 注意EMERGENCY_STOP 不能直接到 ARRIVED根据注释限制
// ========== 飞行阶段 -> 指点操作 ==========
// FLYING -> POINTING_PARENT
.withExternal()
.source(DroneState.FLYING)
.target(DroneState.POINTING_PARENT)
.event(DroneEvent.START_POINTING)
.action(strategy.getStartPointingAction())
.guard(strategy.getCanPointGuard())
.and()
// EMERGENCY_STOP -> POINTING_PARENT
.withExternal()
.source(DroneState.EMERGENCY_STOP)
.target(DroneState.POINTING_PARENT)
.event(DroneEvent.START_POINTING)
.action(strategy.getStartPointingAction())
.guard(strategy.getCanPointGuard())
.and()
// ARRIVED -> POINTING_PARENT
.withExternal()
.source(DroneState.ARRIVED)
.target(DroneState.POINTING_PARENT)
.event(DroneEvent.START_POINTING)
.action(strategy.getStartPointingAction())
.guard(strategy.getCanPointGuard())
.and()
// ========== 飞行阶段 -> 返航 ==========
// FLYING -> RETURNING_PARENT
.withExternal()
.source(DroneState.FLYING)
.target(DroneState.RETURNING_PARENT)
.event(DroneEvent.START_RETURN)
.action(strategy.getStartReturnAction())
.and()
// EMERGENCY_STOP -> RETURNING_PARENT
.withExternal()
.source(DroneState.EMERGENCY_STOP)
.target(DroneState.RETURNING_PARENT)
.event(DroneEvent.START_RETURN)
.action(strategy.getStartReturnAction())
.and()
// ARRIVED -> RETURNING_PARENT
.withExternal()
.source(DroneState.ARRIVED)
.target(DroneState.RETURNING_PARENT)
.event(DroneEvent.START_RETURN)
.action(strategy.getStartReturnAction())
.and()
// ========== 返航阶段内部转换 ==========
// RETURNING -> RETURN_EMERGENCY_STOP
.withExternal()
.source(DroneState.RETURNING)
.target(DroneState.RETURN_EMERGENCY_STOP)
.event(DroneEvent.RETURN_EMERGENCY_STOP)
.action(strategy.getReturnEmergencyStopAction())
.and()
// RETURN_EMERGENCY_STOP -> RETURNING (恢复返航)
.withExternal()
.source(DroneState.RETURN_EMERGENCY_STOP)
.target(DroneState.RETURNING)
.event(DroneEvent.RESUME_RETURN)
.action(strategy.getResumeReturnAction())
.and()
// RETURNING -> RETURN_COMPLETED
.withExternal()
.source(DroneState.RETURNING)
.target(DroneState.RETURN_COMPLETED)
.event(DroneEvent.RETURN_COMPLETED)
.action(strategy.getReturnCompletedAction())
.and()
// 注意:返航中不能指点(根据注释限制)
// 注意RETURN_COMPLETED 不能回退到 RETURNING 或 RETURN_EMERGENCY_STOP根据注释限制
// ========== 返航急停 -> 指点操作 ==========
// RETURN_EMERGENCY_STOP -> POINTING_PARENT (一键起飞和航线飞行都可以指点)
.withExternal()
.source(DroneState.RETURN_EMERGENCY_STOP)
.target(DroneState.POINTING_PARENT)
.event(DroneEvent.START_POINTING)
.action(strategy.getStartPointingAction())
.guard(strategy.getCanPointGuard())
.and()
// ========== 指点操作内部转换 ==========
// POINT_PREPARING -> POINT_FLYING
.withExternal()
.source(DroneState.POINT_PREPARING)
.target(DroneState.POINT_FLYING)
.event(DroneEvent.POINT_PREPARE_COMPLETED)
.action(strategy.getPointPrepareCompletedAction())
.and()
// POINT_FLYING -> POINT_COMPLETED
.withExternal()
.source(DroneState.POINT_FLYING)
.target(DroneState.POINT_COMPLETED)
.event(DroneEvent.POINT_FLYING_COMPLETED)
.action(strategy.getPointFlyingCompletedAction())
.and()
// 任何指点阶段 -> POINT_CANCELLED
.withExternal()
.source(DroneState.POINT_PREPARING)
.target(DroneState.POINT_CANCELLED)
.event(DroneEvent.CANCEL_POINT)
.action(strategy.getCancelPointAction())
.and()
.withExternal()
.source(DroneState.POINT_FLYING)
.target(DroneState.POINT_CANCELLED)
.event(DroneEvent.CANCEL_POINT)
.action(strategy.getCancelPointAction())
.and()
.withExternal()
.source(DroneState.POINT_COMPLETED)
.target(DroneState.POINT_CANCELLED)
.event(DroneEvent.CANCEL_POINT)
.action(strategy.getCancelPointAction())
.and()
// ========== 指点操作 -> 飞行/返航 ==========
// POINT_COMPLETED -> FLYING
.withExternal()
.source(DroneState.POINT_COMPLETED)
.target(DroneState.FLYING)
.event(DroneEvent.POINT_TO_FLYING)
.action(strategy.getPointToFlyingAction())
.and()
// POINT_CANCELLED -> FLYING
.withExternal()
.source(DroneState.POINT_CANCELLED)
.target(DroneState.FLYING)
.event(DroneEvent.POINT_TO_FLYING)
.action(strategy.getPointToFlyingAction())
.and()
// POINT_COMPLETED -> RETURNING_PARENT
.withExternal()
.source(DroneState.POINT_COMPLETED)
.target(DroneState.RETURNING_PARENT)
.event(DroneEvent.POINT_TO_RETURN)
.action(strategy.getPointToReturnAction())
.and()
// POINT_CANCELLED -> RETURNING_PARENT
.withExternal()
.source(DroneState.POINT_CANCELLED)
.target(DroneState.RETURNING_PARENT)
.event(DroneEvent.POINT_TO_RETURN)
.action(strategy.getPointToReturnAction())
.and()
// POINT_COMPLETED -> RETURN_EMERGENCY_STOP
.withExternal()
.source(DroneState.POINT_COMPLETED)
.target(DroneState.RETURN_EMERGENCY_STOP)
.event(DroneEvent.RETURN_EMERGENCY_STOP)
.action(strategy.getReturnEmergencyStopAction())
.and()
// POINT_COMPLETED -> RETURN_COMPLETED
.withExternal()
.source(DroneState.POINT_COMPLETED)
.target(DroneState.RETURN_COMPLETED)
.event(DroneEvent.RETURN_COMPLETED)
.action(strategy.getReturnCompletedAction())
.and()
// ========== 离线处理 ==========
// 任何状态 -> OFFLINE
.withExternal()
.source(DroneState.FLYING_PARENT)
.target(DroneState.OFFLINE)
.event(DroneEvent.DRONE_OFFLINE)
.action(strategy.getOfflineAction())
.and()
.withExternal()
.source(DroneState.RETURNING_PARENT)
.target(DroneState.OFFLINE)
.event(DroneEvent.DRONE_OFFLINE)
.action(strategy.getOfflineAction())
.and()
.withExternal()
.source(DroneState.POINTING_PARENT)
.target(DroneState.OFFLINE)
.event(DroneEvent.DRONE_OFFLINE)
.action(strategy.getOfflineAction());
}
}