package com.ard.work.service.impl;
|
|
import com.ard.common.constant.CacheConstants;
|
import com.ard.common.core.domain.model.LoginUser;
|
import com.ard.common.core.redis.RedisCache;
|
import com.ard.common.utils.SecurityUtils;
|
import com.ard.work.domain.cache.UavStateCache;
|
import com.ard.work.domain.dto.control.SpeedControlDTO;
|
import com.ard.work.domain.dto.state.UavState;
|
import com.ard.work.service.IGimbalSpeedService;
|
import com.ard.work.service.ITyService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.stereotype.Service;
|
import javax.annotation.Resource;
|
import java.util.Map;
|
import java.util.concurrent.*;
|
|
/**
|
* 云台速度控制实现
|
*
|
* @author lsy
|
* @date 2025/10/28
|
*/
|
@Service
|
@Slf4j
|
public class GimbalSpeedService implements IGimbalSpeedService {
|
|
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
private final Map<String, ScheduledFuture<?>> tasks = new ConcurrentHashMap<>();
|
|
@Resource
|
private ITyService tyService;
|
@Resource
|
private RedisCache redisCache;
|
|
@Override
|
public synchronized void startControl(SpeedControlDTO speed) {
|
String boxSn = speed.getBoxSn();
|
|
// ✅ 先判断是否在线
|
if (!isUavOnline(boxSn)) {
|
throw new RuntimeException("无人机离线,无法启动云台控制: " + boxSn);
|
}
|
|
if (tasks.containsKey(boxSn)) {
|
return;
|
}
|
LoginUser loginUser = SecurityUtils.getLoginUser();// 主线程获取
|
// ✅ 启动前先试探一次,确保正常
|
try {
|
SecurityContextHolder.getContext().setAuthentication(
|
new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities())
|
);
|
Boolean ok = tyService.speedControl(speed);
|
if (ok == null || !ok) {
|
throw new RuntimeException("初始速度控制指令失败");
|
}
|
} catch (Exception e) {
|
log.error("初次控制指令异常: {}", e.getMessage());
|
throw new RuntimeException("无法启动云台控制:" + e.getMessage());
|
}
|
|
ScheduledFuture<?> future = executor.scheduleAtFixedRate(() -> {
|
double currentYaw = getCurrentYaw(boxSn);
|
log.warn("currentYaw: {}", currentYaw);
|
if ((speed.getYawSpeed() < 0 && currentYaw <= -180) ||
|
(speed.getYawSpeed() > 0 && currentYaw >= 180)) {
|
stopControl(boxSn);
|
return;
|
}
|
try {
|
// 在定时任务线程设置用户上下文
|
// 手动设置 SecurityContext
|
SecurityContextHolder.getContext().setAuthentication(
|
new UsernamePasswordAuthenticationToken(
|
loginUser, null, loginUser.getAuthorities())
|
);
|
Boolean b = tyService.speedControl(speed);
|
log.warn("speedControl result:{}", b);
|
} catch (Exception e) {
|
log.error(e.getMessage());
|
}
|
|
}, 0, 200, TimeUnit.MILLISECONDS);
|
|
tasks.put(boxSn, future);
|
}
|
@Override
|
public synchronized void stopControl(String boxSn) {
|
ScheduledFuture<?> future = tasks.remove(boxSn);
|
if (future != null) {
|
future.cancel(false);
|
}
|
}
|
|
private double getCurrentYaw(String boxSn) {
|
UavState uavState = UavStateCache.get(boxSn);
|
if(uavState==null)
|
{
|
return 0;
|
}
|
return uavState.getPtzState().getYaw();
|
}
|
|
private boolean isUavOnline(String boxSn) {
|
// 如果 Redis 中存在对应 key,则认为在线
|
Object obj = redisCache.getCacheObject(CacheConstants.UAV_ONLINE_KEY + boxSn);
|
return obj != null;
|
}
|
|
}
|