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

393 lines
16 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.tuoheng.machine.config;
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;
import lombok.extern.slf4j.Slf4j;
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动态获取平台特定的Guard、Action和Listener
*/
@Configuration
@Slf4j
public class DroneMachineConfig {
@Bean(name = "droneStateMachineFactory")
public StateMachineFactory<DroneState, DroneEvent> droneStateMachineFactory(
PlatformStrategyFactory platformStrategyFactory) throws Exception {
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) {
log.error("创建DRONE状态机失败 - 机器ID: {}", machineId, e);
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());
}
}