update vehicle adapter

This commit is contained in:
wait 2025-04-18 11:06:14 +08:00
parent 17c28a5a7f
commit 4882a28c0a
81 changed files with 4660 additions and 4635 deletions

View File

@ -1,40 +0,0 @@
package org.opentcs.kcvehicle;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import org.opentcs.customizations.kernel.KernelInjectionModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class KcCommAdapterModule extends KernelInjectionModule {
private static final Logger LOG = LoggerFactory.getLogger(KcCommAdapterModule.class);
@Override
protected void configure() {
//
// VirtualVehicleConfiguration configuration
// = getConfigBindingProvider().get(
// VirtualVehicleConfiguration.PREFIX,
// VirtualVehicleConfiguration.class
// );
//
//// KcVehicleConfiguration configuration
//// = getConfigBindingProvider().get(
//// KcVehicleConfiguration.PREFIX,
//// KcVehicleConfiguration.class
//// );
//
// if (!configuration.enable()) {
// LOG.info("KC driver disabled by configuration.");
// return;
// }
//
// bind(VirtualVehicleConfiguration.class)
// .toInstance(configuration);
//
// install(new FactoryModuleBuilder().build(LoopbackAdapterComponentsFactory.class));
//
// vehicleCommAdaptersBinder().addBinding().to(LoopbackCommunicationAdapterFactory.class);
}
}

View File

@ -2,4 +2,3 @@
# SPDX-License-Identifier: MIT
org.opentcs.virtualvehicle.LoopbackCommAdapterModule
org.opentcs.kcvehicle.KcCommAdapterModule

View File

@ -1,10 +0,0 @@
package org.opentcs.kcvehicle;
import org.opentcs.data.model.Vehicle;
import org.opentcs.kcvehicle.KcCommunicationAdapter;
public interface KcAdapterComponentsFactory {
// KcCommunicationAdapter createKcCommunicationAdapter(Vehicle vehicle);
KcCommunicationAdapter createKcCommunicationAdapter(Vehicle vehicle);
}

View File

@ -1,163 +0,0 @@
package org.opentcs.kcvehicle;
import com.google.inject.assistedinject.Assisted;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.inject.Inject;
import java.util.concurrent.ScheduledExecutorService;
import org.opentcs.customizations.kernel.KernelExecutor;
import org.opentcs.data.model.Vehicle;
import org.opentcs.data.order.TransportOrder;
import org.opentcs.drivers.vehicle.BasicVehicleCommAdapter;
import org.opentcs.drivers.vehicle.MovementCommand;
import org.opentcs.drivers.vehicle.VehicleProcessModel;
import org.opentcs.kc.udp.Service.ConfirmRelocation;
import org.opentcs.kc.udp.Service.ManualPosition;
import org.opentcs.kc.udp.Service.QryRobotRunStatus;
import org.opentcs.kc.udp.Service.QryRobotStatus;
import org.opentcs.kc.udp.Service.SubCargoStatus;
import org.opentcs.kc.udp.Service.SubRobotStatue;
import org.opentcs.kc.udp.Service.SwitchAutomaticMode;
import org.opentcs.kc.udp.Service.SwitchManualMode;
import org.opentcs.kc.udp.agv.param.function.af.LocationStatusInfo;
import org.opentcs.kc.udp.agv.param.function.af.QueryRobotStatusRsp;
import org.opentcs.kc.udp.agv.param.function.x17.QueryRobotRunStatusRsp;
import org.opentcs.util.ExplainedBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class KcCommunicationAdapter extends BasicVehicleCommAdapter {
private static final Logger LOG = LoggerFactory.getLogger(KcCommunicationAdapter.class);
/**
* This instance's configuration.
*/
private final KcVehicleConfiguration configuration;
/**
* 单个仿真步骤的时间 毫秒
*/
private static final int SIMULATION_PERIOD = 100;
/**
* Creates a new instance.
*/
@Inject
public KcCommunicationAdapter(
KcVehicleConfiguration configuration,
@Assisted
Vehicle vehicle,
@KernelExecutor
ScheduledExecutorService kernelExecutor
) {
super(
new VehicleProcessModel(vehicle),
configuration.commandQueueCapacity(),
configuration.rechargeOperation(),
kernelExecutor
);
this.configuration = configuration;
}
// @Inject
// public KcCommunicationAdapter(Vehicle vehicle) {
// super(new VehicleProcessModel(vehicle), 1, "Recharge");
// }
@Override
public void sendCommand(MovementCommand cmd)
throws IllegalArgumentException {
}
@Override
protected void connectVehicle() {
//initAGV();
getProcessModel().setCommAdapterConnected(true);
}
@Override
protected void disconnectVehicle() {
getProcessModel().setCommAdapterConnected(false);
}
@Override
protected boolean isVehicleConnected() {
return getProcessModel().isCommAdapterConnected();
}
@Nonnull
@Override
public ExplainedBoolean canProcess(
@Nonnull
TransportOrder order
) {
return null;
}
@Override
public void onVehiclePaused(boolean paused) {
}
@Override
public void processMessage(
@Nullable
Object message
) {
}
/**
* 初始化AGV
* 步骤:
* 1调度软件启动机器人启动无顺序要求
* 2等待调度系统以及机器人控制器启动完成调度系统启动即向机器人发送状态查询查询成功即为启动完成
* 3调度软件发送订阅信令至机器人表明订阅机器人状态信息或载货状态机器人接收到订阅信令会依据订阅要求推送订阅信息度软件需要根据订阅信令中上报持续时间提前刷新机器人推送的上报持续时间
* 4调度软件持续监控机器人实时状态
* 5导航初始化
*/
private void initAGV() {
//0xAF获取AGV状态
QueryRobotStatusRsp qryRobotStatusRsp = QryRobotStatus.command();
//开启AGV订阅监听 (0xAF & 0xB0)
SubRobotStatue.command();
SubCargoStatus.command();
//1 切换定位为手动模式命令码0x03变量NaviControl 修改为0
SwitchManualMode.command();
LocationStatusInfo locationStatusInfo = qryRobotStatusRsp.locationStatusInfo;
double agvX = locationStatusInfo.globalX;
double agvY = locationStatusInfo.globalY;
double agvAngle = locationStatusInfo.absoluteDirecAngle;
//3 查询机器人运行状态命令码0x17等待机器人定位状态为定位完成
QueryRobotRunStatusRsp qryRobotRunStatusRsp = QryRobotRunStatus.command();
if (qryRobotRunStatusRsp.robotLocalizationState == 0) {
//2 执行机器人手动定位 命令码0x14
ManualPosition.command(agvX, agvY, agvAngle);
throw new RuntimeException("AGV定位失败执行手动定位中");
} else if (qryRobotRunStatusRsp.robotLocalizationState == 2) {
throw new RuntimeException("AGV定位中");
}
//4 确认初始位置命令码0x1F
ConfirmRelocation.commnd();
//5 切换成自动模式命令码0x03变量NaviControl 修改为1
SwitchAutomaticMode.command();
//打开通讯适配器连接
getProcessModel().setCommAdapterConnected(true);
}
private int getSimulationTimeStep() {
return (int) (SIMULATION_PERIOD * configuration.simulationTimeFactor());
}
}

View File

@ -1,15 +0,0 @@
package org.opentcs.kcvehicle;
import org.opentcs.drivers.vehicle.VehicleCommAdapterDescription;
public class KcCommunicationAdapterDescription extends VehicleCommAdapterDescription {
@Override
public String getDescription() {
return "KC_ADAPTER";
}
@Override
public boolean isSimVehicleCommAdapter() {
return false;
}
}

View File

@ -1,61 +0,0 @@
package org.opentcs.kcvehicle;
import static java.util.Objects.requireNonNull;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.inject.Inject;
import org.opentcs.data.model.Vehicle;
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
import org.opentcs.drivers.vehicle.VehicleCommAdapterDescription;
import org.opentcs.drivers.vehicle.VehicleCommAdapterFactory;
import org.opentcs.drivers.vehicle.VehicleProcessModel;
public class KcCommunicationAdapterFactory implements VehicleCommAdapterFactory {
private final KcAdapterComponentsFactory adapterFactory;
@Inject
public KcCommunicationAdapterFactory(KcAdapterComponentsFactory componentsFactory) {
this.adapterFactory = requireNonNull(componentsFactory, "KC_componentsFactory_NULL");
}
@Override
public VehicleCommAdapterDescription getDescription() {
return new KcCommunicationAdapterDescription();
}
@Override
public boolean providesAdapterFor(
@Nonnull
Vehicle vehicle
) {
return false;
}
@Nullable
@Override
public VehicleCommAdapter getAdapterFor(
@Nonnull
Vehicle vehicle
) {
return adapterFactory.createKcCommunicationAdapter(vehicle);
// return adapterFactory.createKcCommunicationAdapter(vehicle);
}
@Override
public void initialize() {
}
@Override
public boolean isInitialized() {
return false;
}
@Override
public void terminate() {
}
}

View File

@ -1,77 +0,0 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.kcvehicle;
import org.opentcs.configuration.ConfigurationEntry;
import org.opentcs.configuration.ConfigurationPrefix;
/**
* Provides methods to configure to {@link KcCommunicationAdapter}.
*/
@ConfigurationPrefix(KcVehicleConfiguration.PREFIX)
public interface KcVehicleConfiguration {
/**
* This configuration's prefix.
*/
String PREFIX = "kcvehicle";
@ConfigurationEntry(
type = "Boolean",
description = "Whether to enable to register/enable the loopback driver.",
changesApplied = ConfigurationEntry.ChangesApplied.ON_APPLICATION_START,
orderKey = "0_enable"
)
boolean enable();
@ConfigurationEntry(
type = "Integer",
description = "The adapter's command queue capacity.",
changesApplied = ConfigurationEntry.ChangesApplied.ON_NEW_PLANT_MODEL,
orderKey = "1_attributes_1"
)
int commandQueueCapacity();
@ConfigurationEntry(
type = "String",
description = "The string to be treated as a recharge operation.",
changesApplied = ConfigurationEntry.ChangesApplied.ON_NEW_PLANT_MODEL,
orderKey = "1_attributes_2"
)
String rechargeOperation();
@ConfigurationEntry(
type = "Double",
description = "The rate at which the vehicle recharges in percent per second.",
changesApplied = ConfigurationEntry.ChangesApplied.INSTANTLY,
orderKey = "1_attributes_3"
)
double rechargePercentagePerSecond();
@ConfigurationEntry(
type = "Double",
description = {
"The simulation time factor.",
"1.0 is real time, greater values speed up simulation."
},
changesApplied = ConfigurationEntry.ChangesApplied.INSTANTLY,
orderKey = "2_behaviour_1"
)
double simulationTimeFactor();
@ConfigurationEntry(
type = "Integer",
description = {"The virtual vehicle's length in mm when it's loaded."},
changesApplied = ConfigurationEntry.ChangesApplied.INSTANTLY,
orderKey = "2_behaviour_2"
)
int vehicleLengthLoaded();
@ConfigurationEntry(
type = "Integer",
description = {"The virtual vehicle's length in mm when it's unloaded."},
changesApplied = ConfigurationEntry.ChangesApplied.INSTANTLY,
orderKey = "2_behaviour_3"
)
int vehicleLengthUnloaded();
}

View File

@ -7,6 +7,7 @@ import static java.util.Objects.requireNonNull;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.beans.PropertyChangeEvent;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
@ -14,11 +15,14 @@ import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.opentcs.common.LoopbackAdapterConstants;
import org.opentcs.customizations.kernel.KernelExecutor;
import org.opentcs.data.model.Point;
import org.opentcs.data.model.Pose;
import org.opentcs.data.model.Triple;
import org.opentcs.data.model.Vehicle;
@ -44,6 +48,7 @@ import org.opentcs.kc.udp.agv.param.function.af.LocationStatusInfo;
import org.opentcs.kc.udp.agv.param.function.af.QueryRobotStatusRsp;
import org.opentcs.kc.udp.agv.param.function.b0.QueryCargoStatusRsp;
import org.opentcs.kc.udp.agv.param.function.x17.QueryRobotRunStatusRsp;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.util.ExplainedBoolean;
import org.opentcs.virtualvehicle.VelocityController.WayEntry;
import org.slf4j.Logger;
@ -113,25 +118,32 @@ public class LoopbackCommunicationAdapter
*/
private boolean initialized;
/**
* 上报截止时间
* 0xAF上报截止时间.
*/
private long deadline;
private long sub0xafDeadline;
/**
* 上报间隔时间/ms
* 0xB0上报截止时间.
*/
private long intervalTime;
// /**
// * AGV IP
// */
// private final String IP;
// /**
// * AGV 端口
// */
// private final int PORT;
// /**
// * AGV AUTHORIZE_CODE
// */
// private final String AUTHORIZE_CODE;
private long sub0xb0Deadline;
/**
* 创建线程
*/
private final ExecutorService messageProcessingPool = new ThreadPoolExecutor(
4,
8,
60L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(100),
new ThreadPoolExecutor.CallerRunsPolicy()
);
/**
* 订阅状态
*/
private static boolean SUBSCRIBE_STATUS;
/**
* 最后经过点位
*/
private static String LAST_PASSED_POINT;
/**
* Creates a new instance.
@ -193,41 +205,52 @@ public class LoopbackCommunicationAdapter
@Override
public void propertyChange(PropertyChangeEvent evt) {
//调用父类的 propertyChange 方法处理事件
super.propertyChange(evt);
//如果事件源不是 LoopbackVehicleModel 类型直接返回
if (!((evt.getSource()) instanceof LoopbackVehicleModel)) {
return;
}
//如果事件属性名为 LOAD_HANDLING_DEVICES
if (Objects.equals(
evt.getPropertyName(),
VehicleProcessModel.Attribute.LOAD_HANDLING_DEVICES.name()
)) {
if (!getProcessModel().getLoadHandlingDevices().isEmpty()
&& getProcessModel().getLoadHandlingDevices().get(0).isFull()) {
//检查负载处理设备是否为空且第一个设备是否满载更新负载状态为 FULL 并设置车辆长度为加载状态下的长度
loadState = LoadState.FULL;
getProcessModel().setBoundingBox(
getProcessModel().getBoundingBox().withLength(configuration.vehicleLengthLoaded())
);
}
else {
//否则更新负载状态为 EMPTY 并设置车辆长度为未加载状态下的长度
loadState = LoadState.EMPTY;
getProcessModel().setBoundingBox(
getProcessModel().getBoundingBox().withLength(configuration.vehicleLengthUnloaded())
);
}
}
//如果事件属性名为 SINGLE_STEP_MODE
if (Objects.equals(
evt.getPropertyName(),
LoopbackVehicleModel.Attribute.SINGLE_STEP_MODE.name()
)) {
// When switching from single step mode to automatic mode and there are commands to be
// processed, ensure that we start/continue processing them.
//如果单步模式关闭待处理命令队列非空且模拟未运行则启动车辆模拟
if (!getProcessModel().isSingleStepModeEnabled()
&& !getSentCommands().isEmpty()
&& !isSimulationRunning) {
//标记模拟正在运行
isSimulationRunning = true;
//提交任务到线程池执行队列中的第一个命令
((ExecutorService) getExecutor()).submit(
() -> startVehicleSimulation(getSentCommands().peek())
() -> startVehicle(getSentCommands().peek())
);
}
}
@ -261,6 +284,7 @@ public class LoopbackCommunicationAdapter
System.out.println(cmd);
System.out.println("send cmd print start");
// SubRobotStatue.command();
//订单ID
String orderName = cmd.getTransportOrder().getName();
@ -283,29 +307,40 @@ public class LoopbackCommunicationAdapter
System.out.println("sourcePoint:" + sourcePoint);
//下发终点
String destinationPoint = cmd.getStep().getDestinationPoint().getName();
System.out.println("destinationPoint:" + destinationPoint);
Point destinationPoint = cmd.getStep().getDestinationPoint();
//获取点类型
String pointProperty = destinationPoint.getProperty(LoopbackAdapterConstants.POINT_TYPE);
System.out.println("destinationPoint_tcs:point:" + pointProperty);
String destinationPointName = cmd.getStep().getDestinationPoint().getName();
System.out.println("destinationPointName:" + destinationPointName);
//拼接起点终点字符串转为Integer类型获取唯一pathID
Integer pathID = Integer.parseInt(sourcePoint + destinationPoint);
System.out.println("pathID:" + pathID);
System.out.println("send cmd print end");
//订阅0xAF
// sub0xAF();
//AGV控制器执行命令
HybridNavigation.command("1", sourcePoint, destinationPoint, operation);
HybridNavigation.command(orderName, sourcePoint, destinationPointName, operation);
// Start the simulation task if we're not in single step mode and not simulating already.
//检查当前车辆模型是否处于单步模式且未运行若满足条件则设置运行状态为true
if (!getProcessModel().isSingleStepModeEnabled()
&& !isSimulationRunning) {
isSimulationRunning = true;
// The command is added to the sent queue after this method returns. Therefore
// we have to explicitly start the simulation like this.
if (LAST_PASSED_POINT == null) {
//设置最后经过点为起点
LAST_PASSED_POINT = sourcePoint;
//设置订阅状态为true
SUBSCRIBE_STATUS = true;
}
sub0xAF();
// 展示模拟车辆
if (getSentCommands().isEmpty()) {
((ExecutorService) getExecutor()).submit(() -> startVehicleSimulation(cmd));
((ExecutorService) getExecutor()).submit(() -> startVehicle(cmd));
}
else {
((ExecutorService) getExecutor()).submit(
() -> startVehicleSimulation(getSentCommands().peek())
() -> startVehicle(getSentCommands().peek())
);
}
}
@ -318,74 +353,100 @@ public class LoopbackCommunicationAdapter
@Override
public void processMessage(Object message) {
if (message instanceof String) {
//测试使用
getProcessModel().setEnergyLevel(66);
System.out.println(message);
if (message instanceof byte[]) {
updateVehicleModel(message);
}
else if (message instanceof QueryCargoStatusRsp) {
//0xB0响应结果
QueryCargoStatusRsp queryCargoStatusRsp = (QueryCargoStatusRsp) message;
else if (message instanceof HashMap<?, ?>) {
//todo 测试代码----成功
HashMap<?, ?> msg = (HashMap<?, ?>) message;
if (queryCargoStatusRsp.isCargo == 0) {
this.loadState = LoadState.EMPTY;
} else {
this.loadState = LoadState.FULL;
}
}
else if (message instanceof QueryRobotStatusRsp) {
System.out.println("test success");
//0xAF响应结果
QueryRobotStatusRsp queryRobotStatusRsp = (QueryRobotStatusRsp) message;
//电量
float batteryPercentage = queryRobotStatusRsp.batteryStatusInfo.batteryPercentage;
getProcessModel().setEnergyLevel(((int)batteryPercentage * 100));
//充电状态
byte chargingState = queryRobotStatusRsp.batteryStatusInfo.chargingState;
if (chargingState == 1) {
getProcessModel().setState(Vehicle.State.CHARGING);
}
//设置车辆位置(最后一次通过的点)
// String lastPointName = queryRobotStatusRsp.locationStatusInfo.lastPassPointId.toString();
// getProcessModel().setPosition(lastPointName);
////设置车辆姿势(官方弃用设置车辆精确位置)
long positionX = (long)queryRobotStatusRsp.locationStatusInfo.globalX;
long positionY = (long)queryRobotStatusRsp.locationStatusInfo.globalY;
Triple triple = new Triple(positionX, positionY, 0);
double positionAngle = queryRobotStatusRsp.locationStatusInfo.absoluteDirecAngle;
getProcessModel().setPose(new Pose(triple, positionAngle));
}
else if (message instanceof HashMap<?,?>) {
HashMap<?,?> msg = ((HashMap<?, ?>) message);
getProcessModel().setEnergyLevel((int)msg.get("energy"));
getProcessModel().setEnergyLevel((int) msg.get("energy"));
getProcessModel().setState(Vehicle.State.EXECUTING);
long positionX = (long)msg.get("positionX");
long positionY = (long)msg.get("positionY");
long positionX = (long) msg.get("positionX");
long positionY = (long) msg.get("positionY");
Triple triple = new Triple(positionX, positionY, 0);
double positionAngle = (double)msg.get("positionAngle");
double positionAngle = (double) msg.get("positionAngle");
getProcessModel().setPose(new Pose(triple, positionAngle));
}
}
//上报自动续订操作
// renewalSubscribe();
private void updateVehicleModel(Object message) {
try {
byte[] body = (byte[])message;
RcvEventPackage rcv = new RcvEventPackage(body[22], body);
if (body[21] == (byte) 0xAF) {
System.out.println("0xAF sub success");
//AGV状态订阅
QueryRobotStatusRsp queryRobotStatusRsp = new QueryRobotStatusRsp(rcv.getDataBytes());
System.out.println();
//电量--目前无电量返回设置一个随机值
float batteryPercentage = queryRobotStatusRsp.batteryStatusInfo.batteryPercentage;
getProcessModel().setEnergyLevel(89);
//设置AGV最后一个点位置,不设置最后经过点opentcs无法调度
String vehicleNowPosition = getProcessModel().getPosition();
String lastPassPointId = (queryRobotStatusRsp.locationStatusInfo.lastPassPointId).toString();
if (vehicleNowPosition == null || !vehicleNowPosition.equals(lastPassPointId)) {
initVehiclePosition(lastPassPointId);
}
//设置车辆姿势(官方弃用设置车辆精确位置)-------------------目前车辆返回位置为固定值
/* long positionX = (long) queryRobotStatusRsp.locationStatusInfo.globalX;
long positionY = (long) queryRobotStatusRsp.locationStatusInfo.globalY;
Triple triple = new Triple(positionX, positionY, 0);
double positionAngle = queryRobotStatusRsp.locationStatusInfo.absoluteDirecAngle;
LocalDateTime now = LocalDateTime.now();
System.out.println(now + "[positionX:" + positionX + "] [positionY:" + positionY + "] [positionAngle:" + positionAngle + "]");
getProcessModel().setPose(new Pose(triple, positionAngle));*/
//到期续订
renewalSubscribe0xAF();
} else if (body[21] == (byte) 0xB0) {
System.out.println("0xB0 sub success");
//载货状态订阅
QueryCargoStatusRsp queryCargoStatusRsp = new QueryCargoStatusRsp(rcv.getDataBytes());
if (queryCargoStatusRsp.isCargo == 0) {
this.loadState = LoadState.EMPTY;
}
else {
this.loadState = LoadState.FULL;
}
//到期续订
renewalSubscribe0xB0();
}
} catch (Exception e) {
throw new RuntimeException("processMessage_messageExecutorPool:" + e);
}
}
/**
* 订阅到期自动续订
* 订阅到期自动续订0xAF.
*/
private void renewalSubscribe() {
private void renewalSubscribe0xAF() {
Date now = new Date();
if (now.getTime() + intervalTime >= deadline) {
//开启AGV订阅监听 (0xAF & 0xB0)
SubRobotStatue.command();
SubCargoStatus.command();
if (sub0xafDeadline - now.getTime() <= SubRobotStatue.intervalTime && SUBSCRIBE_STATUS) {
sub0xAF();
}
}
/**
* 订阅到期自动续订0xB0.
*/
private void renewalSubscribe0xB0() {
Date now = new Date();
if (sub0xb0Deadline - now.getTime() <= SubCargoStatus.intervalTime && SUBSCRIBE_STATUS) {
sub0xB0();
}
}
@ -446,11 +507,8 @@ public class LoopbackCommunicationAdapter
@Override
protected synchronized void connectVehicle() {
String ip = requireNonNull(vehicle.getProperties().get(LoopbackAdapterConstants.AGV_IP), "AGV IP NOT NULL");
Integer port = Integer.parseInt(requireNonNull(vehicle.getProperties().get(LoopbackAdapterConstants.AGV_PORT), "AGV PORT NOT NULL"));
String authorizeCode = requireNonNull(vehicle.getProperties().get(LoopbackAdapterConstants.AGV_AUTHORIZE_CODE), "AGV AUTHORIZE_CODE NOT NULL");
getProcessModel().setCommAdapterConnected(true);
// initAGV();
// getProcessModel().setCommAdapterConnected(true);
initAGV();
}
@Override
@ -491,6 +549,36 @@ public class LoopbackCommunicationAdapter
}
}
/**
* 执行车辆移动指令
*
* @param command 移动指令
*/
private void startVehicle(MovementCommand command) {
LOG.debug("-Starting vehicle for command: {}", command);
Step step = command.getStep();
getProcessModel().setState(Vehicle.State.EXECUTING);
if (step.getPath() == null) {
LOG.debug("-Starting operation...");
//动作执行待完成
operationExec(command);
} else {
getProcessModel().getVelocityController().addWayEntry(
new WayEntry(
step.getPath().getLength(),
maxVelocity(step),
step.getDestinationPoint().getName(),
step.getVehicleOrientation()
)
);
LOG.debug("-Starting movement ...");
movementExec(command);
}
}
private void startVehicleSimulation(MovementCommand command) {
LOG.debug("Starting vehicle simulation for command: {}", command);
Step step = command.getStep();
@ -529,12 +617,54 @@ public class LoopbackCommunicationAdapter
: step.getPath().getMaxVelocity();
}
/**
* 执行运行指令.
*
* @param command 要执行的命令
*/
private void movementExec(MovementCommand command) {
//检查当前车辆模型的速度控制器是否有路径条目若无则直接返回
if (!getProcessModel().getVelocityController().hasWayEntries()) {
return;
}
//获取AGV最终经过点
String currentPoint = getProcessModel().getPosition() != null ? getProcessModel().getPosition() : "";
//获取当前路径条目并推进时间步长检查是否仍处于同一路径条目
if (currentPoint.equals(LAST_PASSED_POINT)) {
//若是则重新调度当前方法以继续模拟
getExecutor().schedule(
() -> movementExec(command),
SIMULATION_PERIOD,
TimeUnit.MILLISECONDS
);
} else {
LAST_PASSED_POINT = currentPoint;
//若否更新车辆位置为上一路径条目的目标点并根据命令是否有操作决定进入操作模拟或完成命令并模拟下一个命令
LOG.debug("-Movement finished.");
if (!command.hasEmptyOperation()) {
//执行AGV动作
LOG.debug("-Starting operation...");
operationExec(command);
} else {
//完成当前命令
finishMoveCmd(command);
//执行下一个命令
nextCommand();
}
}
}
/**
* Simulate the movement part of a MovementCommand.
*
* @param command The command to simulate.
*/
private void movementSimulation(MovementCommand command) {
//检查当前车辆模型的速度控制器是否有路径条目若无则直接返回
if (!getProcessModel().getVelocityController().hasWayEntries()) {
return;
}
@ -543,7 +673,9 @@ public class LoopbackCommunicationAdapter
getProcessModel().getVelocityController().advanceTime(getSimulationTimeStep());
WayEntry currentWayEntry = getProcessModel().getVelocityController().getCurrentWayEntry();
//if we are still on the same way entry then reschedule to do it again
//获取当前路径条目并推进时间步长检查是否仍处于同一路径条目
if (prevWayEntry == currentWayEntry) {
//若是则重新调度当前方法以继续模拟
getExecutor().schedule(
() -> movementSimulation(command),
SIMULATION_PERIOD,
@ -553,6 +685,7 @@ public class LoopbackCommunicationAdapter
else {
//if the way enties are different then we have finished this step
//and we can move on.
//若否更新车辆位置为上一路径条目的目标点并根据命令是否有操作决定进入操作模拟或完成命令并模拟下一个命令
getProcessModel().setPosition(prevWayEntry.getDestPointName());
LOG.debug("Movement simulation finished.");
if (!command.hasEmptyOperation()) {
@ -570,8 +703,18 @@ public class LoopbackCommunicationAdapter
}
}
/**
* 执行移动命令的操作部分
*
* @param command 要执行的命令
*/
private void operationExec(MovementCommand command) {
}
/**
* Simulate the operation part of a movement command.
* 模拟移动命令的操作部分
*
* @param command The command to simulate.
* @param timePassed The amount of time passed since starting the simulation.
@ -626,6 +769,7 @@ public class LoopbackCommunicationAdapter
/**
* Simulate recharging the vehicle.
* 模拟为车辆充电
*
* @param rechargePosition The vehicle position where the recharge simulation was started.
* @param rechargePercentage The recharge percentage of the vehicle while it is charging.
@ -671,14 +815,43 @@ public class LoopbackCommunicationAdapter
+ (float) (configuration.rechargePercentagePerSecond() / 1000.0) * SIMULATION_PERIOD;
}
/**
* 结束移动命令
* @param command 指令
*/
private void finishMoveCmd(MovementCommand command) {
//检查已发送命令队列的大小是否小于等于1且未发送命令队列是否为空
if (getSentCommands().size() <= 1 && getUnsentCommands().isEmpty()) {
System.out.println("-getSentCommands <= 1 && getUnsentCommands is null");
getProcessModel().setState(Vehicle.State.IDLE);
//清除订单对应唯一ID
HybridNavigation.delUniqueOrderID(command);
}
//如果传入指令和移动指令队列第一条数据相同
if (Objects.equals(getSentCommands().peek(), command)) {
// 完成当前任务
getProcessModel().commandExecuted(getSentCommands().poll());
} else {
//
LOG.warn(
"-{}: Exec command not oldest in sent queue: {} != {}",
getName(),
command,
getSentCommands().peek()
);
}
}
private void finishMovementCommand(MovementCommand command) {
//Set the vehicle state to idle
if (getSentCommands().size() <= 1 && getUnsentCommands().isEmpty()) {
getProcessModel().setState(Vehicle.State.IDLE);
}
if (Objects.equals(getSentCommands().peek(), command)) {
// Let the comm adapter know we have finished this command.
// Let the comm adapter know we have finished this command. 让通信适配器知道我们已经完成了这个命令
getProcessModel().commandExecuted(getSentCommands().poll());
// HybridNavigation.delUniqueOrderID(command);
}
else {
LOG.warn(
@ -690,6 +863,22 @@ public class LoopbackCommunicationAdapter
}
}
void nextCommand() {
if (getSentCommands().isEmpty() || getProcessModel().isSingleStepModeEnabled()) {
LOG.debug("Vehicle exec is done.");
getProcessModel().setState(Vehicle.State.IDLE);
isSimulationRunning = false;
LAST_PASSED_POINT = null;
SUBSCRIBE_STATUS = false;
}
else {
LOG.debug("Triggering exec for next command: {}", getSentCommands().peek());
((ExecutorService) getExecutor()).submit(
() -> startVehicle(getSentCommands().peek())
);
}
}
void simulateNextCommand() {
if (getSentCommands().isEmpty() || getProcessModel().isSingleStepModeEnabled()) {
LOG.debug("Vehicle simulation is done.");
@ -727,47 +916,133 @@ public class LoopbackCommunicationAdapter
*/
private void initAGV() {
//0xAF获取AGV状态
QueryRobotStatusRsp qryRobotStatusRsp = QryRobotStatus.command();
if (true) {
//0xAF获取AGV状态
System.out.println("=================---initAGV_0xAF");
QueryRobotStatusRsp qryRobotStatusRsp = QryRobotStatus.command();
if (qryRobotStatusRsp == null) {
getProcessModel().setCommAdapterConnected(false);
throw new RuntimeException("initAGV 0xAF response is null");
}
//设置订阅时间和上报间隔
Date now = new Date();
deadline = now.getTime() + 1000;
intervalTime = 100;
//开启AGV订阅监听 (0xAF & 0xB0)
SubRobotStatue.command();
SubCargoStatus.command();
//1 切换定位为手动模式命令码0x03变量NaviControl 修改为0
SwitchManualMode.command();
LocationStatusInfo locationStatusInfo = qryRobotStatusRsp.locationStatusInfo;
double agvX = locationStatusInfo.globalX;
double agvY = locationStatusInfo.globalY;
double agvAngle = locationStatusInfo.absoluteDirecAngle;
//开启0xAF订阅
sub0xAF();
//3 查询机器人运行状态命令码0x17等待机器人定位状态为定位完成
QueryRobotRunStatusRsp qryRobotRunStatusRsp = QryRobotRunStatus.command();
if (qryRobotRunStatusRsp.robotLocalizationState == 0) {
//开启0xB0订阅
// sub0xB0()
// //设置车辆姿势(官方弃用设置车辆精确位置)-------------------目前车辆返回位置为固定值
// long positionX = (long) qryRobotStatusRsp.locationStatusInfo.globalX;
// long positionY = (long) qryRobotStatusRsp.locationStatusInfo.globalY;
// Triple triple = new Triple(positionX, positionY, 0);
// double positionAngle = qryRobotStatusRsp.locationStatusInfo.absoluteDirecAngle;
// getProcessModel().setPose(new Pose(triple, positionAngle));
//3 查询机器人运行状态命令码0x17等待机器人定位状态为定位完成
System.out.println("=================---initAGV_0x17");
QueryRobotRunStatusRsp qryRobotRunStatusRsp = QryRobotRunStatus.command();
if (qryRobotRunStatusRsp == null) {
getProcessModel().setCommAdapterConnected(false);
throw new RuntimeException("initAGV 0x17 response is null");
}
if (qryRobotRunStatusRsp.robotLocalizationState == 0) {
getProcessModel().setCommAdapterConnected(false);
throw new RuntimeException("AGV定位失败请执行手动定位");
}
else if (qryRobotRunStatusRsp.robotLocalizationState == 2) {
getProcessModel().setCommAdapterConnected(false);
throw new RuntimeException("AGV定位中,请稍后再试");
}
//5 切换成自动模式命令码0x03变量NaviControl 修改为1
System.out.println();
System.out.println("=================---initAGV_0x03-----111111");
SwitchAutomaticMode.command();
getProcessModel().setState(Vehicle.State.IDLE);
//打开通讯适配器连接
getProcessModel().setCommAdapterConnected(true);
} else {
//0xAF获取AGV状态
System.out.println("=================---initAGV_0xAF");
QueryRobotStatusRsp qryRobotStatusRsp = QryRobotStatus.command();
if (qryRobotStatusRsp == null) {
getProcessModel().setCommAdapterConnected(false);
throw new RuntimeException("initAGV 0xAF response is null");
}
//开启0xAF订阅
sub0xAF();
//开启0xB0订阅
sub0xB0();
//1 切换定位为手动模式命令码0x03变量NaviControl 修改为0
System.out.println();
System.out.println("=================---initAGV_0x03-----000000");
SwitchManualMode.command();
getProcessModel().setState(Vehicle.State.UNAVAILABLE);
//设置AGV最后一个点位置
String lastPassPointId = (qryRobotStatusRsp.locationStatusInfo.lastPassPointId).toString();
initVehiclePosition(lastPassPointId);
//2 执行机器人手动定位 命令码0x14
System.out.println("=================---initAGV_0x14");
LocationStatusInfo locationStatusInfo = qryRobotStatusRsp.locationStatusInfo;
double agvX = locationStatusInfo.globalX;
double agvY = locationStatusInfo.globalY;
double agvAngle = locationStatusInfo.absoluteDirecAngle;
ManualPosition.command(agvX, agvY, agvAngle);
throw new RuntimeException("AGV定位失败执行手动定位中");
//3 查询机器人运行状态命令码0x17等待机器人定位状态为定位完成
System.out.println("=================---initAGV_0x17");
QueryRobotRunStatusRsp qryRobotRunStatusRsp = QryRobotRunStatus.command();
} else if (qryRobotRunStatusRsp.robotLocalizationState == 2) {
throw new RuntimeException("AGV定位中");
if (qryRobotRunStatusRsp == null) {
getProcessModel().setCommAdapterConnected(false);
throw new RuntimeException("initAGV 0x17 response is null");
}
if (qryRobotRunStatusRsp.robotLocalizationState == 0) {
getProcessModel().setCommAdapterConnected(false);
throw new RuntimeException("AGV定位失败执行手动定位中");
}
else if (qryRobotRunStatusRsp.robotLocalizationState == 2) {
getProcessModel().setCommAdapterConnected(false);
throw new RuntimeException("AGV定位中,请稍后再试");
}
//4 确认初始位置命令码0x1F
System.out.println("=================---initAGV_0x1F");
ConfirmRelocation.commnd();
//5 切换成自动模式命令码0x03变量NaviControl 修改为1
System.out.println("=================---initAGV_0x03-----111111");
SwitchAutomaticMode.command();
getProcessModel().setState(Vehicle.State.IDLE);
//打开通讯适配器连接
getProcessModel().setCommAdapterConnected(true);
}
}
//4 确认初始位置命令码0x1F
ConfirmRelocation.commnd();
private void sub0xAF(){
messageProcessingPool.submit(() -> {
Date now = new Date();
sub0xafDeadline = now.getTime() + 10000;
SubRobotStatue.command();
});
}
//5 切换成自动模式命令码0x03变量NaviControl 修改为1
SwitchAutomaticMode.command();
//打开通讯适配器连接
getProcessModel().setCommAdapterConnected(true);
private void sub0xB0(){
messageProcessingPool.submit(() -> {
Date now = new Date();
sub0xb0Deadline = now.getTime() + 10000;
SubCargoStatus.command();
});
}
}

View File

@ -58,6 +58,11 @@ public class LoopbackVehicleModelTO
return singleStepModeEnabled;
}
/**
* 设置单步模式已启用.
* @param singleStepModeEnabled 启用单步模式
* @return LoopbackVehicleModelTO
*/
public LoopbackVehicleModelTO setSingleStepModeEnabled(boolean singleStepModeEnabled) {
this.singleStepModeEnabled = singleStepModeEnabled;
return this;
@ -67,6 +72,11 @@ public class LoopbackVehicleModelTO
return loadOperation;
}
/**
* 设置装载操作.
* @param loadOperation 状态
* @return LoopbackVehicleModelTO
*/
public LoopbackVehicleModelTO setLoadOperation(String loadOperation) {
this.loadOperation = loadOperation;
return this;
@ -76,6 +86,11 @@ public class LoopbackVehicleModelTO
return unloadOperation;
}
/**
* 设置卸载操作.
* @param unloadOperation 状态
* @return LoopbackVehicleModelTO
*/
public LoopbackVehicleModelTO setUnloadOperation(String unloadOperation) {
this.unloadOperation = unloadOperation;
return this;
@ -85,6 +100,11 @@ public class LoopbackVehicleModelTO
return operatingTime;
}
/**
* 设置运行时间.
* @param operatingTime 时间戳
* @return LoopbackVehicleModelTO
*/
public LoopbackVehicleModelTO setOperatingTime(int operatingTime) {
this.operatingTime = operatingTime;
return this;
@ -94,6 +114,11 @@ public class LoopbackVehicleModelTO
return maxAcceleration;
}
/**
* 设置最大加速度.
* @param maxAcceleration
* @return LoopbackVehicleModelTO
*/
public LoopbackVehicleModelTO setMaxAcceleration(int maxAcceleration) {
this.maxAcceleration = maxAcceleration;
return this;
@ -103,6 +128,11 @@ public class LoopbackVehicleModelTO
return maxDeceleration;
}
/**
* 设置最大减速.
* @param maxDeceleration
* @return LoopbackVehicleModelTO
*/
public LoopbackVehicleModelTO setMaxDeceleration(int maxDeceleration) {
this.maxDeceleration = maxDeceleration;
return this;
@ -112,6 +142,11 @@ public class LoopbackVehicleModelTO
return maxFwdVelocity;
}
/**
* 设置最大前驱速度.
* @param maxFwdVelocity
* @return LoopbackVehicleModelTO
*/
public LoopbackVehicleModelTO setMaxFwdVelocity(int maxFwdVelocity) {
this.maxFwdVelocity = maxFwdVelocity;
return this;
@ -121,6 +156,11 @@ public class LoopbackVehicleModelTO
return maxRevVelocity;
}
/**
* 设置最大速度.
* @param maxRevVelocity
* @return LoopbackVehicleModelTO
*/
public LoopbackVehicleModelTO setMaxRevVelocity(int maxRevVelocity) {
this.maxRevVelocity = maxRevVelocity;
return this;
@ -130,6 +170,11 @@ public class LoopbackVehicleModelTO
return vehiclePaused;
}
/**
* 将车辆设置为暂停.
* @param vehiclePaused
* @return LoopbackVehicleModelTO
*/
public LoopbackVehicleModelTO setVehiclePaused(boolean vehiclePaused) {
this.vehiclePaused = vehiclePaused;
return this;

View File

@ -18,7 +18,7 @@ public interface GuestUserCredentials {
/**
* 主机IP
*/
String IP = "192.168.0.106";
String IP = "192.168.124.111";
/**
* 内核开放端口
*/

View File

@ -53,5 +53,9 @@ public interface LoopbackAdapterConstants {
* AGV 端口
*/
String AGV_PORT = "AGV:PORT";
/**
* 定制点位类型1=WMS请求点位
*/
String POINT_TYPE = "tcs:point";
}

View File

@ -11,133 +11,136 @@ import org.opentcs.kc.common.byteutils.ByteUtils;
public class CaffeineUtil {
/**
* 缓存的最大容量
*/
private static final int MAXIMUM_SIZE = 1000;
/**
* 缓存的最大容量
*/
private static final int MAXIMUM_SIZE = 1000;
/**
* 缓存项的写入后过期时间
*/
private static final int EXPIRE_AFTER_WRITE_DURATION = 10;
/**
* 缓存项的写入后过期时间
*/
private static final int EXPIRE_AFTER_WRITE_DURATION = 10;
/**
* 过期时间单位分钟
*/
private static final TimeUnit EXPIRE_AFTER_WRITE_TIMEUNIT = TimeUnit.MINUTES;
/**
* 过期时间单位分钟
*/
private static final TimeUnit EXPIRE_AFTER_WRITE_TIMEUNIT = TimeUnit.MINUTES;
private static Cache<String, Object> cache;
private static Cache<String, AtomicInteger> cacheUUID;
private static Cache<String, Object> cache;
private static Cache<String, AtomicInteger> cacheUUID;
/**
* 初始化Caffeine缓存配置
*/
static {
//todo https://github.com/ben-manes/caffeine/wiki 研究一下然后升级一下版本
cache = Caffeine.newBuilder()
.maximumSize(MAXIMUM_SIZE)
.expireAfterWrite(EXPIRE_AFTER_WRITE_DURATION, EXPIRE_AFTER_WRITE_TIMEUNIT)
.build();
/**
* 初始化Caffeine缓存配置
*/
static {
//todo https://github.com/ben-manes/caffeine/wiki 研究一下然后升级一下版本
cache = Caffeine.newBuilder()
.maximumSize(MAXIMUM_SIZE)
.expireAfterWrite(EXPIRE_AFTER_WRITE_DURATION, EXPIRE_AFTER_WRITE_TIMEUNIT)
.build();
cacheUUID = Caffeine.newBuilder()
.maximumSize(10)
.expireAfterWrite(Long.MAX_VALUE, EXPIRE_AFTER_WRITE_TIMEUNIT)
.build();
cacheUUID = Caffeine.newBuilder()
.maximumSize(10)
.expireAfterWrite(Long.MAX_VALUE, EXPIRE_AFTER_WRITE_TIMEUNIT)
.build();
}
public static void main(String[] args) {
byte[] a = getUUID();
byte[] b = getUUID();
byte[] d = ByteUtils.intToBytes(300);
byte[] c = ByteUtils.intToBytes(32000);
//todo int 转两个字节长度
System.out.println(Arrays.asList(getUUID()));
}
public static synchronized byte[] getUUID() {
AtomicInteger uuid = cacheUUID.getIfPresent("UUID");
if (uuid == null) {
//transationId 从1 开始0留给心跳变量这样就固定报文了
cacheUUID.put("UUID", new AtomicInteger(1));
return ByteUtils.intToBytes(1);
}
public static void main(String[] args) {
byte[] a = getUUID();
byte[] b = getUUID();
byte[] d = ByteUtils.intToBytes(300);
byte[] c = ByteUtils.intToBytes(32000);
//todo int 转两个字节长度
System.out.println(Arrays.asList(getUUID()));
else {
if (uuid.get() >= 32000) {
cacheUUID.put("UUID", new AtomicInteger(1));
return ByteUtils.intToBytes(1);
}
else {
return ByteUtils.intToBytes(uuid.incrementAndGet());
}
}
}
public static synchronized byte[] getUUID() {
AtomicInteger uuid = cacheUUID.getIfPresent("UUID");
if(uuid == null){
//transationId 从1 开始0留给心跳变量这样就固定报文了
cacheUUID.put("UUID",new AtomicInteger(1));
return ByteUtils.intToBytes(1);
}else {
if(uuid.get() >= 32000){
cacheUUID.put("UUID",new AtomicInteger(1));
return ByteUtils.intToBytes(1);
}else {
return ByteUtils.intToBytes(uuid.incrementAndGet());
}
}
public static synchronized byte[] getUUIDAGV() {
AtomicInteger agvuuid = cacheUUID.getIfPresent("AGVUUID");
if (agvuuid == null) {
//transationId 从1 开始0留给心跳变量这样就固定报文了
cacheUUID.put("AGVUUID", new AtomicInteger(1));
return ByteUtils.intToBytesS(1);
}
public static synchronized byte[] getUUIDAGV() {
AtomicInteger agvuuid = cacheUUID.getIfPresent("AGVUUID");
if(agvuuid == null){
//transationId 从1 开始0留给心跳变量这样就固定报文了
cacheUUID.put("AGVUUID",new AtomicInteger(1));
return ByteUtils.intToBytesS(1);
}else {
if(agvuuid.get() >= 32000){
cacheUUID.put("AGVUUID",new AtomicInteger(1));
return ByteUtils.intToBytesS(1);
}else {
return ByteUtils.intToBytesS(agvuuid.incrementAndGet());
}
}
else {
if (agvuuid.get() >= 32000) {
cacheUUID.put("AGVUUID", new AtomicInteger(1));
return ByteUtils.intToBytesS(1);
}
else {
return ByteUtils.intToBytesS(agvuuid.incrementAndGet());
}
}
}
/**
* 获取缓存值
*
* @param key 缓存键
* @return 缓存值
*/
public static Object get(String key) {
return cache.getIfPresent(key);
}
/**
* 获取缓存值
*
* @param key 缓存键
* @return 缓存值
*/
public static Object get(String key) {
return cache.getIfPresent(key);
}
/**
* 设置缓存值
*
* @param key 缓存键
* @param value 缓存值
*/
public static void put(String key, Object value) {
cache.put(key, value);
}
/**
* 设置缓存值
*
* @param key 缓存键
* @param value 缓存值
*/
public static void put(String key, Object value) {
cache.put(key, value);
}
/**
* 移除缓存项
*
* @param key 缓存键
*/
public static void remove(String key) {
cache.invalidate(key);
}
/**
* 移除缓存项
*
* @param key 缓存键
*/
public static void remove(String key) {
cache.invalidate(key);
}
/**
* 清空缓存
*/
public static void clear() {
cache.invalidateAll();
}
/**
* 清空缓存
*/
public static void clear() {
cache.invalidateAll();
}
/**
* 获取缓存中的所有值
*
* @return 缓存中的所有值集合
*/
public static Collection<Object> getAllValues() {
return cache.asMap().values();
}
/**
* 获取缓存中的所有值
*
* @return 缓存中的所有值集合
*/
public static Collection<Object> getAllValues() {
return cache.asMap().values();
}
/**
* 清空缓存中的所有值
*/
public static void removeAllValues() {
cache.invalidateAll();
}
/**
* 清空缓存中的所有值
*/
public static void removeAllValues() {
cache.invalidateAll();
}
}

View File

@ -6,34 +6,35 @@ package org.opentcs.kc.common;
* 2017年3月30日 下午7:05:54
*/
public interface Const {
/**
* 服务器地址
*/
public static final String SERVER = "127.0.0.1";
/**
* 服务器地址
*/
public static final String SERVER = "127.0.0.1";
public static void main(String[] args) {
String s = "123, 34, 104, 101, 97, 100, 101, 114, 34, 58, 123, 34, 116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 73, 100, 34, 58, 34, 50, 48, 50, 52, 48, 49, 48, 50, 49, 53, 52, 48, 50, 55, 95, 51, 100, 56, 49, 99, 34, 44, 34, 109, 101, 115, 115, 97, 103, 101, 84, 121, 112, 101, 34, 58, 51, 44, 34, 109, 101, 115, 115, 97, 103, 101, 78, 97, 109, 101, 34, 58, 34, 72, 101, 97, 114, 116, 66, 101, 97, 116, 34, 44, 34, 115, 101, 110, 100, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 58, 34, 50, 48, 50, 52, 45, 48, 49, 45, 48, 50, 32, 49, 53, 58, 52, 48, 58, 50, 55, 34, 125, 44, 34, 98, 111, 100, 121, 34, 58, 34, 49, 34, 44, 34, 114, 101, 116, 117, 114, 110, 115, 34, 58, 110, 117, 108, 108, 125";
String[] split = s.split(",");
System.out.println(split.length);
}
public static void main(String[] args) {
String s
= "123, 34, 104, 101, 97, 100, 101, 114, 34, 58, 123, 34, 116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 73, 100, 34, 58, 34, 50, 48, 50, 52, 48, 49, 48, 50, 49, 53, 52, 48, 50, 55, 95, 51, 100, 56, 49, 99, 34, 44, 34, 109, 101, 115, 115, 97, 103, 101, 84, 121, 112, 101, 34, 58, 51, 44, 34, 109, 101, 115, 115, 97, 103, 101, 78, 97, 109, 101, 34, 58, 34, 72, 101, 97, 114, 116, 66, 101, 97, 116, 34, 44, 34, 115, 101, 110, 100, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 58, 34, 50, 48, 50, 52, 45, 48, 49, 45, 48, 50, 32, 49, 53, 58, 52, 48, 58, 50, 55, 34, 125, 44, 34, 98, 111, 100, 121, 34, 58, 34, 49, 34, 44, 34, 114, 101, 116, 117, 114, 110, 115, 34, 58, 110, 117, 108, 108, 125";
String[] split = s.split(",");
System.out.println(split.length);
}
/**
* 监听端口
*/
public static final int PORT = 6789;
//public static final int PORT = 9000;
/**
* 监听端口
*/
public static final int PORT = 6789;
//public static final int PORT = 9000;
/**
* 心跳超时时间
*/
public static final int TIMEOUT = 5000;
/**
* 心跳超时时间
*/
public static final int TIMEOUT = 5000;
public static final int NEED_REPLY_TYPE = 1;
public static final int NO_REPLY_TYPE = 2;
public static final int HEARTBEAT_TYPE = 3;
public static final int NEED_REPLY_TYPE = 1;
public static final int NO_REPLY_TYPE = 2;
public static final int HEARTBEAT_TYPE = 3;
public static final Integer REQUEST_TYPE = 1;
public static final Integer RESPONSE_TYPE = 2;
public static final Integer REQUEST_TYPE = 1;
public static final Integer RESPONSE_TYPE = 2;
}

View File

@ -3,43 +3,38 @@ package org.opentcs.kc.common;
import java.util.Arrays;
/**
* @Desc: "通用的数据传输底层类"
* @Author: caixiang
* @DATE: 2022/10/18 16:22
*/
public class Package {
private byte[] body;
private String transationId;
private byte[] body;
private String transationId;
public Package(byte[] body, String transationId) {
this.body = body;
this.transationId = transationId;
}
public Package(byte[] body, String transationId) {
this.body = body;
this.transationId = transationId;
}
public byte[] getBody() {
return body;
}
public byte[] getBody() {
return body;
}
public void setBody(byte[] body) {
this.body = body;
}
public void setBody(byte[] body) {
this.body = body;
}
public String getTransationId() {
return transationId;
}
public String getTransationId() {
return transationId;
}
public void setTransationId(String transationId) {
this.transationId = transationId;
}
public void setTransationId(String transationId) {
this.transationId = transationId;
}
@Override
public String toString() {
return "Package{" +
"body=" + Arrays.toString(body) +
", transationId='" + transationId + '\'' +
'}';
}
@Override
public String toString() {
return "Package{" +
"body=" + Arrays.toString(body) +
", transationId='" + transationId + '\'' +
'}';
}
}

View File

@ -1,64 +1,66 @@
/*
Copyright 2016 S7connector members (github.com/s7connector)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
* Copyright 2016 S7connector members (github.com/s7connector)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.opentcs.kc.common;
/**
* The Class S7Exception is an exception related to S7 Communication
*/
public final class ParseDataException extends RuntimeException {
public final class ParseDataException
extends
RuntimeException {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = -4761415733559374116L;
/** The Constant serialVersionUID. */
private static final long serialVersionUID = -4761415733559374116L;
/**
* Instantiates a new s7 exception.
*/
public ParseDataException() {
}
/**
* Instantiates a new s7 exception.
*/
public ParseDataException() {
}
/**
* Instantiates a new s7 exception.
*
* @param message
* the message
*/
public ParseDataException(final String message) {
super(message);
}
/**
* Instantiates a new s7 exception.
*
* @param message
* the message
*/
public ParseDataException(final String message) {
super(message);
}
/**
* Instantiates a new s7 exception.
*
* @param message
* the message
* @param cause
* the cause
*/
public ParseDataException(final String message, final Throwable cause) {
super(message, cause);
}
/**
* Instantiates a new s7 exception.
*
* @param message
* the message
* @param cause
* the cause
*/
public ParseDataException(final String message, final Throwable cause) {
super(message, cause);
}
/**
* Instantiates a new s7 exception.
*
* @param cause
* the cause
*/
public ParseDataException(final Throwable cause) {
super(cause);
}
/**
* Instantiates a new s7 exception.
*
* @param cause
* the cause
*/
public ParseDataException(final Throwable cause) {
super(cause);
}
}

View File

@ -1,49 +1,44 @@
package org.opentcs.kc.common;
/**
* @Desc: "通用的数据传输底层类"
* @Author: caixiang
* @DATE: 2022/10/18 16:22
*/
public class RcvPackage {
private boolean isOk;
private Object value;
private String content;
private boolean isOk;
private Object value;
private String content;
public RcvPackage(boolean isOk, Object value, String content) {
this.isOk = isOk;
this.value = value;
this.content = content;
}
public RcvPackage() {
}
public RcvPackage(boolean isOk, Object value, String content) {
this.isOk = isOk;
this.value = value;
this.content = content;
}
public boolean isOk() {
return isOk;
}
public RcvPackage() {
}
public void setValue(Object value) {
this.value = value;
}
public boolean isOk() {
return isOk;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public String getContent() {
return content;
}
public Object getValue() {
return value;
}
public String getContent() {
return content;
}
@Override
public String toString() {
return "RcvPackage{" +
"isOk=" + isOk +
", value=" + value +
", content='" + content + '\'' +
'}';
}
@Override
public String toString() {
return "RcvPackage{" +
"isOk=" + isOk +
", value=" + value +
", content='" + content + '\'' +
'}';
}
}

View File

@ -6,73 +6,60 @@ import java.time.format.DateTimeFormatter;
import java.util.Random;
import java.util.UUID;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2022/10/24 16:27
*/
public class Utils {
/**
* java生成随机数字15位数
* @return
*/
public static String getTransationId() {
String val = String.valueOf(System.currentTimeMillis());
Random random = new Random();
for (int i = 0; i < 2; i++) {
val += String.valueOf(random.nextInt(10));
}
return val;
public static String getTransationId() {
String val = String.valueOf(System.currentTimeMillis());
Random random = new Random();
for (int i = 0; i < 2; i++) {
val += String.valueOf(random.nextInt(10));
}
return val;
}
/**
* 获取指定长度的随机数
* (获取指定长度uuid)
*
* @return
*/
public static String getUUID(int len) {
if (0 >= len) {
return null;
}
/**
* 获取指定长度的随机数
* (获取指定长度uuid)
*
* @return
*/
public static String getUUID(int len)
{
if(0 >= len)
{
return null;
}
String uuid = getUUID();
StringBuffer str = new StringBuffer();
String uuid = getUUID();
StringBuffer str = new StringBuffer();
for (int i = 0; i < len; i++)
{
str.append(uuid.charAt(i));
}
return str.toString();
for (int i = 0; i < len; i++) {
str.append(uuid.charAt(i));
}
/**
*32位默认长度的uuid
* (获取32位uuid)
*
* @return
*/
public static String getUUID()
{
return UUID.randomUUID().toString().replace("-", "");
return str.toString();
}
/**
* 32位默认长度的uuid
* (获取32位uuid)
*
* @return
*/
public static String getUUID() {
return UUID.randomUUID().toString().replace("-", "");
}
/*
* type:
* 1.返回的是这种格式2021-08-16 15:00:05
* 2.返回的是这种格式20210816150021
*/
public static String getNowDate(Integer type) {
if (type == 1) {
return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
/*
type:
1.返回的是这种格式2021-08-16 15:00:05
2.返回的是这种格式20210816150021
*/
public static String getNowDate(Integer type){
if(type==1){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}else {
return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
}
else {
return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
}
}
}

View File

@ -4,346 +4,356 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2022/4/1 17:32
*/
//对数字和字节进行转换 假设数据存储是以大端模式存储的
// byte: 字节类型 占8位二进制 00000000
// char: 字符类型 占2个字节 16位二进制 byte[0] byte[1]
// int : 整数类型 占4个字节 32位二进制 byte[0] byte[1] byte[2] byte[3]
// long: 长整数类型 占8个字节 64位二进制 byte[0] byte[1] byte[2] byte[3] byte[4] byte[5]
// long: 长整数类型 占8个字节 64位二进制 byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7]
// float: 浮点数(小数) 占4个字节 32位二进制 byte[0] byte[1] byte[2] byte[3]
// double: 双精度浮点数(小数) 占8个字节 64位二进制 byte[0] byte[1] byte[2] byte[3] byte[4]byte[5] byte[6] byte[7]
// 对数字和字节进行转换 假设数据存储是以大端模式存储的
// byte: 字节类型 占8位二进制 00000000
// char: 字符类型 占2个字节 16位二进制 byte[0] byte[1]
// int : 整数类型 占4个字节 32位二进制 byte[0] byte[1] byte[2] byte[3]
// long: 长整数类型 占8个字节 64位二进制 byte[0] byte[1] byte[2] byte[3] byte[4] byte[5]
// long: 长整数类型 占8个字节 64位二进制 byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7]
// float: 浮点数(小数) 占4个字节 32位二进制 byte[0] byte[1] byte[2] byte[3]
// double: 双精度浮点数(小数) 占8个字节 64位二进制 byte[0] byte[1] byte[2] byte[3] byte[4]byte[5] byte[6] byte[7]
public class ByteUtil {
/**
* int转byte
*
* @param intValue int值
* @return byte值
*/
public static byte intToByte(int intValue) {
return (byte) intValue;
/**
* int转byte
*
* @param intValue int值
* @return byte值
*/
public static byte intToByte(int intValue) {
return (byte) intValue;
}
public static byte intTo1Byte(int intValue) {
ByteBuffer byteBuffer = ByteBuffer.allocate(4);
byteBuffer.putInt(intValue);
byte[] byteArray = byteBuffer.array();
return byteArray[3]; // 取低字节
}
/**
* byte转无符号int
*
* @param byteValue byte值
* @return 无符号int值
* @since 3.2.0
*/
public static int byteToUnsignedInt(byte byteValue) {
// Java 总是把 byte 当做有符处理我们可以通过将其和 0xFF 进行二进制与得到它的无符值
return byteValue & 0xFF;
}
/**
*
* 字符串转成16个字节的byte[] 不足16个字节前面填充0
*/
public static byte[] stringTo16Byte(String input) {
byte[] originalBytes = input.getBytes(StandardCharsets.UTF_8);
ByteBuffer buffer = ByteBuffer.allocate(16);
buffer.put(originalBytes);
buffer.put(new byte[16 - originalBytes.length]);
return buffer.array();
}
/**
* byte数组转short<br>
* 默认以小端序转换
*
* @param bytes byte数组
* @return short值
*/
public static short bytesToShort(byte[] bytes) {
return bytesToShort(bytes, ByteOrder.LITTLE_ENDIAN);
}
/**
* byte数组转short<br>
* 自定义端序
*
* @param bytes byte数组
* @param byteOrder 端序
* @return short值
*/
public static short bytesToShort(byte[] bytes, ByteOrder byteOrder) {
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
//小端模式数据的高字节保存在内存的高地址中而数据的低字节保存在内存的低地址中
return (short) (bytes[0] & 0xff | (bytes[1] & 0xff) << Byte.SIZE);
}
else {
return (short) (bytes[1] & 0xff | (bytes[0] & 0xff) << Byte.SIZE);
}
}
/**
* short转byte数组<br>
* 默认以小端序转换
*
* @param shortValue short值
* @return byte数组
*/
public static byte[] shortToBytes(short shortValue) {
return shortToBytes(shortValue, ByteOrder.LITTLE_ENDIAN);
}
/**
* short转byte数组<br>
* 自定义端序
*
* @param shortValue short值
* @param byteOrder 端序
* @return byte数组
*/
public static byte[] shortToBytes(short shortValue, ByteOrder byteOrder) {
byte[] b = new byte[Short.BYTES];
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
b[0] = (byte) (shortValue & 0xff);
b[1] = (byte) ((shortValue >> Byte.SIZE) & 0xff);
}
else {
b[1] = (byte) (shortValue & 0xff);
b[0] = (byte) ((shortValue >> Byte.SIZE) & 0xff);
}
return b;
}
/**
* byte[]转int值<br>
* 默认以小端序转换
*
* @param bytes byte数组
* @return int值
*/
public static int bytesToInt(byte[] bytes) {
return bytesToInt(bytes, ByteOrder.LITTLE_ENDIAN);
}
/**
* byte[]转int值<br>
* 自定义端序
*
* @param bytes byte数组
* @param byteOrder 端序
* @return int值
*/
public static int bytesToInt(byte[] bytes, ByteOrder byteOrder) {
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
return bytes[0] & 0xFF | //
(bytes[1] & 0xFF) << 8 | //
(bytes[2] & 0xFF) << 16 | //
(bytes[3] & 0xFF) << 24; //
}
else {
return bytes[3] & 0xFF | //
(bytes[2] & 0xFF) << 8 | //
(bytes[1] & 0xFF) << 16 | //
(bytes[0] & 0xFF) << 24; //
}
public static byte intTo1Byte(int intValue) {
ByteBuffer byteBuffer = ByteBuffer.allocate(4);
byteBuffer.putInt(intValue);
byte[] byteArray = byteBuffer.array();
return byteArray[3]; // 取低字节
}
}
/**
* byte转无符号int
*
* @param byteValue byte值
* @return 无符号int值
* @since 3.2.0
*/
public static int byteToUnsignedInt(byte byteValue) {
// Java 总是把 byte 当做有符处理我们可以通过将其和 0xFF 进行二进制与得到它的无符值
return byteValue & 0xFF;
}
/**
* int转byte数组<br>
* 默认以小端序转换
*
* @param intValue int值
* @return byte数组
*/
public static byte[] intToBytes(int intValue) {
return intToBytes(intValue, ByteOrder.LITTLE_ENDIAN);
}
/**
*
* 字符串转成16个字节的byte[] 不足16个字节前面填充0
* */
public static byte[] stringTo16Byte(String input) {
byte[] originalBytes = input.getBytes(StandardCharsets.UTF_8);
ByteBuffer buffer = ByteBuffer.allocate(16);
buffer.put(originalBytes);
buffer.put(new byte[16 - originalBytes.length]);
return buffer.array();
}
/**
* int转byte数组<br>
* 自定义端序
*
* @param intValue int值
* @param byteOrder 端序
* @return byte数组
*/
public static byte[] intToBytes(int intValue, ByteOrder byteOrder) {
/**
* byte数组转short<br>
* 默认以小端序转换
*
* @param bytes byte数组
* @return short值
*/
public static short bytesToShort(byte[] bytes) {
return bytesToShort(bytes, ByteOrder.LITTLE_ENDIAN);
}
/**
* byte数组转short<br>
* 自定义端序
*
* @param bytes byte数组
* @param byteOrder 端序
* @return short值
*/
public static short bytesToShort(byte[] bytes, ByteOrder byteOrder) {
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
//小端模式数据的高字节保存在内存的高地址中而数据的低字节保存在内存的低地址中
return (short) (bytes[0] & 0xff | (bytes[1] & 0xff) << Byte.SIZE);
} else {
return (short) (bytes[1] & 0xff | (bytes[0] & 0xff) << Byte.SIZE);
}
}
/**
* short转byte数组<br>
* 默认以小端序转换
*
* @param shortValue short值
* @return byte数组
*/
public static byte[] shortToBytes(short shortValue) {
return shortToBytes(shortValue, ByteOrder.LITTLE_ENDIAN);
}
/**
* short转byte数组<br>
* 自定义端序
*
* @param shortValue short值
* @param byteOrder 端序
* @return byte数组
*/
public static byte[] shortToBytes(short shortValue, ByteOrder byteOrder) {
byte[] b = new byte[Short.BYTES];
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
b[0] = (byte) (shortValue & 0xff);
b[1] = (byte) ((shortValue >> Byte.SIZE) & 0xff);
} else {
b[1] = (byte) (shortValue & 0xff);
b[0] = (byte) ((shortValue >> Byte.SIZE) & 0xff);
}
return b;
}
/**
* byte[]转int值<br>
* 默认以小端序转换
*
* @param bytes byte数组
* @return int值
*/
public static int bytesToInt(byte[] bytes) {
return bytesToInt(bytes, ByteOrder.LITTLE_ENDIAN);
}
/**
* byte[]转int值<br>
* 自定义端序
*
* @param bytes byte数组
* @param byteOrder 端序
* @return int值
*/
public static int bytesToInt(byte[] bytes, ByteOrder byteOrder) {
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
return bytes[0] & 0xFF | //
(bytes[1] & 0xFF) << 8 | //
(bytes[2] & 0xFF) << 16 | //
(bytes[3] & 0xFF) << 24; //
} else {
return bytes[3] & 0xFF | //
(bytes[2] & 0xFF) << 8 | //
(bytes[1] & 0xFF) << 16 | //
(bytes[0] & 0xFF) << 24; //
}
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
return new byte[]{ //
(byte) (intValue & 0xFF), //
(byte) ((intValue >> 8) & 0xFF), //
(byte) ((intValue >> 16) & 0xFF), //
(byte) ((intValue >> 24) & 0xFF) //
};
}
/**
* int转byte数组<br>
* 默认以小端序转换
*
* @param intValue int值
* @return byte数组
*/
public static byte[] intToBytes(int intValue) {
return intToBytes(intValue, ByteOrder.LITTLE_ENDIAN);
else {
return new byte[]{ //
(byte) ((intValue >> 24) & 0xFF), //
(byte) ((intValue >> 16) & 0xFF), //
(byte) ((intValue >> 8) & 0xFF), //
(byte) (intValue & 0xFF) //
};
}
/**
* int转byte数组<br>
* 自定义端序
*
* @param intValue int值
* @param byteOrder 端序
* @return byte数组
*/
public static byte[] intToBytes(int intValue, ByteOrder byteOrder) {
}
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
return new byte[]{ //
(byte) (intValue & 0xFF), //
(byte) ((intValue >> 8) & 0xFF), //
(byte) ((intValue >> 16) & 0xFF), //
(byte) ((intValue >> 24) & 0xFF) //
};
/**
* long转byte数组<br>
* 默认以小端序转换<br>
* from:
* https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
* @param longValue long值
* @return byte数组
*/
public static byte[] longToBytes(long longValue) {
return longToBytes(longValue, ByteOrder.LITTLE_ENDIAN);
}
} else {
return new byte[]{ //
(byte) ((intValue >> 24) & 0xFF), //
(byte) ((intValue >> 16) & 0xFF), //
(byte) ((intValue >> 8) & 0xFF), //
(byte) (intValue & 0xFF) //
};
}
/**
* long转byte数组<br>
* 自定义端序<br>
* from:
* https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
* @param longValue long值
* @param byteOrder 端序
* @return byte数组
*/
public static byte[] longToBytes(long longValue, ByteOrder byteOrder) {
byte[] result = new byte[Long.BYTES];
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
for (int i = 0; i < result.length; i++) {
result[i] = (byte) (longValue & 0xFF);
longValue >>= Byte.SIZE;
}
}
else {
for (int i = (result.length - 1); i >= 0; i--) {
result[i] = (byte) (longValue & 0xFF);
longValue >>= Byte.SIZE;
}
}
return result;
}
/**
* byte数组转long<br>
* 默认以小端序转换<br>
* from:
* https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
* @param bytes byte数组
* @return long值
*/
public static long bytesToLong(byte[] bytes) {
return bytesToLong(bytes, ByteOrder.LITTLE_ENDIAN);
}
/**
* byte数组转long<br>
* 自定义端序<br>
* from:
* https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
* @param bytes byte数组
* @param byteOrder 端序
* @return long值
*/
public static long bytesToLong(byte[] bytes, ByteOrder byteOrder) {
long values = 0;
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
for (int i = (Long.BYTES - 1); i >= 0; i--) {
values <<= Byte.SIZE;
values |= (bytes[i] & 0xff);
}
}
else {
for (int i = 0; i < Long.BYTES; i++) {
values <<= Byte.SIZE;
values |= (bytes[i] & 0xff);
}
}
/**
* long转byte数组<br>
* 默认以小端序转换<br>
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
* @param longValue long值
* @return byte数组
*/
public static byte[] longToBytes(long longValue) {
return longToBytes(longValue, ByteOrder.LITTLE_ENDIAN);
}
return values;
}
/**
* long转byte数组<br>
* 自定义端序<br>
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
* @param longValue long值
* @param byteOrder 端序
* @return byte数组
*/
public static byte[] longToBytes(long longValue, ByteOrder byteOrder) {
byte[] result = new byte[Long.BYTES];
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
for (int i = 0; i < result.length; i++) {
result[i] = (byte) (longValue & 0xFF);
longValue >>= Byte.SIZE;
}
} else {
for (int i = (result.length - 1); i >= 0; i--) {
result[i] = (byte) (longValue & 0xFF);
longValue >>= Byte.SIZE;
}
}
return result;
}
/**
* double转byte数组<br>
* 默认以小端序转换<br>
*
* @param doubleValue double值
* @return byte数组
*/
public static byte[] doubleToBytes(double doubleValue) {
return doubleToBytes(doubleValue, ByteOrder.LITTLE_ENDIAN);
}
/**
* byte数组转long<br>
* 默认以小端序转换<br>
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
* @param bytes byte数组
* @return long值
*/
public static long bytesToLong(byte[] bytes) {
return bytesToLong(bytes, ByteOrder.LITTLE_ENDIAN);
}
/**
* double转byte数组<br>
* 自定义端序<br>
* from:
* https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
* @param doubleValue double值
* @param byteOrder 端序
* @return byte数组
*/
public static byte[] doubleToBytes(double doubleValue, ByteOrder byteOrder) {
return longToBytes(Double.doubleToLongBits(doubleValue), byteOrder);
}
/**
* byte数组转long<br>
* 自定义端序<br>
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
* @param bytes byte数组
* @param byteOrder 端序
* @return long值
*/
public static long bytesToLong(byte[] bytes, ByteOrder byteOrder) {
long values = 0;
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
for (int i = (Long.BYTES - 1); i >= 0; i--) {
values <<= Byte.SIZE;
values |= (bytes[i] & 0xff);
}
} else {
for (int i = 0; i < Long.BYTES; i++) {
values <<= Byte.SIZE;
values |= (bytes[i] & 0xff);
}
}
/**
* byte数组转Double<br>
* 默认以小端序转换<br>
*
* @param bytes byte数组
* @return long值
*/
public static double bytesToDouble(byte[] bytes) {
return bytesToDouble(bytes, ByteOrder.LITTLE_ENDIAN);
}
return values;
}
/**
* byte数组转double<br>
* 自定义端序<br>
*
* @param bytes byte数组
* @param byteOrder 端序
* @return long值
*/
public static double bytesToDouble(byte[] bytes, ByteOrder byteOrder) {
return Double.longBitsToDouble(bytesToLong(bytes, byteOrder));
}
/**
* double转byte数组<br>
* 默认以小端序转换<br>
*
* @param doubleValue double值
* @return byte数组
*/
public static byte[] doubleToBytes(double doubleValue) {
return doubleToBytes(doubleValue, ByteOrder.LITTLE_ENDIAN);
}
/**
* {@link Number}转换为
*
* @param number 数字
* @return bytes
*/
public static byte[] numberToBytes(Number number) {
return numberToBytes(number, ByteOrder.LITTLE_ENDIAN);
}
/**
* double转byte数组<br>
* 自定义端序<br>
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
*
* @param doubleValue double值
* @param byteOrder 端序
* @return byte数组
*/
public static byte[] doubleToBytes(double doubleValue, ByteOrder byteOrder) {
return longToBytes(Double.doubleToLongBits(doubleValue), byteOrder);
/**
* {@link Number}转换为
*
* @param number 数字
* @param byteOrder 端序
* @return bytes
*/
public static byte[] numberToBytes(Number number, ByteOrder byteOrder) {
if (number instanceof Double) {
return doubleToBytes((Double) number, byteOrder);
}
/**
* byte数组转Double<br>
* 默认以小端序转换<br>
*
* @param bytes byte数组
* @return long值
*/
public static double bytesToDouble(byte[] bytes) {
return bytesToDouble(bytes, ByteOrder.LITTLE_ENDIAN);
else if (number instanceof Long) {
return longToBytes((Long) number, byteOrder);
}
/**
* byte数组转double<br>
* 自定义端序<br>
*
* @param bytes byte数组
* @param byteOrder 端序
* @return long值
*/
public static double bytesToDouble(byte[] bytes, ByteOrder byteOrder) {
return Double.longBitsToDouble(bytesToLong(bytes, byteOrder));
else if (number instanceof Integer) {
return intToBytes((Integer) number, byteOrder);
}
/**
* {@link Number}转换为
*
* @param number 数字
* @return bytes
*/
public static byte[] numberToBytes(Number number) {
return numberToBytes(number, ByteOrder.LITTLE_ENDIAN);
else if (number instanceof Short) {
return shortToBytes((Short) number, byteOrder);
}
/**
* {@link Number}转换为
*
* @param number 数字
* @param byteOrder 端序
* @return bytes
*/
public static byte[] numberToBytes(Number number, ByteOrder byteOrder) {
if (number instanceof Double) {
return doubleToBytes((Double) number, byteOrder);
} else if (number instanceof Long) {
return longToBytes((Long) number, byteOrder);
} else if (number instanceof Integer) {
return intToBytes((Integer) number, byteOrder);
} else if (number instanceof Short) {
return shortToBytes((Short) number, byteOrder);
} else {
return doubleToBytes(number.doubleValue(), byteOrder);
}
else {
return doubleToBytes(number.doubleValue(), byteOrder);
}
}
}

View File

@ -1,21 +1,16 @@
package org.opentcs.kc.common.byteutils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2022/12/5 11:11
*/
public class CommonFunctions {
/**
* a 整除 b 如果有余数+1
* */
public static Integer exactDivision(Integer a,Integer b) {
/**
* a 整除 b 如果有余数+1
*/
public static Integer exactDivision(Integer a, Integer b) {
int c = a/b;
int c = a / b;
if(a%b!=0){
c = a/b+1;
}
return c;
if (a % b != 0) {
c = a / b + 1;
}
return c;
}
}

View File

@ -1,32 +1,27 @@
package org.opentcs.kc.common.byteutils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2024-05-08 11:02
*/
public class StringArrayStruc {
private String[] content;
private Integer strSize;
private String[] content;
private Integer strSize;
public StringArrayStruc(String[] content, Integer strSize) {
this.content = content;
this.strSize = strSize;
}
public StringArrayStruc(String[] content, Integer strSize) {
this.content = content;
this.strSize = strSize;
}
public String[] getContent() {
return content;
}
public String[] getContent() {
return content;
}
public void setContent(String[] content) {
this.content = content;
}
public void setContent(String[] content) {
this.content = content;
}
public Integer getStrSize() {
return strSize;
}
public Integer getStrSize() {
return strSize;
}
public void setStrSize(Integer strSize) {
this.strSize = strSize;
}
public void setStrSize(Integer strSize) {
this.strSize = strSize;
}
}

View File

@ -1,34 +1,34 @@
package org.opentcs.kc.common.enmuc;
public enum ModbusFC {
//心跳变量这个可以要求电控同事加一个不和业务关联只用于通讯
MB_HOLD_REG((byte) 0x03, (byte) 0x10),
Q_OUT((byte) 0x01, (byte) 0x05),
I_IN((byte) 0x02, null),
IW_IN((byte) 0x04, null),
;
//心跳变量这个可以要求电控同事加一个不和业务关联只用于通讯
MB_HOLD_REG((byte) 0x03, (byte) 0x10),
Q_OUT((byte) 0x01, (byte) 0x05),
I_IN((byte) 0x02, null),
IW_IN((byte) 0x04, null),
;
private Byte fread;
private Byte fwrite;
private Byte fread;
private Byte fwrite;
ModbusFC(Byte fread, Byte fwrite){
this.fread = fread;
this.fwrite = fwrite;
}
ModbusFC(Byte fread, Byte fwrite) {
this.fread = fread;
this.fwrite = fwrite;
}
public Byte getFread() {
return fread;
}
public Byte getFread() {
return fread;
}
public void setFread(Byte fread) {
this.fread = fread;
}
public void setFread(Byte fread) {
this.fread = fread;
}
public Byte getFwrite() {
return fwrite;
}
public Byte getFwrite() {
return fwrite;
}
public void setFwrite(Byte fwrite) {
this.fwrite = fwrite;
}
public void setFwrite(Byte fwrite) {
this.fwrite = fwrite;
}
}

View File

@ -5,61 +5,62 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Author: 蔡翔
* @Date: 2019/11/6 14:11
* @Version 1.0
*
* 重点
* AsyncFuture 这个类就是票据 刚拿到这个票据是没有信息的当done == true 的时候这个票据 上就自动有信息了
* 这个结果类设计的比较神奇
* 重点.
* AsyncFuture 这个类就是票据 刚拿到这个票据是没有信息的当done == true 的时候这个票据 上就自动有信息了.
* 这个结果类设计的比较神奇.
*/
public class AsyncFuture<Object> implements Future<Object> {
public class AsyncFuture<Object>
implements
Future<Object> {
private static final Logger logger = LoggerFactory.getLogger(AsyncFuture.class);
private volatile boolean done = false;
private Object oldRequest;
private Object result;
private static final Logger logger = LoggerFactory.getLogger(AsyncFuture.class);
private volatile boolean done = false;
private Object oldRequest;
private Object result;
public AsyncFuture(Object oldRequest) {
this.oldRequest = oldRequest;
}
public AsyncFuture() {
}
public void done(Object result){
synchronized (this){
this.result = result;
this.done = true;
//注意这里的notifyAll只能唤醒 本锁的所有 下的所有 wait(),这里的锁就是 AsyncFuture这个类
notifyAll();
}
public AsyncFuture(Object oldRequest) {
this.oldRequest = oldRequest;
}
public AsyncFuture() {
}
public void done(Object result) {
synchronized (this) {
this.result = result;
this.done = true;
//注意这里的notifyAll只能唤醒 本锁的所有 下的所有 wait(),这里的锁就是 AsyncFuture这个类
notifyAll();
}
}
@Override
public Object get(Long timeout) throws Exception {
return null;
}
@Override
public Object get(Long timeout)
throws Exception {
return null;
}
@Override
public Object get(Long timeout, String transationId) throws Exception {
synchronized (this){
//其实有 synchronize就相当于有一个阻塞队列当有线程执行了wait 方法就会把执行wait的这个线程给加入wait<Thread> 队列
//当有线程执行notify方法的时候就会往这个队列中取出一个或者多个Thread,取出来以后就能执行后续代码了
@Override
public Object get(Long timeout, String transationId)
throws Exception {
synchronized (this) {
//其实有 synchronize就相当于有一个阻塞队列当有线程执行了wait 方法就会把执行wait的这个线程给加入wait<Thread> 队列
//当有线程执行notify方法的时候就会往这个队列中取出一个或者多个Thread,取出来以后就能执行后续代码了
// System.out.println("get");
// 当线程执行wait()会把当前的锁释放然后让出CPU进入等待状态 wait()会立刻释放synchronizedobj中的obj锁以便其他线程可以执行obj.notify()
// * 当线程执行notify()/notifyAll()方法时会唤醒一个处于等待状态该对象锁的线程然后继续往下执行直到执行完退出对象锁锁住的区域synchronized修饰的代码块后再释放锁
this.wait(timeout);
if(!done){
//logger.error("T3 timeout , request information: "+oldRequest.toString());
SendedList.remove(transationId);
throw new Exception("T3 timeout , request information: "+oldRequest.toString());
}
//因为上面的代码是加锁的所以这里的代码也是加锁的
return result;
}
// 当线程执行wait()会把当前的锁释放然后让出CPU进入等待状态 wait()会立刻释放synchronizedobj中的obj锁以便其他线程可以执行obj.notify()
// * 当线程执行notify()/notifyAll()方法时会唤醒一个处于等待状态该对象锁的线程然后继续往下执行直到执行完退出对象锁锁住的区域synchronized修饰的代码块后再释放锁
this.wait(timeout);
if (!done) {
//logger.error("T3 timeout , request information: "+oldRequest.toString());
SendedList.remove(transationId);
throw new Exception("T3 timeout , request information: " + oldRequest.toString());
}
//因为上面的代码是加锁的所以这里的代码也是加锁的
return result;
}
}
}

View File

@ -1,14 +1,11 @@
package org.opentcs.kc.syn;
/**
* @Author: 蔡翔
* @Date: 2019/11/6 13:49
* @Version 1.0
*/
public interface Future<MQMessage> {
//别人调用我的时候我先给他们返回一个结果
MQMessage get(Long timeout) throws Exception;
//别人调用我的时候我先给他们返回一个结果
MQMessage get(Long timeout)
throws Exception;
MQMessage get(Long timeout, String transationId) throws Exception;
MQMessage get(Long timeout, String transationId)
throws Exception;
}

View File

@ -1,13 +1,6 @@
package org.opentcs.kc.syn;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2021/8/17 14:35
*/
public class Main {
// public static void main(String[] args) throws Exception {

View File

@ -4,12 +4,6 @@ package org.opentcs.kc.syn;
import org.opentcs.kc.common.CaffeineUtil;
import org.opentcs.kc.common.Package;
/**
* @Desc: "MES端 发送远程指令列表"
* @Author: caixiang
* @DATE: 2021/8/17 14:14
*/
public class SendedList {
// private static HashMap<String, AsyncFuture<MBPackage>> list = new HashMap<>();
// public static synchronized AsyncFuture<MQMessage> get(String transitionId){
@ -19,33 +13,33 @@ public class SendedList {
// list.put(transitionId,asyncFuture);
// }
public static synchronized AsyncFuture<Package> add(String transitionId, Package PackageRequest) {
AsyncFuture<Package> objectAsyncFuture = new AsyncFuture<>(PackageRequest);
//list.put(transitionId,objectAsyncFuture);
CaffeineUtil.put(transitionId,objectAsyncFuture);
return objectAsyncFuture;
public static synchronized AsyncFuture<Package> add(String transitionId, Package PackageRequest) {
AsyncFuture<Package> objectAsyncFuture = new AsyncFuture<>(PackageRequest);
//list.put(transitionId,objectAsyncFuture);
CaffeineUtil.put(transitionId, objectAsyncFuture);
return objectAsyncFuture;
}
//如果超时了那么让外部把这个key 给清除掉防止 list 过大
public static synchronized void remove(String transitionId) {
//list.remove(transitionId);
CaffeineUtil.remove(transitionId);
}
@SuppressWarnings("unchecked")
public static synchronized Boolean set(String transitionId, Package message) {
//AsyncFuture<MBPackage> mqMessageAsyncFuture = list.get(transitionId);
AsyncFuture<Package> mqMessageAsyncFuture = (AsyncFuture<Package>) CaffeineUtil.get(
transitionId
);
if (mqMessageAsyncFuture == null) {
return false;
}
//如果超时了那么让外部把这个key 给清除掉防止 list 过大
public static synchronized void remove(String transitionId) {
//list.remove(transitionId);
CaffeineUtil.remove(transitionId);
}
@SuppressWarnings("unchecked")
public static synchronized Boolean set(String transitionId, Package message) {
//AsyncFuture<MBPackage> mqMessageAsyncFuture = list.get(transitionId);
AsyncFuture<Package> mqMessageAsyncFuture = (AsyncFuture<Package>)CaffeineUtil.get(transitionId);
if(mqMessageAsyncFuture == null){
return false;
}
mqMessageAsyncFuture.done(message);
//清除 防止这个hashMap过大
CaffeineUtil.remove(transitionId);
return true;
}
mqMessageAsyncFuture.done(message);
//清除 防止这个hashMap过大
CaffeineUtil.remove(transitionId);
return true;
}
}

View File

@ -13,23 +13,24 @@ import java.util.Random;
* 类说明日志信息用String数组代替
*/
public class LogConst {
public final static int MONITOR_SIDE_PORT = 9998;
private static final String[] LOG_INFOS = {
"晨光微好,暖在夕阳。幽幽的巷子里,有着岁月酝酿的酒,愈久愈淳。一笔墨香,一盏明灯,记千帆过浪,数不尽的悲欢离合,待那水莲花开。",
"未来无期,静在安好。一剪寒梅,纷扰了岁月,抚平了伤痕。摆动的双桨,拨动了心的潭水。陌上花开,落一地秋霜,红枫染了红尘,便许了你十里红装。",
"离别的风,风干了月的泪。夜里的美",
"是梦的呢喃低语,挥走一片彩云,段落成珠。拂袖离去,乘鹤而来,古道西风瘦马。斑驳的树影中,眉目如画的眼,轻语告别了往事如烟。",
"无言的殇,几世沧桑,几生悲凉。一起剪了西窗烛,听了夜来风吹雨。昨日的叹息,今日的迷离,执一伞,存了一世一笔的温情。一曲长歌,唱尽了一世繁华,一世缘……",
"一世恋书,那便十里花开。一生凄凉,那便霜花十里。" ,
"一抹浓烟,便翻页书,展颜一笑,是时间带来遥远的梦。细数树的年轮,感受昨日惆怅,留一半清醒,梦一半叶落。在指尖流过的沙,海边浪花一朵朵,不相遇,才有不约而同。",
"这世俗,太多牵挂留在心间,一点朱砂泪,一曲相诗歌。岁月朦胧,梦醒了人生,风雨相容,演绎了一段风情。雪亦梦,雨亦梦,万张红纸从天洒来。惊动了山,撼动了天。" +
"一纸情愁,一指烟凉。一相思,一思量,水漫岸头,我们都有着自己不同的三生故事。迎一夜秋风,送一世暖阳,一切冰雪里的花开,是我一生的柔情。" +
"记忆中的短笛,有着清风须来的气息,那时我们面向大海,海风在耳边述说着大海边缘的温暖故事。安好一轮冷月,静好了一残红日,这便是我的语言,我的情丝。" +
"一漫山水,一段情,留在了岁月,拭去了风,晴雨清风,倒是暖阳拂绿草。" +
"这便,晨光微好,花开静好……"};
public final static int MONITOR_SIDE_PORT = 9998;
private static final String[] LOG_INFOS = {
"晨光微好,暖在夕阳。幽幽的巷子里,有着岁月酝酿的酒,愈久愈淳。一笔墨香,一盏明灯,记千帆过浪,数不尽的悲欢离合,待那水莲花开。",
"未来无期,静在安好。一剪寒梅,纷扰了岁月,抚平了伤痕。摆动的双桨,拨动了心的潭水。陌上花开,落一地秋霜,红枫染了红尘,便许了你十里红装。",
"离别的风,风干了月的泪。夜里的美",
"是梦的呢喃低语,挥走一片彩云,段落成珠。拂袖离去,乘鹤而来,古道西风瘦马。斑驳的树影中,眉目如画的眼,轻语告别了往事如烟。",
"无言的殇,几世沧桑,几生悲凉。一起剪了西窗烛,听了夜来风吹雨。昨日的叹息,今日的迷离,执一伞,存了一世一笔的温情。一曲长歌,唱尽了一世繁华,一世缘……",
"一世恋书,那便十里花开。一生凄凉,那便霜花十里。",
"一抹浓烟,便翻页书,展颜一笑,是时间带来遥远的梦。细数树的年轮,感受昨日惆怅,留一半清醒,梦一半叶落。在指尖流过的沙,海边浪花一朵朵,不相遇,才有不约而同。",
"这世俗,太多牵挂留在心间,一点朱砂泪,一曲相诗歌。岁月朦胧,梦醒了人生,风雨相容,演绎了一段风情。雪亦梦,雨亦梦,万张红纸从天洒来。惊动了山,撼动了天。" +
"一纸情愁,一指烟凉。一相思,一思量,水漫岸头,我们都有着自己不同的三生故事。迎一夜秋风,送一世暖阳,一切冰雪里的花开,是我一生的柔情。" +
"记忆中的短笛,有着清风须来的气息,那时我们面向大海,海风在耳边述说着大海边缘的温暖故事。安好一轮冷月,静好了一残红日,这便是我的语言,我的情丝。" +
"一漫山水,一段情,留在了岁月,拭去了风,晴雨清风,倒是暖阳拂绿草。" +
"这便,晨光微好,花开静好……"};
private final static Random r = new Random();
public static String getLogInfo(){
return LOG_INFOS[r.nextInt(LOG_INFOS.length-1)];
}
private final static Random r = new Random();
public static String getLogInfo() {
return LOG_INFOS[r.nextInt(LOG_INFOS.length - 1)];
}
}

View File

@ -19,56 +19,66 @@ import java.net.InetSocketAddress;
* 类说明日志的广播端 ( Client )
*/
public class LogEventBroadcaster {
private final EventLoopGroup group;
private final Bootstrap bootstrap;
private final EventLoopGroup group;
private final Bootstrap bootstrap;
public LogEventBroadcaster(InetSocketAddress remoteAddress) {
group = new NioEventLoopGroup();
bootstrap = new Bootstrap();
//引导该 NioDatagramChannel无连接的
bootstrap.group(group).channel(NioDatagramChannel.class)
//todo 设置 SO_BROADCAST 套接字选项option so_broadcast差异这里和单播 是有差异的
.option(ChannelOption.SO_BROADCAST, true)
.handler(new LogEventEncoder(remoteAddress));
public LogEventBroadcaster(InetSocketAddress remoteAddress) {
group = new NioEventLoopGroup();
bootstrap = new Bootstrap();
//引导该 NioDatagramChannel无连接的
bootstrap.group(group).channel(NioDatagramChannel.class)
//todo 设置 SO_BROADCAST 套接字选项option so_broadcast差异这里和单播 是有差异的
.option(ChannelOption.SO_BROADCAST, true)
.handler(new LogEventEncoder(remoteAddress));
}
public void run()
throws Exception {
//绑定 Channel
Channel ch = bootstrap.bind(0).sync().channel();
long count = 0;
//启动主处理循环模拟日志发送
for (;;) {
ch.writeAndFlush(
new LogMsg(
null, ++count,
LogConst.getLogInfo()
)
);
try {
//休眠 2 如果被中断则退出循环
Thread.sleep(2000);
}
catch (InterruptedException e) {
Thread.interrupted();
break;
}
}
}
public void run() throws Exception {
//绑定 Channel
Channel ch = bootstrap.bind(0).sync().channel();
long count = 0;
//启动主处理循环模拟日志发送
for (;;) {
ch.writeAndFlush(new LogMsg(null, ++count,
LogConst.getLogInfo()));
try {
//休眠 2 如果被中断则退出循环
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.interrupted();
break;
}
}
public void stop() {
group.shutdownGracefully();
}
public static void main(String[] args)
throws Exception {
//创建并启动一个新的 UdpQuestionSide 的实例
LogEventBroadcaster broadcaster = new LogEventBroadcaster(
//表明本应用发送的报文并没有一个确定的目的地也就是进行广播
//就是往这个网络下 所有主机发送数据往这些主机的 LogConst.MONITOR_SIDE_PORT端口 发送数据
//todo 这里的设置和 单播是有差异的
new InetSocketAddress(
"255.255.255.255",
LogConst.MONITOR_SIDE_PORT
)
);
try {
System.out.println("广播服务启动");
broadcaster.run();
}
public void stop() {
group.shutdownGracefully();
}
public static void main(String[] args) throws Exception {
//创建并启动一个新的 UdpQuestionSide 的实例
LogEventBroadcaster broadcaster = new LogEventBroadcaster(
//表明本应用发送的报文并没有一个确定的目的地也就是进行广播
//就是往这个网络下 所有主机发送数据往这些主机的 LogConst.MONITOR_SIDE_PORT端口 发送数据
//todo 这里的设置和 单播是有差异的
new InetSocketAddress("255.255.255.255",
LogConst.MONITOR_SIDE_PORT));
try {
System.out.println("广播服务启动");
broadcaster.run();
}
finally {
broadcaster.stop();
}
finally {
broadcaster.stop();
}
}
}

View File

@ -18,30 +18,38 @@ import java.util.List;
* 作者DarkKIng
* 类说明解码将DatagramPacket解码为实际的日志实体类
*/
public class LogEventDecoder extends MessageToMessageDecoder<DatagramPacket> {
public class LogEventDecoder
extends
MessageToMessageDecoder<DatagramPacket> {
@Override
protected void decode(ChannelHandlerContext ctx,
DatagramPacket datagramPacket, List<Object> out)
throws Exception {
//获取对 DatagramPacket 中的数据ByteBuf的引用
ByteBuf data = datagramPacket.content();
long time = new Date().getTime();
@Override
protected void decode(
ChannelHandlerContext ctx,
DatagramPacket datagramPacket, List<Object> out
)
throws Exception {
//获取对 DatagramPacket 中的数据ByteBuf的引用
ByteBuf data = datagramPacket.content();
long time = new Date().getTime();
System.out.println(time+" 接受到发送的消息:");
//获得消息的id
long msgId = data.readLong();
//获得分隔符SEPARATOR
byte sepa = data.readByte();
//获取读索引的当前位置就是分隔符的索引+1
int idx = data.readerIndex();
//提取日志消息从读索引开始到最后为日志的信息
String sendMsg = data.slice(idx ,
data.readableBytes()).toString(CharsetUtil.UTF_8);
//构建一个新的 LogMsg 对象并且将它添加到已经解码的消息的列表中
LogMsg event = new LogMsg(datagramPacket.sender(),
msgId, sendMsg);
//作为本handler的处理结果交给后面的handler进行处理
out.add(event);
}
System.out.println(time + " 接受到发送的消息:");
//获得消息的id
long msgId = data.readLong();
//获得分隔符SEPARATOR
byte sepa = data.readByte();
//获取读索引的当前位置就是分隔符的索引+1
int idx = data.readerIndex();
//提取日志消息从读索引开始到最后为日志的信息
String sendMsg = data.slice(
idx,
data.readableBytes()
).toString(CharsetUtil.UTF_8);
//构建一个新的 LogMsg 对象并且将它添加到已经解码的消息的列表中
LogMsg event = new LogMsg(
datagramPacket.sender(),
msgId, sendMsg
);
//作为本handler的处理结果交给后面的handler进行处理
out.add(event);
}
}

View File

@ -18,31 +18,36 @@ import java.util.List;
* 作者DarkKIng
* 类说明编码将实际的日志实体类编码为DatagramPacket
*/
public class LogEventEncoder extends MessageToMessageEncoder<LogMsg> {
private final InetSocketAddress remoteAddress;
public class LogEventEncoder
extends
MessageToMessageEncoder<LogMsg> {
private final InetSocketAddress remoteAddress;
//LogEventEncoder 创建了即将被发送到指定的 InetSocketAddress
// DatagramPacket 消息
public LogEventEncoder(InetSocketAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
//LogEventEncoder 创建了即将被发送到指定的 InetSocketAddress
// DatagramPacket 消息
public LogEventEncoder(InetSocketAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
@Override
protected void encode(ChannelHandlerContext channelHandlerContext,
LogMsg logMsg, List<Object> out) throws Exception {
byte[] msg = logMsg.getMsg().getBytes(CharsetUtil.UTF_8);
//容量的计算两个long型+消息的内容+分割符
ByteBuf buf = channelHandlerContext.alloc()
.buffer(8*2 + msg.length + 1);
//将发送时间写入到 ByteBuf中
buf.writeLong(logMsg.getTime());
//将消息id写入到 ByteBuf中
buf.writeLong(logMsg.getMsgId());
//添加一个 SEPARATOR
buf.writeByte(LogMsg.SEPARATOR);
//将日志消息写入 ByteBuf中
buf.writeBytes(msg);
//将一个拥有数据和目的地地址的新 DatagramPacket 添加到出站的消息列表中
out.add(new DatagramPacket(buf, remoteAddress));
}
@Override
protected void encode(
ChannelHandlerContext channelHandlerContext,
LogMsg logMsg, List<Object> out
)
throws Exception {
byte[] msg = logMsg.getMsg().getBytes(CharsetUtil.UTF_8);
//容量的计算两个long型+消息的内容+分割符
ByteBuf buf = channelHandlerContext.alloc()
.buffer(8 * 2 + msg.length + 1);
//将发送时间写入到 ByteBuf中
buf.writeLong(logMsg.getTime());
//将消息id写入到 ByteBuf中
buf.writeLong(logMsg.getMsgId());
//添加一个 SEPARATOR
buf.writeByte(LogMsg.SEPARATOR);
//将日志消息写入 ByteBuf中
buf.writeBytes(msg);
//将一个拥有数据和目的地地址的新 DatagramPacket 添加到出站的消息列表中
out.add(new DatagramPacket(buf, remoteAddress));
}
}

View File

@ -14,29 +14,36 @@ import io.netty.channel.SimpleChannelInboundHandler;
* 类说明日志的业务处理类,实际的业务处理接受日志信息
*/
public class LogEventHandler
extends SimpleChannelInboundHandler<LogMsg> {
extends
SimpleChannelInboundHandler<LogMsg> {
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) throws Exception {
//当异常发生时打印栈跟踪信息并关闭对应的 Channel
cause.printStackTrace();
ctx.close();
}
@Override
public void exceptionCaught(
ChannelHandlerContext ctx,
Throwable cause
)
throws Exception {
//当异常发生时打印栈跟踪信息并关闭对应的 Channel
cause.printStackTrace();
ctx.close();
}
@Override
public void channelRead0(ChannelHandlerContext ctx,
LogMsg event) throws Exception {
//创建 StringBuilder并且构建输出的字符串
StringBuilder builder = new StringBuilder();
builder.append(event.getTime());
builder.append(" [");
builder.append(event.getSource().toString());
builder.append("] [");
builder.append(event.getMsgId());
builder.append("] ");
builder.append(event.getMsg());
//打印 LogMsg 的数据
System.out.println(builder.toString());
}
@Override
public void channelRead0(
ChannelHandlerContext ctx,
LogMsg event
)
throws Exception {
//创建 StringBuilder并且构建输出的字符串
StringBuilder builder = new StringBuilder();
builder.append(event.getTime());
builder.append(" [");
builder.append(event.getSource().toString());
builder.append("] [");
builder.append(event.getMsgId());
builder.append("] ");
builder.append(event.getMsg());
//打印 LogMsg 的数据
System.out.println(builder.toString());
}
}

View File

@ -6,58 +6,55 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import java.net.InetSocketAddress;
/**
* @Desc: ""
* @Author: caixiang ( Server 接受消息 )
* @DATE: 2024/12/15 10:57
*/
public class LogEventMonitor {
private final EventLoopGroup group;
private final Bootstrap bootstrap;
private final EventLoopGroup group;
private final Bootstrap bootstrap;
public LogEventMonitor(InetSocketAddress address) {
group = new NioEventLoopGroup();
bootstrap = new Bootstrap();
//引导该 NioDatagramChannel
bootstrap.group(group)
.channel(NioDatagramChannel.class)
//设置套接字选项 SO_BROADCAST
.option(ChannelOption.SO_BROADCAST, true)
//允许重用
.option(ChannelOption.SO_REUSEADDR,true)
.handler( new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel)
throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new LogEventDecoder());
pipeline.addLast(new LogEventHandler());
}
} )
.localAddress(address);
}
public LogEventMonitor(InetSocketAddress address) {
group = new NioEventLoopGroup();
bootstrap = new Bootstrap();
//引导该 NioDatagramChannel
bootstrap.group(group)
.channel(NioDatagramChannel.class)
//设置套接字选项 SO_BROADCAST
.option(ChannelOption.SO_BROADCAST, true)
//允许重用
.option(ChannelOption.SO_REUSEADDR, true)
.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel)
throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new LogEventDecoder());
pipeline.addLast(new LogEventHandler());
}
})
.localAddress(address);
}
public Channel bind() {
//绑定 Channel注意DatagramChannel 是无连接的
return bootstrap.bind().syncUninterruptibly().channel();
}
public Channel bind() {
//绑定 Channel注意DatagramChannel 是无连接的
return bootstrap.bind().syncUninterruptibly().channel();
}
public void stop() {
group.shutdownGracefully();
}
public void stop() {
group.shutdownGracefully();
}
public static void main(String[] args) throws Exception {
//构造一个新的 UdpAnswerSide并指明监听端口
LogEventMonitor monitor = new LogEventMonitor(
new InetSocketAddress(LogConst.MONITOR_SIDE_PORT));
try {
//绑定本地监听端口
Channel channel = monitor.bind();
System.out.println("UdpAnswerSide running");
channel.closeFuture().sync();
} finally {
monitor.stop();
}
public static void main(String[] args)
throws Exception {
//构造一个新的 UdpAnswerSide并指明监听端口
LogEventMonitor monitor = new LogEventMonitor(
new InetSocketAddress(LogConst.MONITOR_SIDE_PORT)
);
try {
//绑定本地监听端口
Channel channel = monitor.bind();
System.out.println("UdpAnswerSide running");
channel.closeFuture().sync();
}
finally {
monitor.stop();
}
}
}

View File

@ -13,51 +13,53 @@ import java.net.InetSocketAddress;
* 类说明日志实体类
*/
public final class LogMsg {
public static final byte SEPARATOR = (byte) ':';
/*源的 InetSocketAddress*/
private final InetSocketAddress source;
/*消息内容*/
private final String msg;
/*消息id*/
private final long msgId;
/*消息发送的时间*/
private final long time;
public static final byte SEPARATOR = (byte) ':';
/* 源的 InetSocketAddress */
private final InetSocketAddress source;
/* 消息内容 */
private final String msg;
/* 消息id */
private final long msgId;
/* 消息发送的时间 */
private final long time;
//用于传入消息的构造函数
public LogMsg(String msg) {
this(null, msg,-1,System.currentTimeMillis());
}
//用于传入消息的构造函数
public LogMsg(String msg) {
this(null, msg, -1, System.currentTimeMillis());
}
//用于传出消息的构造函数
public LogMsg(InetSocketAddress source, long msgId,
String msg) {
this(source,msg,msgId,System.currentTimeMillis());
}
//用于传出消息的构造函数
public LogMsg(
InetSocketAddress source, long msgId,
String msg
) {
this(source, msg, msgId, System.currentTimeMillis());
}
public LogMsg(InetSocketAddress source, String msg, long msgId, long time) {
this.source = source;
this.msg = msg;
this.msgId = msgId;
this.time = time;
}
public LogMsg(InetSocketAddress source, String msg, long msgId, long time) {
this.source = source;
this.msg = msg;
this.msgId = msgId;
this.time = time;
}
//返回发送 LogMsg 的源的 InetSocketAddress
public InetSocketAddress getSource() {
return source;
}
//返回发送 LogMsg 的源的 InetSocketAddress
public InetSocketAddress getSource() {
return source;
}
//返回消息内容
public String getMsg() {
return msg;
}
//返回消息内容
public String getMsg() {
return msg;
}
//返回消息id
public long getMsgId() {
return msgId;
}
//返回消息id
public long getMsgId() {
return msgId;
}
//返回消息中的时间
public long getTime() {
return time;
}
//返回消息中的时间
public long getTime() {
return time;
}
}

View File

@ -3,12 +3,13 @@ package org.opentcs.kc.udp;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
//import org.opentcs.kc.udp.agv.param.AgvEvent;
import org.opentcs.kc.common.byteutils.ByteUtils;
import org.opentcs.kc.udp.agv.param.AgvEvent;
import org.opentcs.kc.udp.agv.param.AgvEventConstant;
import org.opentcs.kc.udp.agv.param.function.af.QueryRobotStatusRsp;
import org.opentcs.kc.udp.agv.param.function.b1.SubscribeInfo;
import org.opentcs.kc.udp.agv.param.function.b1.SubscribeParam;
import org.opentcs.kc.udp.agv.param.function.b1.SubscribeRsp;
import org.opentcs.kc.udp.agv.param.function.navigation.*;
import org.opentcs.kc.udp.agv.param.function.read.ReadParam;
import org.opentcs.kc.udp.agv.param.function.read.ReadStrValue;
@ -17,42 +18,42 @@ import org.opentcs.kc.udp.agv.param.function.write.WriteParam;
import org.opentcs.kc.udp.agv.param.function.write.WriteStrValue;
import org.opentcs.kc.udp.agv.param.function.write.WriteValueMember;
import org.opentcs.kc.udp.agv.param.function.x14.RobotSetPosition;
import org.opentcs.kc.udp.agv.param.function.x17.QueryRobotRunStatusRsp;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.kc.udp.io.UDPClient;
import org.opentcs.kc.udp.agv.param.AgvEvent;
/**
*
* AGV启动
* 0xAF(查询机器人状态) 👌
* 0xB1(下发订阅信令) 👌
* 0xAF(查询机器人状态) 👌
* 0xB1(下发订阅信令) 👌
* 初始化
* 0x03(切换手自动) 👌
* 0x14(手动定位) 👌
* 0x17(查询机器人运行状态) 👌
* 0x1F(确认初始位置) 👌
* 0x03(切换手自动) 👌
* 0x14(手动定位) 👌
* 0x17(查询机器人运行状态) 👌
* 0x1F(确认初始位置) 👌
* 运行
* 0xAE(导航控制导航点控制) 👌
*
*
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/17 16:25
*/
public class KCCommandDemo {
public static void main(String [] args) throws Exception{
public static void main(String[] args)
throws Exception {
// {
// //0xAF(查询机器人状态)
// AgvEvent agvEvent = queryStatus();
// printInfo(agvEvent);
// RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
// if(rcv.isOk()){
// System.out.println();
// System.out.println("received transationId : "+ "isok:"+rcv.isOk());
// for (byte b:rcv.getValue()){
// System.out.print(byteToHex(b)+" ");
// }
// System.out.println();
// System.out.println("---------------------");
// for (byte c:rcv.getDataBytes()){
// System.out.print(byteToHex(c)+" ");
// }
// QueryRobotStatusRsp queryRobotStatusRsp = new QueryRobotStatusRsp(rcv.getDataBytes());
// System.out.println();
// System.out.println("received transationId : "+ "isok:"+rcv.isOk());
// for (byte b:rcv.getValue()){
// System.out.print(byteToHex(b)+" ");
// }
// }else {
// System.out.println();
// System.out.println("received transationId : "+ "isok:"+rcv.isOk());
@ -86,6 +87,10 @@ public class KCCommandDemo {
// if(rcv.isOk()){
// System.out.println();
// System.out.println("received transationId : "+ "isok:"+rcv.isOk());
// for (byte b:rcv.getDataBytes()) {
// System.out.print(byteToHex(b)+" ");
// }
//
// SubscribeRsp subscribeRsp = new SubscribeRsp(rcv.getDataBytes());
// if(subscribeRsp.isOk()){
// //...
@ -142,26 +147,26 @@ public class KCCommandDemo {
// }
// {
// //0x14(手动定位)
// AgvEvent agvEvent = manualLocation();
// printInfo(agvEvent);
// RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
// if(rcv.isOk()){
// System.out.println();
// System.out.println("received "+ "isok:"+rcv.isOk()+" dataBytes:");
// printInfo(rcv);
// if(rcv.isOk()){
// //get and parse value
// System.out.println("0x14 ok");
// }else {
// System.out.println("0x14 failed");
// }
// }else {
// System.out.println();
// System.out.println("received transationId : "+ "isok:"+rcv.isOk());
// }
// }
{
//0x14(手动定位)
AgvEvent agvEvent = manualLocation();
printInfo(agvEvent);
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
if(rcv.isOk()){
System.out.println();
System.out.println("received "+ "isok:"+rcv.isOk()+" dataBytes:");
printInfo(rcv);
if(rcv.isOk()){
//get and parse value
System.out.println("0x14 ok");
}else {
System.out.println("0x14 failed");
}
}else {
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
}
}
// {
@ -170,33 +175,40 @@ public class KCCommandDemo {
// printInfo(agvEvent);
// RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
// if(rcv.isOk()){
// System.out.println();
// System.out.println("received transationId : "+ "isok:"+rcv.isOk());
// for (byte b:rcv.getValue()){
// System.out.print(byteToHex(b)+" ");
// }
// System.out.println();
// System.out.println("print databytes:-----=======");
// for (byte c:rcv.getDataBytes()){
// System.out.print(byteToHex(c)+" ");
// }
// //QueryCargoStatusRsp queryCargoStatusRsp = new QueryCargoStatusRsp(rcv.getDataBytes());
// QueryRobotRunStatusRsp queryRobotRunStatusRsp = new QueryRobotRunStatusRsp(rcv.getDataBytes());
// System.out.println(queryRobotRunStatusRsp.toString());
// System.out.println();
// System.out.println("received transationId : "+ "isok:"+rcv.isOk());
// for (byte b:rcv.getValue()){
// System.out.print(byteToHex(b)+" ");
// }
//
// }else {
// System.out.println();
// System.out.println("received transationId : "+ "isok:"+rcv.isOk());
// }
// }
{
//0x1F(确认初始位置)
AgvEvent agvEvent = confirmInitialPosition();
printInfo(agvEvent);
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
if(rcv.isOk()){
System.out.println("0x1F ok");
}else {
System.out.println();
System.out.println("0x1F fail");
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
}
}
// {
// //0x1F(确认初始位置)
// AgvEvent agvEvent = confirmInitialPosition();
// printInfo(agvEvent);
// RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
// if (rcv.isOk()) {
// System.out.println("0x1F ok");
// }
// else {
// System.out.println();
// System.out.println("0x1F fail");
// System.out.println("received transationId : " + "isok:" + rcv.isOk());
// }
// }
// {
// //0xAE(导航控制导航点控制)
@ -212,196 +224,235 @@ public class KCCommandDemo {
// }
// }
}
public static String byteToHex(byte b) {
// 将byte转换为无符号整数
int unsignedByte = b & 0xFF;
// 使用Integer.toHexString方法转换为十六进制字符串
String hexString = Integer.toHexString(unsignedByte);
// 如果字符串长度为1需要在前面补0
if (hexString.length() == 1) {
return "0" + hexString;
}
return hexString;
}
public static String byteToHex(byte b) {
// 将byte转换为无符号整数
int unsignedByte = b & 0xFF;
// 使用Integer.toHexString方法转换为十六进制字符串
String hexString = Integer.toHexString(unsignedByte);
// 如果字符串长度为1需要在前面补0
if (hexString.length() == 1) {
return "0" + hexString;
}
return hexString;
public static void printInfo(AgvEvent agvEvent) {
System.out.println("sended transationId : " + agvEvent.getTransationIdString());
for (byte b : agvEvent.toBytes().getBody()) {
System.out.print(byteToHex(b) + " ");
}
}
public static void printInfo(AgvEvent agvEvent){
System.out.println("sended transationId : "+agvEvent.getTransationIdString());
for (byte b:agvEvent.toBytes().getBody()){
System.out.print(byteToHex(b)+" ");
}
public static void printInfo(RcvEventPackage rcv) {
for (byte b : rcv.getDataBytes()) {
System.out.print(byteToHex(b) + " ");
}
}
public static void printInfo(RcvEventPackage rcv){
/**
* decs: read操作
* 指令0x02
* author: caixiang
* date: 2025/1/17 16:25
*/
public static AgvEvent readValue() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_READ);
List<ReadValueMember> readValueMemberList = new ArrayList<>();
ReadValueMember readValueMember1 = new ReadValueMember(Short.valueOf("0"), Short.valueOf("1"));
readValueMemberList.add(readValueMember1);
for (byte b: rcv.getDataBytes()){
System.out.print(byteToHex(b)+" ");
}
}
List<ReadStrValue> readStrValueList = new ArrayList<>();
ReadStrValue readStrValue = new ReadStrValue("Battry_SOC", 1, readValueMemberList);
readStrValueList.add(readStrValue);
/**
* decs: read操作
* 指令0x02
* author: caixiang
* date: 2025/1/17 16:25
* */
public static AgvEvent readValue() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_READ);
List<ReadValueMember> readValueMemberList = new ArrayList<>();
ReadValueMember readValueMember1 = new ReadValueMember(Short.valueOf("0"),Short.valueOf("1"));
readValueMemberList.add(readValueMember1);
ReadParam readParam = new ReadParam(agvEvent.getTransationId(), readStrValueList);
agvEvent.setBody(readParam.toBytes());
List<ReadStrValue> readStrValueList = new ArrayList<>();
ReadStrValue readStrValue = new ReadStrValue("Battry_SOC", 1, readValueMemberList);
readStrValueList.add(readStrValue);
return agvEvent;
}
ReadParam readParam = new ReadParam(agvEvent.getTransationId(),readStrValueList );
agvEvent.setBody(readParam.toBytes());
/**
* decs: write操作
* 指令0x03
* author: caixiang
* date: 2025/1/17 16:25
*/
public static AgvEvent writeValue() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_WRITE);
return agvEvent;
}
List<WriteValueMember> valueMemberList = new ArrayList<>();
WriteValueMember valueMember1 = new WriteValueMember(
Short.valueOf("0"), Short.valueOf("4"), ByteUtils.uintToBytes(3, ByteOrder.LITTLE_ENDIAN)
);
valueMemberList.add(valueMember1);
/**
* decs: write操作
* 指令0x03
* author: caixiang
* date: 2025/1/17 16:25
* */
public static AgvEvent writeValue() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_WRITE);
List<WriteStrValue> strValueList = new ArrayList<>();
WriteStrValue strValue = new WriteStrValue("TestRW", 1, valueMemberList);
strValueList.add(strValue);
List<WriteValueMember> valueMemberList = new ArrayList<>();
WriteValueMember valueMember1 = new WriteValueMember(Short.valueOf("0"),Short.valueOf("4"), ByteUtils.uintToBytes(3, ByteOrder.LITTLE_ENDIAN));
valueMemberList.add(valueMember1);
WriteParam param = new WriteParam(1, strValueList);
agvEvent.setBody(param.toBytes());
List<WriteStrValue> strValueList = new ArrayList<>();
WriteStrValue strValue = new WriteStrValue("TestRW", 1, valueMemberList);
strValueList.add(strValue);
WriteParam param = new WriteParam(1,strValueList );
agvEvent.setBody(param.toBytes());
return agvEvent;
}
return agvEvent;
}
/**
* decs: 查询机器人状态
* 指令0xAF
* author: caixiang
* date: 2025/1/17 16:25
*/
public static AgvEvent queryStatus() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_QUERY_ROBOT_STATUS);
return agvEvent;
}
/**
* decs: 导航控制
* 指令0xAE
* author: caixiang
* date: 2025/1/17 16:25
*/
public static AgvEvent navigationControl() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_QUERY_ROBOT_STATUS);
//TODO 构建
Integer orderId = 1;
//构建point
Action[] pointActions1 = new Action[]{
new Action(
ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(
orderId, (byte) 0x01
)
)
//,new Action()... 每一个point 可以绑定一个或者多个 action
};
Action[] pointActions2 = new Action[]{
new Action(
ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(
orderId, (byte) 0x01
)
)
};
Action[] pointActions3 = new Action[]{
new Action(
ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(
orderId, (byte) 0x01
)
)
};
Point[] points = new Point[]{
new Point(
0, 1, 1f, (byte) 0x00, ByteUtils.usintTo1Byte(pointActions1.length), pointActions1
),
new Point(
2, 2, 1f, (byte) 0x00, ByteUtils.usintTo1Byte(pointActions2.length), pointActions2
),
new Point(
4, 3, 1f, (byte) 0x00, ByteUtils.usintTo1Byte(pointActions3.length), pointActions3
)
};
//构建path
Action[] pathActions1 = new Action[]{
new Action(
ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(
orderId, (byte) 0x01
)
)
//,new Action()... 每一个path 可以绑定一个或者多个 action
};
Action[] pathActions2 = new Action[]{
new Action(
ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(
orderId, (byte) 0x01
)
)
};
Path[] paths = new Path[]{
new Path(
1, 1, 1f, (byte) 0x00, (byte) 0x00, ByteUtils.usintTo1Byte(pathActions1.length), 5f, 1f,
pathActions1
),
new Path(
3, 2, 1f, (byte) 0x00, (byte) 0x00, ByteUtils.usintTo1Byte(pathActions2.length), 5f, 1f,
pathActions2
),
};
NavigationParam navigationParam = new NavigationParam(
1, 1, ByteUtils.usintTo1Byte(points.length), ByteUtils.usintTo1Byte(points.length - 1),
points, paths
);
agvEvent.setBody(navigationParam.toBytes());
return agvEvent;
}
/**
* decs: 确认机器人位置
* 指令0x1F
* author: caixiang
* date: 2025/1/17 16:25
*/
public static AgvEvent confirmInitialPosition() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_CONFIRM_ROBOT_POSITION);
return agvEvent;
}
/**
* decs: 查询机器人运行状态
* 指令0x17
* author: caixiang
* date: 2025/1/17 16:25
*/
public static AgvEvent queryRobotRunStatus() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_QUERY_ROBOT_RUN_STATUS);
return agvEvent;
}
public static AgvEvent manualLocation() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_ROBOT_SET_POSITION);
RobotSetPosition robotSetPosition = new RobotSetPosition(11, 11, 11);
byte[] bytes = robotSetPosition.toBytes();
agvEvent.setBody(bytes);
return agvEvent;
}
/**
* decs: 查询机器人状态
* 指令0xAF
* author: caixiang
* date: 2025/1/17 16:25
* */
public static AgvEvent queryStatus() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_QUERY_ROBOT_STATUS);
return agvEvent;
}
/**
* decs: 查询载货状态
* 指令0xB0
* author: caixiang
* date: 2025/1/17 16:25
*/
public static AgvEvent checkCargoStatus() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_QUERY_CARRY_STATUS);
return agvEvent;
}
/**
* decs: 导航控制
* 指令0xAE
* author: caixiang
* date: 2025/1/17 16:25
* */
public static AgvEvent navigationControl() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_QUERY_ROBOT_STATUS);
//TODO 构建
Integer orderId = 1;
//构建point
Action[] pointActions1 = new Action[]{
new Action(ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(orderId, (byte) 0x01))
//,new Action()... 每一个point 可以绑定一个或者多个 action
};
Action[] pointActions2 = new Action[]{
new Action(ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(orderId, (byte) 0x01))
};
Action[] pointActions3 = new Action[]{
new Action(ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(orderId, (byte) 0x01))
};
Point[] points = new Point[]{
new Point(0, 1, 1f, (byte)0x00, ByteUtils.usintTo1Byte(pointActions1.length),pointActions1),
new Point(2, 2, 1f, (byte)0x00, ByteUtils.usintTo1Byte(pointActions2.length),pointActions2),
new Point(4, 3, 1f, (byte)0x00, ByteUtils.usintTo1Byte(pointActions3.length),pointActions3)
};
//构建path
Action[] pathActions1 = new Action[]{
new Action(ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(orderId, (byte) 0x01))
//,new Action()... 每一个path 可以绑定一个或者多个 action
};
Action[] pathActions2 = new Action[]{
new Action(ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(orderId, (byte) 0x01))
};
Path[] paths = new Path[]{
new Path(1,1,1f,(byte)0x00,(byte)0x00,ByteUtils.usintTo1Byte(pathActions1.length),5f,1f,pathActions1) ,
new Path(3,2,1f,(byte)0x00,(byte)0x00,ByteUtils.usintTo1Byte(pathActions2.length),5f,1f,pathActions2) ,
};
NavigationParam navigationParam = new NavigationParam(1,1,ByteUtils.usintTo1Byte(points.length),ByteUtils.usintTo1Byte(points.length-1),points,paths);
agvEvent.setBody(navigationParam.toBytes());
return agvEvent;
}
/**
* decs: 确认机器人位置
* 指令0x1F
* author: caixiang
* date: 2025/1/17 16:25
* */
public static AgvEvent confirmInitialPosition() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_CONFIRM_ROBOT_POSITION);
return agvEvent;
}
/**
* decs: 查询机器人运行状态
* 指令0x17
* author: caixiang
* date: 2025/1/17 16:25
* */
public static AgvEvent queryRobotRunStatus() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_QUERY_ROBOT_RUN_STATUS);
return agvEvent;
}
public static AgvEvent manualLocation() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_ROBOT_SET_POSITION);
RobotSetPosition robotSetPosition = new RobotSetPosition(11, 11, 11);
byte[] bytes = robotSetPosition.toBytes();
agvEvent.setBody(bytes);
return agvEvent;
}
/**
* decs: 查询载货状态
* 指令0xB0
* author: caixiang
* date: 2025/1/17 16:25
* */
public static AgvEvent checkCargoStatus() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_QUERY_CARRY_STATUS);
return agvEvent;
}
/**
* decs: 下发订阅信息
* 指令0xB1
* author: caixiang
* date: 2025/1/17 16:25
* */
public static AgvEvent issueSubscribe() {
List<SubscribeInfo> subscribeInfoList = new ArrayList<>();
SubscribeInfo subscribeInfo = new SubscribeInfo(new byte[]{(byte)0xaf,(byte)0x00}, (short) 100,1000);
//SubscribeInfo subscribeInfo = new SubscribeInfo(new byte[]{(byte)0xb0,(byte)0x00}, (short) 100,1000);
subscribeInfoList.add(subscribeInfo);
SubscribeParam subscribeParam = new SubscribeParam(subscribeInfoList);
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_ISSUE_SUBSCRIPTION,subscribeParam.toBytes());
return agvEvent;
}
/**
* decs: 下发订阅信息
* 指令0xB1
* author: caixiang
* date: 2025/1/17 16:25
*/
public static AgvEvent issueSubscribe() {
List<SubscribeInfo> subscribeInfoList = new ArrayList<>();
SubscribeInfo subscribeInfo = new SubscribeInfo(
new byte[]{(byte) 0xaf, (byte) 0x00}, (short) 100, 1000
);
//SubscribeInfo subscribeInfo = new SubscribeInfo(new byte[]{(byte)0xb0,(byte)0x00}, (short) 100,1000);
subscribeInfoList.add(subscribeInfo);
SubscribeParam subscribeParam = new SubscribeParam(subscribeInfoList);
AgvEvent agvEvent = new AgvEvent(
AgvEventConstant.CommandCode_ISSUE_SUBSCRIPTION, subscribeParam.toBytes()
);
return agvEvent;
}
}

View File

@ -3,11 +3,6 @@ package org.opentcs.kc.udp.Service;
import org.opentcs.kc.udp.agv.param.AgvEvent;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
/**
* @author xzh
* @date 2025/2/21
* @desc 命令基类
*/
public class BaseCommand {
public static String byteToHex(byte b) {
@ -22,17 +17,17 @@ public class BaseCommand {
return hexString;
}
public static void printInfo(AgvEvent agvEvent){
System.out.println("sended transationId : "+agvEvent.getTransationIdString());
for (byte b:agvEvent.toBytes().getBody()){
System.out.print(byteToHex(b)+" ");
public static void printInfo(AgvEvent agvEvent) {
System.out.println("sended transationId : " + agvEvent.getTransationIdString());
for (byte b : agvEvent.toBytes().getBody()) {
System.out.print(byteToHex(b) + " ");
}
}
public static void printInfo(RcvEventPackage rcv){
public static void printInfo(RcvEventPackage rcv) {
for (byte b: rcv.getDataBytes()){
System.out.print(byteToHex(b)+" ");
for (byte b : rcv.getDataBytes()) {
System.out.print(byteToHex(b) + " ");
}
}

View File

@ -5,19 +5,16 @@ import org.opentcs.kc.udp.agv.param.AgvEventConstant;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.kc.udp.io.UDPClient;
/**
* @author xzh
* @date 2025/2/21
* @desc 确认位置 0x1F
*/
public class ConfirmRelocation extends BaseCommand{
public class ConfirmRelocation
extends
BaseCommand {
/**
* decs: 确认机器人位置
* 指令0x1F
* author: caixiang
* date: 2025/1/17 16:25
* */
* decs: 确认机器人位置.
* 指令0x1F.
* author: caixiang.
* date: 2025/1/17 16:25.
*/
public static AgvEvent confirmInitialPosition() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_CONFIRM_ROBOT_POSITION);
return agvEvent;
@ -28,12 +25,13 @@ public class ConfirmRelocation extends BaseCommand{
AgvEvent agvEvent = confirmInitialPosition();
printInfo(agvEvent);
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
if(rcv.isOk()){
if (rcv.isOk()) {
System.out.println("0x1F ok");
}else {
}
else {
System.out.println();
System.out.println("0x1F fail");
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
System.out.println("received transationId : " + "isok:" + rcv.isOk());
}
}
}

View File

@ -1,5 +1,7 @@
package org.opentcs.kc.udp.Service;
import java.util.HashMap;
import org.opentcs.drivers.vehicle.MovementCommand;
import org.opentcs.kc.common.byteutils.ByteUtils;
import org.opentcs.kc.udp.agv.param.AgvEvent;
import org.opentcs.kc.udp.agv.param.AgvEventConstant;
@ -11,7 +13,9 @@ import org.opentcs.kc.udp.agv.param.function.navigation.Point;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.kc.udp.io.UDPClient;
public class HybridNavigation extends BaseCommand{
public class HybridNavigation
extends
BaseCommand {
/**
* 测试模式true=开启测试false=关闭测试
@ -38,6 +42,14 @@ public class HybridNavigation extends BaseCommand{
* 用于定位段在整个任务中的位置目的是区分同一个段ID是否在一个任务中出现多次从1开始奇数递增例如1->3->5->7
*/
private static Integer pathSerialNum = 1;
/**
* 订单名映射int类型数据.
*/
private static HashMap<String, Integer> orderNameMap = new HashMap<>();
/**
* 订单映射最大订单ID.
*/
private static int currentMaxiOrderId = 0;
/**
@ -45,45 +57,37 @@ public class HybridNavigation extends BaseCommand{
* 指令0xAE
* author: caixiang
* date: 2025/1/17 16:25
* */
public static AgvEvent navigationControl(Integer sourcePoint, Integer destinationPoint, Integer pathID, String operation) {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_QUERY_ROBOT_STATUS);
*/
public static AgvEvent navigationControl(
Integer sourcePoint, Integer destinationPoint, Integer pathID, String operation
) {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_MIXED_ISSUANCE_TASK);
//TODO 构建
Integer orderId = orderID;
// Integer orderId = 1;
//构建point
Action[] pointActions1 = new Action[]{
new Action(ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(orderId, (byte) 0x01))
//,new Action()... 每一个point 可以绑定一个或者多个 action
};
Action[] pointActions2 = new Action[]{
new Action(ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(orderId, (byte) 0x01))
};
// Action[] pointActions3 = new Action[]{
// new Action(ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(orderId, (byte) 0x01))
// };
Integer oldPointSerialNum = pointSerialNum;
pointSerialNum += 2;
Point[] points = new Point[]{
new Point(oldPointSerialNum, sourcePoint, 1f, (byte)0x00, ByteUtils.usintTo1Byte(pointActions1.length),pointActions1),
new Point(pointSerialNum, destinationPoint, 1f, (byte)0x00, ByteUtils.usintTo1Byte(pointActions2.length),pointActions2)
// new Point(4, 3, 1f, (byte)0x00, ByteUtils.usintTo1Byte(pointActions3.length),pointActions3)
new Point(
oldPointSerialNum, sourcePoint, 0f, (byte) 0x00, ByteUtils.usintTo1Byte(0), null
),
new Point(
pointSerialNum, destinationPoint, 0f, (byte) 0x00, ByteUtils.usintTo1Byte(0), null
)
};
//构建path
Action[] pathActions1 = new Action[]{
new Action(ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(orderId, (byte) 0x01))
//,new Action()... 每一个path 可以绑定一个或者多个 action
};
// Action[] pathActions2 = new Action[]{
// new Action(ActionSet.stop0x01, (byte) 0x00, 1, ActionSet.stop0x01_paramsize, ActionSet.stop0x01(orderId, (byte) 0x01))
// };
Path[] paths = new Path[]{
new Path(pathSerialNum,pathID,1f,(byte)0x00,(byte)0x00,ByteUtils.usintTo1Byte(pathActions1.length),5f,1f,pathActions1) ,
// new Path(3,2,1f,(byte)0x00,(byte)0x00,ByteUtils.usintTo1Byte(pathActions2.length),5f,1f,pathActions2) ,
new Path(
pathSerialNum, pathID, 0f, (byte) 0x00, (byte) 0x01, ByteUtils.usintTo1Byte(0), 1f, 1f, null
),
};
NavigationParam navigationParam = new NavigationParam(orderID,taskKey,ByteUtils.usintTo1Byte(points.length),ByteUtils.usintTo1Byte(points.length-1),points,paths);
pathSerialNum += 2;
NavigationParam navigationParam = new NavigationParam(
orderID, taskKey, ByteUtils.usintTo1Byte(points.length), ByteUtils.usintTo1Byte(
points.length - 1
), points, paths
);
taskKey++;
agvEvent.setBody(navigationParam.toBytes());
return agvEvent;
@ -96,16 +100,24 @@ public class HybridNavigation extends BaseCommand{
* @param destinationPoint 下发终点
* @param operation 执行操作
*/
public static void command(String orderName, String sourcePoint, String destinationPoint, String operation) {
if (TEST_MODEL) {
return;
}
public static void command(
String orderName, String sourcePoint, String destinationPoint, String operation
) {
// if (TEST_MODEL) {
// return;
// }
Integer newOrderName = Integer.parseInt(orderName);
Integer newOrderName = getUniqueOrderID(orderName);
Integer newSourcePoint = Integer.parseInt(sourcePoint);
Integer newDestinationPoint = Integer.parseInt(destinationPoint);
//拼接起点终点字符串转为Integer类型获取唯一pathID
Integer pathID = Integer.parseInt(sourcePoint + destinationPoint);
Integer pathID;
if (newSourcePoint <= newDestinationPoint) {
pathID = Integer.parseInt(sourcePoint + destinationPoint);
} else {
pathID = Integer.parseInt(destinationPoint + sourcePoint);
}
System.out.println("pathID:" + pathID);
if (!orderID.equals(newOrderName)) {
//切换订单重置参数
@ -116,17 +128,19 @@ public class HybridNavigation extends BaseCommand{
AgvEvent agvEvent = navigationControl(newSourcePoint, newDestinationPoint, pathID, operation);
printInfo(agvEvent);
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
if(rcv.isOk()){
if (rcv.isOk()) {
System.out.println("0xAE ok");
}else {
}
else {
System.out.println();
System.out.println("0xAE fail");
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
System.out.println("received transationId : " + "isok:" + rcv.isOk());
}
}
/**
* 初始化参数
*
* @param newOrderName 新的订单ID
*/
private static void initParams(Integer newOrderName) {
@ -136,4 +150,34 @@ public class HybridNavigation extends BaseCommand{
pathSerialNum = 1;
}
/**
* 维护订单名对应int类型唯一ID
* @param orderName 订单名
* @return Integer
*/
private static Integer getUniqueOrderID(String orderName){
Integer orderId;
if (orderNameMap.containsKey(orderName)) {
//订单名已存在
orderId = orderNameMap.get(orderName);
} else {
//订单名不存在创建对应映射
currentMaxiOrderId = currentMaxiOrderId + 1;
orderId = currentMaxiOrderId;
orderNameMap.put(orderName, orderId);
}
return orderId;
}
/**
* 任务结束删除唯一orderID.
* @param command 订单
*/
public static void delUniqueOrderID(MovementCommand command){
String orderName = command.getTransportOrder().getName();
orderNameMap.remove(orderName);
}
}

View File

@ -7,12 +7,9 @@ import org.opentcs.kc.udp.agv.param.function.x14.RobotSetPosition;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.kc.udp.io.UDPClient;
/**
* @author xzh
* @date 2025/2/21
* @desc 手动定位 0x14
*/
public class ManualPosition extends BaseCommand{
public class ManualPosition
extends
BaseCommand {
public static AgvEvent manualLocation(double agvX, double agvY, double agvAngle) {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_ROBOT_SET_POSITION);
@ -27,19 +24,21 @@ public class ManualPosition extends BaseCommand{
AgvEvent agvEvent = manualLocation(agvX, agvY, agvAngle);
printInfo(agvEvent);
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
if(rcv.isOk()){
if (rcv.isOk()) {
System.out.println();
System.out.println("received "+ "isok:"+rcv.isOk()+" dataBytes:");
System.out.println("received " + "isok:" + rcv.isOk() + " dataBytes:");
printInfo(rcv);
if(rcv.isOk()){
if (rcv.isOk()) {
//get and parse value
System.out.println("0x14 ok");
}else {
}
else {
System.out.println("0x14 failed");
}
}else {
}
else {
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
System.out.println("received transationId : " + "isok:" + rcv.isOk());
throw new RuntimeException("0x14 failed");
}
}

View File

@ -6,19 +6,16 @@ import org.opentcs.kc.udp.agv.param.function.x17.QueryRobotRunStatusRsp;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.kc.udp.io.UDPClient;
/**
* @author xzh
* @date 2025/2/21
* @desc 获取AGV运行状态
*/
public class QryRobotRunStatus extends BaseCommand{
public class QryRobotRunStatus
extends
BaseCommand {
/**
* decs: 查询机器人运行状态
* decs: 查询机器人运行状态.
* 指令0x17
* author: caixiang
* date: 2025/1/17 16:25
* */
*/
public static AgvEvent queryRobotRunStatus() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_QUERY_ROBOT_RUN_STATUS);
return agvEvent;
@ -29,19 +26,22 @@ public class QryRobotRunStatus extends BaseCommand{
AgvEvent agvEvent = queryRobotRunStatus();
printInfo(agvEvent);
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
if(rcv.isOk()){
if (rcv.isOk()) {
//QueryCargoStatusRsp queryCargoStatusRsp = new QueryCargoStatusRsp(rcv.getDataBytes());
QueryRobotRunStatusRsp queryRobotRunStatusRsp = new QueryRobotRunStatusRsp(rcv.getDataBytes());
QueryRobotRunStatusRsp queryRobotRunStatusRsp = new QueryRobotRunStatusRsp(
rcv.getDataBytes()
);
System.out.println(queryRobotRunStatusRsp.toString());
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
for (byte b:rcv.getValue()){
System.out.print(byteToHex(b)+" ");
System.out.println("received transationId : " + "isok:" + rcv.isOk());
for (byte b : rcv.getValue()) {
System.out.print(byteToHex(b) + " ");
}
return queryRobotRunStatusRsp;
}else {
}
else {
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
System.out.println("received transationId : " + "isok:" + rcv.isOk());
throw new RuntimeException("0x17 fail");
}
}

View File

@ -6,20 +6,17 @@ import org.opentcs.kc.udp.agv.param.function.af.QueryRobotStatusRsp;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.kc.udp.io.UDPClient;
/**
* @author xzh
* @date 2025/2/21
* @desc 查询机器人状态
*/
public class QryRobotStatus
extends BaseCommand {
extends
BaseCommand {
/**
* decs: 查询机器人状态
* 指令0xAF
* author: caixiang
* date: 2025/1/17 16:25
* */
*/
public static AgvEvent queryStatus() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_QUERY_ROBOT_STATUS);
return agvEvent;
@ -31,16 +28,22 @@ public class QryRobotStatus
printInfo(agvEvent);
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
if(rcv.isOk()){
QueryRobotStatusRsp queryRobotStatusRsp = new QueryRobotStatusRsp(rcv.getDataBytes());
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
return queryRobotStatusRsp;
// for (byte b:rcv.getValue()){
// System.out.print(byteToHex(b)+" ");
for (byte b:rcv.getValue()){
System.out.print(byteToHex(b)+" ");
}
System.out.println();
System.out.println("0xAF received transationId : "+ "isok:"+rcv.isOk());
// for (byte c:rcv.getDataBytes()){
// System.out.print(byteToHex(c)+" ");
// }
}else {
QueryRobotStatusRsp queryRobotStatusRsp = new QueryRobotStatusRsp(rcv.getDataBytes());
return queryRobotStatusRsp;
}
else {
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
System.out.println("received transationId : " + "isok:" + rcv.isOk());
throw new RuntimeException("0xAF fail");
}
}

View File

@ -13,60 +13,64 @@ import org.opentcs.kc.udp.agv.param.function.b1.SubscribeRsp;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.kc.udp.io.UDPClient;
/**
* @author xzh
* @date 2025/2/21
* @desc 订阅载货状态
*/
public class SubCargoStatus extends BaseCommand{
public class SubCargoStatus
extends
BaseCommand {
public static final int intervalTime = 1000;
/**
* decs: 下发订阅信息
* 指令0xB1
* author: caixiang
* date: 2025/1/17 16:25
* */
*/
public static AgvEvent issueSubscribe() {
List<SubscribeInfo> subscribeInfoList = new ArrayList<>();
// SubscribeInfo subscribeInfo = new SubscribeInfo(new byte[]{(byte)0xaf,(byte)0x00}, (short) 100,1000);
SubscribeInfo subscribeInfo = new SubscribeInfo(new byte[]{(byte)0xb0,(byte)0x00}, (short) 100,1000);
SubscribeInfo subscribeInfo = new SubscribeInfo(
new byte[]{(byte) 0xb0, (byte) 0x00}, (short) intervalTime, 10000
);
subscribeInfoList.add(subscribeInfo);
SubscribeParam subscribeParam = new SubscribeParam(subscribeInfoList);
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_ISSUE_SUBSCRIPTION,subscribeParam.toBytes());
AgvEvent agvEvent = new AgvEvent(
AgvEventConstant.CommandCode_ISSUE_SUBSCRIPTION, subscribeParam.toBytes()
);
return agvEvent;
}
public static void command()
{
public static void command() {
// 0xB1(订阅信息)
AgvEvent agvEvent = issueSubscribe();
printInfo(agvEvent);
//todo 订阅参数构建完毕 去写 回调部分
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
if(rcv.isOk()){
if (rcv.isOk()) {
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
System.out.println("received transationId : " + "isok:" + rcv.isOk());
SubscribeRsp subscribeRsp = new SubscribeRsp(rcv.getDataBytes());
if(subscribeRsp.isOk()){
//...
}else {
if (subscribeRsp.isOk()) {
//...
}
}else {
else {
//...
}
}
else {
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
System.out.println("received transationId : " + "isok:" + rcv.isOk());
}
}
//订阅执行操作
public void subscribe0xB0Operate(String name,QueryCargoStatusRsp queryCargoStatusRsp)
{
public void subscribe0xB0Operate(String name, QueryCargoStatusRsp queryCargoStatusRsp) {
// Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
//修改载货状态
if (queryCargoStatusRsp.isCargo == 0) {
//未载货
} else if (queryCargoStatusRsp.isCargo == 1) {
}
else if (queryCargoStatusRsp.isCargo == 1) {
//载货
}
}

View File

@ -10,27 +10,29 @@ import org.opentcs.kc.udp.agv.param.function.b1.SubscribeRsp;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.kc.udp.io.UDPClient;
/**
* @author xzh
* @date 2025/2/21
* @desc 订阅机器人状态
*/
public class SubRobotStatue extends BaseCommand {
public class SubRobotStatue
extends
BaseCommand {
public static final int intervalTime = 1000;
/**
* decs: 下发订阅信息
* 指令0xB1
* author: caixiang
* date: 2025/1/17 16:25
* */
*/
public static AgvEvent issueSubscribe() {
List<SubscribeInfo> subscribeInfoList = new ArrayList<>();
SubscribeInfo subscribeInfo = new SubscribeInfo(new byte[]{(byte)0xaf,(byte)0x00}, (short) 100,1000);
SubscribeInfo subscribeInfo = new SubscribeInfo(
new byte[]{(byte) 0xaf, (byte) 0x00}, (short) intervalTime, 10000
);
// SubscribeInfo subscribeInfo = new SubscribeInfo(new byte[]{(byte)0xb0,(byte)0x00}, (short) 100,1000);
subscribeInfoList.add(subscribeInfo);
SubscribeParam subscribeParam = new SubscribeParam(subscribeInfoList);
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_ISSUE_SUBSCRIPTION,subscribeParam.toBytes());
AgvEvent agvEvent = new AgvEvent(
AgvEventConstant.CommandCode_ISSUE_SUBSCRIPTION, subscribeParam.toBytes()
);
return agvEvent;
}
@ -40,18 +42,20 @@ public class SubRobotStatue extends BaseCommand {
printInfo(agvEvent);
//todo 订阅参数构建完毕 去写 回调部分
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
if(rcv.isOk()){
if (rcv.isOk()) {
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
System.out.println("received transationId : " + "isok:" + rcv.isOk());
SubscribeRsp subscribeRsp = new SubscribeRsp(rcv.getDataBytes());
if(subscribeRsp.isOk()){
//...
}else {
if (subscribeRsp.isOk()) {
//...
}
}else {
else {
//...
}
}
else {
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
System.out.println("received transationId : " + "isok:" + rcv.isOk());
}
}
}

View File

@ -12,31 +12,30 @@ import org.opentcs.kc.udp.agv.param.function.write.WriteValueMember;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.kc.udp.io.UDPClient;
/**
* @author xzh
* @date 2025/2/21
* @desc 切换自动模式
*/
public class SwitchAutomaticMode extends BaseCommand{
public class SwitchAutomaticMode
extends
BaseCommand {
/**
* decs: write操作
* 指令0x03
* author: caixiang
* date: 2025/1/17 16:25
* */
*/
public static AgvEvent writeValue() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_WRITE);
List<WriteValueMember> valueMemberList = new ArrayList<>();
WriteValueMember valueMember1 = new WriteValueMember(Short.valueOf("1"),Short.valueOf("4"), ByteUtils.uintToBytes(3, ByteOrder.LITTLE_ENDIAN));
WriteValueMember valueMember1 = new WriteValueMember(
Short.valueOf("1"), Short.valueOf("4"), ByteUtils.uintToBytes(3, ByteOrder.LITTLE_ENDIAN)
);
valueMemberList.add(valueMember1);
List<WriteStrValue> strValueList = new ArrayList<>();
WriteStrValue strValue = new WriteStrValue("TestRW", 1, valueMemberList);
strValueList.add(strValue);
WriteParam param = new WriteParam(1,strValueList );
WriteParam param = new WriteParam(1, strValueList);
agvEvent.setBody(param.toBytes());
return agvEvent;
@ -47,19 +46,21 @@ public class SwitchAutomaticMode extends BaseCommand{
AgvEvent agvEvent = writeValue();
printInfo(agvEvent);
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
if(rcv.isOk()){
if (rcv.isOk()) {
System.out.println();
System.out.println("received "+ "isok:"+rcv.isOk()+" dataBytes:");
System.out.println("received " + "isok:" + rcv.isOk() + " dataBytes:");
printInfo(rcv);
if(rcv.isOk()){
if (rcv.isOk()) {
//get and parse value
System.out.println("write ok");
}else {
}
else {
System.out.println("write failed");
}
}else {
}
else {
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
System.out.println("received transationId : " + "isok:" + rcv.isOk());
}
}
}

View File

@ -12,31 +12,30 @@ import org.opentcs.kc.udp.agv.param.function.write.WriteValueMember;
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.kc.udp.io.UDPClient;
/**
* @author xzh
* @date 2025/2/21
* @desc 切换手动模式
*/
public class SwitchManualMode extends BaseCommand{
public class SwitchManualMode
extends
BaseCommand {
/**
* decs: write操作
* 指令0x03
* author: caixiang
* date: 2025/1/17 16:25
* */
*/
public static AgvEvent writeValue() {
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_WRITE);
List<WriteValueMember> valueMemberList = new ArrayList<>();
WriteValueMember valueMember1 = new WriteValueMember(Short.valueOf("0"),Short.valueOf("4"), ByteUtils.uintToBytes(3, ByteOrder.LITTLE_ENDIAN));
WriteValueMember valueMember1 = new WriteValueMember(
Short.valueOf("0"), Short.valueOf("4"), ByteUtils.uintToBytes(3, ByteOrder.LITTLE_ENDIAN)
);
valueMemberList.add(valueMember1);
List<WriteStrValue> strValueList = new ArrayList<>();
WriteStrValue strValue = new WriteStrValue("TestRW", 1, valueMemberList);
strValueList.add(strValue);
WriteParam param = new WriteParam(1,strValueList );
WriteParam param = new WriteParam(1, strValueList);
agvEvent.setBody(param.toBytes());
return agvEvent;
@ -47,19 +46,21 @@ public class SwitchManualMode extends BaseCommand{
AgvEvent agvEvent = writeValue();
printInfo(agvEvent);
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
if(rcv.isOk()){
if (rcv.isOk()) {
System.out.println();
System.out.println("received "+ "isok:"+rcv.isOk()+" dataBytes:");
System.out.println("received " + "isok:" + rcv.isOk() + " dataBytes:");
printInfo(rcv);
if(rcv.isOk()){
if (rcv.isOk()) {
//get and parse value
System.out.println("write ok");
}else {
}
else {
System.out.println("write failed");
}
}else {
}
else {
System.out.println();
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
System.out.println("received transationId : " + "isok:" + rcv.isOk());
}
}
}

View File

@ -7,20 +7,23 @@ import org.opentcs.kc.udp.io.UDPClient;
/**
* 作者蔡翔
*/
public class AgvUdpChannelInitializer extends ChannelInitializer<NioDatagramChannel> {
private UDPClient client;
public class AgvUdpChannelInitializer
extends
ChannelInitializer<NioDatagramChannel> {
private UDPClient client;
public AgvUdpChannelInitializer(UDPClient client) {
System.out.println(client.getHost());
this.client = client;
}
public AgvUdpChannelInitializer(UDPClient client) {
System.out.println(client.getHost());
this.client = client;
}
@Override
protected void initChannel(NioDatagramChannel channel) throws Exception {
// Modbus
// 在管道中添加我们自己的接收数据实现方法
//todo 到时候这里改成 FixedLengthFrameDecoder 资料https://www.cnblogs.com/java-chen-hao/p/11571229.html
@Override
protected void initChannel(NioDatagramChannel channel)
throws Exception {
// Modbus
// 在管道中添加我们自己的接收数据实现方法
//todo 到时候这里改成 FixedLengthFrameDecoder 资料https://www.cnblogs.com/java-chen-hao/p/11571229.html
// channel.pipeline().addLast(
// new LengthFieldBasedFrameDecoder(
// 200,
@ -30,7 +33,7 @@ public class AgvUdpChannelInitializer extends ChannelInitializer<NioDatagramChan
// 7,
// true)
// );
channel.pipeline().addLast(new AgvUdpDecode(this.client)); //InBoundHandler
//channel.pipeline().addLast(new AgvUdpEncode()); //OutBoundHandler
}
channel.pipeline().addLast(new AgvUdpDecode(this.client)); //InBoundHandler
//channel.pipeline().addLast(new AgvUdpEncode()); //OutBoundHandler
}
}

View File

@ -11,78 +11,77 @@ import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.opentcs.kc.udp.io.UDPClient;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2024-06-06 10:45
*/
public class AgvUdpDecode extends SimpleChannelInboundHandler<DatagramPacket> {
public class AgvUdpDecode
extends
SimpleChannelInboundHandler<DatagramPacket> {
private UDPClient client;
private UDPClient client;
//授权码16字节 + 报文头8个字节 + 报文数据长度2个字节 + 保留2字节 = 28字节
private static final int HEADER_SIZE = 28;
//授权码16字节 + 报文头8个字节 + 报文数据长度2个字节 + 保留2字节 = 28字节
private static final int HEADER_SIZE = 28;
public AgvUdpDecode(UDPClient client) {
this.client = client;
public AgvUdpDecode(UDPClient client) {
this.client = client;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg)
throws Exception {
//获得应答DatagramPacket提供了content()方法取得报文的实际内容
ByteBuf in = msg.content();
if (in.readableBytes() < HEADER_SIZE) {
throw new Exception("readed bytes < header length");
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg)
throws Exception {
//获得应答DatagramPacket提供了content()方法取得报文的实际内容
ByteBuf in = msg.content();
if (in.readableBytes() < HEADER_SIZE){
throw new Exception("readed bytes < header length");
}
int dataLength = in.getShortLE(24);
if (dataLength < 0) {
throw new Exception("bodyLength [" + dataLength + "] is not right, remote:" + ctx.channel().remoteAddress());
}
int neededLength = HEADER_SIZE + dataLength;
int isDataEnough = in.readableBytes() - neededLength;
//收到的数据是否足够组包
if(isDataEnough<0){
// 不够消息体长度(剩下的buffe组不了消息体),重新去组包
throw new Exception("readed bytes < content length");
}else {
//todo这里重写subscribe 的逻辑,注意要区分是 订阅的还是 主动请求的
//组包成功
byte[] body = new byte[neededLength];
in.readBytes(body);
//System.out.println("received bytes :"+ Arrays.toString(body));
String uuid = body[18]+"-"+body[19];
Package mbPackage = new Package(body,uuid);
byte commandCode = body[21];
if(body[18]==(byte)0x00 && body[19]==(byte)0x00){
//获取响应IP
InetSocketAddress sender = msg.sender();
String hostAddress = sender.getAddress().getHostAddress();
if(commandCode == (byte)0xAF ){
client.subscribe0xAF(new RcvEventPackage(body[22],body));
}else if(commandCode == (byte)0xB0){
client.subscribe0xB0(new RcvEventPackage(body[22],body));
}else {
SendedList.set(uuid , mbPackage);
}
}else {
SendedList.set(uuid , mbPackage);
}
}
int dataLength = in.getShortLE(24);
if (dataLength < 0) {
throw new Exception(
"bodyLength [" + dataLength + "] is not right, remote:" + ctx.channel().remoteAddress()
);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
int neededLength = HEADER_SIZE + dataLength;
int isDataEnough = in.readableBytes() - neededLength;
//收到的数据是否足够组包
if (isDataEnough < 0) {
// 不够消息体长度(剩下的buffe组不了消息体),重新去组包
throw new Exception("readed bytes < content length");
}
else {
//todo这里重写subscribe 的逻辑,注意要区分是 订阅的还是 主动请求的
//组包成功
byte[] body = new byte[neededLength];
in.readBytes(body);
//System.out.println("received bytes :"+ Arrays.toString(body));
String uuid = body[18] + "-" + body[19];
Package mbPackage = new Package(body, uuid);
byte commandCode = body[21];
if (body[18] == (byte) 0x00 && body[19] == (byte) 0x00) {
//获取响应IP
InetSocketAddress sender = msg.sender();
String hostAddress = sender.getAddress().getHostAddress();
if (commandCode == (byte) 0xAF || commandCode == (byte) 0xB0) {
client.subscribeKC(new RcvEventPackage(body[22], body), body);
}
else {
SendedList.set(uuid, mbPackage);
}
}
else {
SendedList.set(uuid, mbPackage);
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}

View File

@ -5,89 +5,90 @@ import java.util.Arrays;
import java.util.List;
import org.opentcs.kc.common.Package;
import org.opentcs.kc.common.byteutils.ByteUtil;
//import org.opentcs.kc.common.byteutils.ByteUtil;
//import org.opentcs.kc.common.byteutils.ByteUtil;
// import org.opentcs.kc.common.byteutils.ByteUtil;
// import org.opentcs.kc.common.byteutils.ByteUtil;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2024/12/27 15:59
*/
public class AgvEvent extends AgvEventHeader implements IAgvEvent, Serializable {
private byte[] bodyLength;
private byte[] retain;
private byte[] body;
public class AgvEvent
extends
AgvEventHeader
implements
IAgvEvent,
Serializable {
private byte[] bodyLength;
private byte[] retain;
private byte[] body;
//for Request
//有content 没有content 传new byte[]
public AgvEvent(Byte commandCode) {
super(commandCode);
//初始化
bodyLength = new byte[]{0x00,0x00};
retain = new byte[]{0x00,0x00};
body = new byte[]{};
}
public AgvEvent(Byte commandCode,byte[] body) {
super(commandCode);
//初始化
bodyLength = new byte[]{0x00,0x00};
retain = new byte[]{0x00,0x00};
if(commandCode.equals(AgvEventConstant.CommandCode_ISSUE_SUBSCRIPTION)){
//依据命令码 构建参数
this.bodyLength = ByteUtil.shortToBytes((short) body.length);
this.body = body;
}
}
//for Request
//有content 没有content 传new byte[]
public AgvEvent(Byte commandCode) {
super(commandCode);
//初始化
bodyLength = new byte[]{0x00, 0x00};
retain = new byte[]{0x00, 0x00};
body = new byte[]{};
}
public void setBody(byte[] body) {
this.bodyLength = ByteUtil.shortToBytes((short) body.length);
this.body = body;
public AgvEvent(Byte commandCode, byte[] body) {
super(commandCode);
//初始化
bodyLength = new byte[]{0x00, 0x00};
retain = new byte[]{0x00, 0x00};
if (commandCode.equals(AgvEventConstant.CommandCode_ISSUE_SUBSCRIPTION)) {
//依据命令码 构建参数
this.bodyLength = ByteUtil.shortToBytes((short) body.length);
this.body = body;
}
}
//for Response
public AgvEvent(Byte serviceCode, Byte commandCode, Byte executionCode) {
super(serviceCode, commandCode, executionCode);
}
public void setBody(byte[] body) {
this.bodyLength = ByteUtil.shortToBytes((short) body.length);
this.body = body;
}
@Override
public Package toBytes() {
List<Byte> headerBytes = getHeaderBytes();
for (Byte b : bodyLength) {
headerBytes.add(b);
}
for (Byte b : retain) {
headerBytes.add(b);
}
for (Byte b : body) {
headerBytes.add(b);
}
byte[] bytes = new byte[headerBytes.size()];
for (int i = 0; i < headerBytes.size(); i++) {
bytes[i] = headerBytes.get(i);
}
return new Package(bytes, getTransationIdString());
}
//for Response
public AgvEvent(Byte serviceCode, Byte commandCode, Byte executionCode) {
super(serviceCode, commandCode, executionCode);
}
public String getTransationIdString() {
return transationId[0]+"-"+transationId[1];
@Override
public Package toBytes() {
List<Byte> headerBytes = getHeaderBytes();
for (Byte b : bodyLength) {
headerBytes.add(b);
}
for (Byte b : retain) {
headerBytes.add(b);
}
for (Byte b : body) {
headerBytes.add(b);
}
byte[] bytes = new byte[headerBytes.size()];
for (int i = 0; i < headerBytes.size(); i++) {
bytes[i] = headerBytes.get(i);
}
return new Package(bytes, getTransationIdString());
}
@Override
public Package toBytes(Object newValue) {
return null;
}
public String getTransationIdString() {
return transationId[0] + "-" + transationId[1];
}
@Override
public String toString() {
return "AgvEvent{" +
"Header=" + headerToString() +
", bodyLength=" + Arrays.toString(bodyLength) +
", body=" + Arrays.toString(body) +
'}';
}
@Override
public Package toBytes(Object newValue) {
return null;
}
@Override
public String protocolName() {
return "";
}
@Override
public String toString() {
return "AgvEvent{" +
"Header=" + headerToString() +
", bodyLength=" + Arrays.toString(bodyLength) +
", body=" + Arrays.toString(body) +
'}';
}
@Override
public String protocolName() {
return "";
}
}

View File

@ -1,38 +1,35 @@
package org.opentcs.kc.udp.agv.param;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2024/12/27 10:19
*/
public class AgvEventConstant {
public static final byte[] AuthorizationCode = new byte[]{ (byte)0xd4 , (byte)0x97 , (byte)0x44 , (byte)0x9c , (byte)0xcb , (byte)0xcf , (byte)0x0b , (byte)0x4c , (byte)0x95 , (byte)0x51 , (byte)0xd8 , (byte)0x61 , (byte)0x70 , (byte)0xf1 , (byte)0xe7 , (byte)0x94};
public static final byte[] AuthorizationCode = new byte[]{(byte) 0xd4, (byte) 0x97, (byte) 0x44,
(byte) 0x9c, (byte) 0xcb, (byte) 0xcf, (byte) 0x0b, (byte) 0x4c, (byte) 0x95, (byte) 0x51,
(byte) 0xd8, (byte) 0x61, (byte) 0x70, (byte) 0xf1, (byte) 0xe7, (byte) 0x94};
public static final byte VersionNum = 0x01;
public static final byte MSGTypeRequest = 0x00;
public static final byte MSGTypeResponse = 0x01;
public static final byte VersionNum = 0x01;
public static final byte MSGTypeRequest = 0x00;
public static final byte MSGTypeResponse = 0x01;
//命令码 开始
public static final byte ServiceCode = 0x10;
//命令码 开始
public static final byte ServiceCode = 0x10;
public static final byte CommandCode_READ = 0x02;
public static final byte CommandCode_WRITE = 0x03;
public static final byte CommandCode_MIXED_ISSUANCE_TASK = (byte) 0xAE;
public static final byte CommandCode_QUERY_ROBOT_STATUS = (byte) 0xAF;
public static final byte CommandCode_QUERY_CARRY_STATUS = (byte) 0xB0;
public static final byte CommandCode_ISSUE_SUBSCRIPTION = (byte) 0xB1;
public static final byte CommandCode_ACT_IMMEDIATELY = (byte) 0xB2;
public static final byte CommandCode_SET_ABILITY= (byte) 0xB7;
public static final byte CommandCode_ROBOT_SET_POSITION= (byte) 0x14;
public static final byte CommandCode_GET_ROBOT_POSITION= (byte) 0x15;
public static final byte CommandCode_NAVIGATION_CONTROL= (byte) 0x16;
public static final byte CommandCode_QUERY_ROBOT_NAVIGATION_STATUS= (byte) 0x1D;
public static final byte CommandCode_QUERY_ROBOT_RUN_STATUS= (byte) 0x17;
public static final byte CommandCode_CONFIRM_ROBOT_POSITION= (byte) 0x1F;
//命令码 结束
public static final byte CommandCode_READ = 0x02;
public static final byte CommandCode_WRITE = 0x03;
public static final byte CommandCode_MIXED_ISSUANCE_TASK = (byte) 0xAE;
public static final byte CommandCode_QUERY_ROBOT_STATUS = (byte) 0xAF;
public static final byte CommandCode_QUERY_CARRY_STATUS = (byte) 0xB0;
public static final byte CommandCode_ISSUE_SUBSCRIPTION = (byte) 0xB1;
public static final byte CommandCode_ACT_IMMEDIATELY = (byte) 0xB2;
public static final byte CommandCode_SET_ABILITY = (byte) 0xB7;
public static final byte CommandCode_ROBOT_SET_POSITION = (byte) 0x14;
public static final byte CommandCode_GET_ROBOT_POSITION = (byte) 0x15;
public static final byte CommandCode_NAVIGATION_CONTROL = (byte) 0x16;
public static final byte CommandCode_QUERY_ROBOT_NAVIGATION_STATUS = (byte) 0x1D;
public static final byte CommandCode_QUERY_ROBOT_RUN_STATUS = (byte) 0x17;
public static final byte CommandCode_CONFIRM_ROBOT_POSITION = (byte) 0x1F;
//命令码 结束
}

View File

@ -6,107 +6,102 @@ import java.util.List;
import org.opentcs.kc.common.CaffeineUtil;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2024-06-07 13:29
*/
public class AgvEventHeader {
//常量区域 开始
//授权码
public byte[] authorizationCode;
//header 开始
//版本号
public byte versionNum;
//报文类型 0x00请求报文 ; 0x01应答报文
public byte msgType;
//request response transationId一致,2个字节
public byte[] transationId;
//服务码
public byte serviceCode;
//命令码用于区分不同命令request response 相同
public byte commandCode;
//执行码应答报文填写表明命令执行情况请求数据包置 0
public byte executionCode;
//保留
public byte retain;
//常量区域 开始
//授权码
public byte[] authorizationCode;
//header 开始
//版本号
public byte versionNum;
//报文类型 0x00请求报文 ; 0x01应答报文
public byte msgType;
//request response transationId一致,2个字节
public byte[] transationId;
//服务码
public byte serviceCode;
//命令码用于区分不同命令request response 相同
public byte commandCode;
//执行码应答报文填写表明命令执行情况请求数据包置 0
public byte executionCode;
//保留
public byte retain;
//header 结束
//常量区域 结束
//header 结束
//常量区域 结束
//request
public AgvEventHeader(Byte commandCode) {
this.authorizationCode = AgvEventConstant.AuthorizationCode;
this.versionNum = AgvEventConstant.VersionNum;
this.msgType = AgvEventConstant.MSGTypeRequest;
//request
public AgvEventHeader(Byte commandCode) {
this.authorizationCode = AgvEventConstant.AuthorizationCode;
this.versionNum = AgvEventConstant.VersionNum;
this.msgType = AgvEventConstant.MSGTypeRequest;
this.transationId = CaffeineUtil.getUUIDAGV();
this.serviceCode = 0x10;
this.commandCode = commandCode;
this.executionCode = 0x00;
this.retain = 0x00;
this.transationId = CaffeineUtil.getUUIDAGV();
this.serviceCode = 0x10;
this.commandCode = commandCode;
this.executionCode = 0x00;
this.retain = 0x00;
}
public AgvEventHeader(byte[] src) {
this.authorizationCode = ByteUtils.copyOfRange(src, 0, 16);
this.versionNum = src[16];
this.msgType = src[17];
this.transationId = ByteUtils.copyOfRange(src, 18, 20);
this.serviceCode = src[20];
this.commandCode = src[21];
this.executionCode = src[22];
this.retain = src[23];
}
//response
public AgvEventHeader(Byte serviceCode, Byte commandCode, Byte executionCode) {
this.authorizationCode = AgvEventConstant.AuthorizationCode;
this.versionNum = AgvEventConstant.VersionNum;
this.msgType = AgvEventConstant.MSGTypeResponse;
this.transationId = CaffeineUtil.getUUIDAGV();
this.serviceCode = serviceCode;
}
public byte[] getTransationId() {
return transationId;
}
public String headerToString() {
return "AgvEventHeader{" +
"authorizationCode=" + Arrays.toString(authorizationCode) +
", versionNum=" + versionNum +
", msgType=" + msgType +
", transationId=" + Arrays.toString(transationId) +
", serviceCode=" + serviceCode +
", commandCode=" + commandCode +
", executionCode=" + executionCode +
", retain=" + retain +
'}';
}
public List<Byte> getHeaderBytes() {
List<Byte> bytes = new ArrayList<>();
//add 授权码
for (byte b : authorizationCode) {
bytes.add(b);
}
public AgvEventHeader(byte[] src){
this.authorizationCode = ByteUtils.copyOfRange(src,0,16);
this.versionNum = src[16];
this.msgType = src[17];
this.transationId = ByteUtils.copyOfRange(src,18,20);
this.serviceCode = src[20];
this.commandCode = src[21];
this.executionCode = src[22];
this.retain = src[23];
}
//response
public AgvEventHeader(Byte serviceCode, Byte commandCode, Byte executionCode) {
this.authorizationCode = AgvEventConstant.AuthorizationCode;
this.versionNum = AgvEventConstant.VersionNum;
this.msgType = AgvEventConstant.MSGTypeResponse;
this.transationId = CaffeineUtil.getUUIDAGV();
this.serviceCode = serviceCode;
}
public byte[] getTransationId() {
return transationId;
}
public String headerToString() {
return "AgvEventHeader{" +
"authorizationCode=" + Arrays.toString(authorizationCode) +
", versionNum=" + versionNum +
", msgType=" + msgType +
", transationId=" + Arrays.toString(transationId) +
", serviceCode=" + serviceCode +
", commandCode=" + commandCode +
", executionCode=" + executionCode +
", retain=" + retain +
'}';
}
public List<Byte> getHeaderBytes(){
List<Byte> bytes = new ArrayList<>();
//add 授权码
for (byte b : authorizationCode) {
bytes.add(b);
}
//add 协议版本号
bytes.add(versionNum);
//add 报文类型
bytes.add(msgType);
//add 报文标识
for (byte b : transationId) {
bytes.add(b);
}
bytes.add(serviceCode);
bytes.add(commandCode);
bytes.add(executionCode);
bytes.add(retain);
return bytes;
//add 协议版本号
bytes.add(versionNum);
//add 报文类型
bytes.add(msgType);
//add 报文标识
for (byte b : transationId) {
bytes.add(b);
}
bytes.add(serviceCode);
bytes.add(commandCode);
bytes.add(executionCode);
bytes.add(retain);
return bytes;
}
}

View File

@ -1,12 +1,14 @@
package org.opentcs.kc.udp.agv.param;
import org.opentcs.kc.common.byteutils.ByteUtil;
import org.opentcs.kc.common.Package;
public interface IAgvEvent {
//read sended
public Package toBytes();
//write sended
public Package toBytes(Object newValue);
import org.opentcs.kc.common.byteutils.ByteUtil;
public String protocolName();
public interface IAgvEvent {
//read sended
public Package toBytes();
//write sended
public Package toBytes(Object newValue);
public String protocolName();
}

View File

@ -2,24 +2,19 @@ package org.opentcs.kc.udp.agv.param.function.af;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/21 10:03
*/
public class AbnormalEventStatusInfo {
private byte[] src;
//事件码,2个字节
public byte[] eventCode;
//异常等级,2个字节
public byte[] abnormalLevel;
//remain,8个字节
public byte[] remain;
private byte[] src;
//事件码,2个字节
public byte[] eventCode;
//异常等级,2个字节
public byte[] abnormalLevel;
//remain,8个字节
public byte[] remain;
public AbnormalEventStatusInfo(byte[] src) {
this.src = src;
this.eventCode = ByteUtils.copyBytes(src, 0, 2);
this.abnormalLevel = ByteUtils.copyBytes(src, 2, 2);
this.remain = ByteUtils.copyBytes(src, 4, 8);
}
public AbnormalEventStatusInfo(byte[] src) {
this.src = src;
this.eventCode = ByteUtils.copyBytes(src, 0, 2);
this.abnormalLevel = ByteUtils.copyBytes(src, 2, 2);
this.remain = ByteUtils.copyBytes(src, 4, 8);
}
}

View File

@ -2,24 +2,19 @@ package org.opentcs.kc.udp.agv.param.function.af;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/21 10:38
*/
public class ActionInfo {
private byte[] src;
//动作 ID,4个字节
public byte[] actionId;
//动作状态,1个字节
public byte actionStatus;
//预留,7个字节
public byte[] remain;
private byte[] src;
//动作 ID,4个字节
public byte[] actionId;
//动作状态,1个字节
public byte actionStatus;
//预留,7个字节
public byte[] remain;
public ActionInfo(byte[] src) {
this.src = src;
this.actionId = ByteUtils.copyBytes(src, 0, 4);
this.actionStatus = src[4];
this.remain = ByteUtils.copyBytes(src,5,7);
}
public ActionInfo(byte[] src) {
this.src = src;
this.actionId = ByteUtils.copyBytes(src, 0, 4);
this.actionStatus = src[4];
this.remain = ByteUtils.copyBytes(src, 5, 7);
}
}

View File

@ -2,34 +2,30 @@ package org.opentcs.kc.udp.agv.param.function.af;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/20 16:28
*/
public class BatteryStatusInfo {
//src
private byte[] src;
//电量百分比
public float batteryPercentage;
//电压
public float voltage;
//电流
public float electricCurrent;
//充电情况,1个字节
public byte chargingState;
//预留,7个字节
public byte[] remain;
public BatteryStatusInfo(byte[] src) {
this.src = src;
this.batteryPercentage = ByteUtils.bytesToFloat(src, 0);
this.voltage = ByteUtils.bytesToFloat(src, 4);
this.electricCurrent = ByteUtils.bytesToFloat(src, 8);
this.chargingState = src[12];
this.remain=new byte[7];
for (int i = 0; i < 7; i++) {
this.remain[i]=src[13+i];
}
//src
private byte[] src;
//电量百分比
public float batteryPercentage;
//电压
public float voltage;
//电流
public float electricCurrent;
//充电情况,1个字节
public byte chargingState;
//预留,7个字节
public byte[] remain;
public BatteryStatusInfo(byte[] src) {
this.src = src;
this.batteryPercentage = ByteUtils.bytesToFloat(src, 0);
this.voltage = ByteUtils.bytesToFloat(src, 4);
this.electricCurrent = ByteUtils.bytesToFloat(src, 8);
this.chargingState = src[12];
this.remain = new byte[7];
for (int i = 0; i < 7; i++) {
this.remain[i] = src[13 + i];
}
}
}

View File

@ -2,79 +2,74 @@ package org.opentcs.kc.udp.agv.param.function.af;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/20 14:56
*/
public class LocationStatusInfo {
private byte[] src;
//4个字节, 全局x,单位 m
public float globalX;
//4个字节, 全局y,单位 m
public float globalY;
//机器人绝对车体方向角,单位 rad
public float absoluteDirecAngle;
//最后通过点 ID
public Integer lastPassPointId;
//最后通过edge ID
public Integer lastPassEdgeId;
//最后通过点在任务中的序列号
public Integer serialNumber;
//置信度,1个字节
public byte confidenceLevel;
//预留8个字节
public byte[] remain;
private byte[] src;
//4个字节, 全局x,单位 m
public float globalX;
//4个字节, 全局y,单位 m
public float globalY;
//机器人绝对车体方向角,单位 rad
public float absoluteDirecAngle;
//最后通过点 ID
public Integer lastPassPointId;
//最后通过edge ID
public Integer lastPassEdgeId;
//最后通过点在任务中的序列号
public Integer serialNumber;
//置信度,1个字节
public byte confidenceLevel;
//预留8个字节
public byte[] remain;
public static void main(String[] args) {
byte[] src = new byte[32];
src[0] = (byte) 0x73;
src[1] = (byte) 0xde;
src[2] = (byte) 0xba;
src[3] = (byte) 0xbd;
public static void main(String[] args) {
byte[] src = new byte[32];
src[0] = (byte) 0x73;
src[1] = (byte) 0xde;
src[2] = (byte) 0xba;
src[3] = (byte) 0xbd;
src[4] = (byte) 0x34;
src[5] = (byte) 0xbf;
src[6] = (byte) 0xd0;
src[7] = (byte) 0x40;
src[4] = (byte) 0x34;
src[5] = (byte) 0xbf;
src[6] = (byte) 0xd0;
src[7] = (byte) 0x40;
src[8] = (byte) 0x59;
src[9] = (byte) 0x3c;
src[10] = (byte) 0x1d;
src[11] = (byte) 0x3d;
System.out.println("x: "+ByteUtils.bytesToFloat(src, 0));
System.out.println("y: "+ByteUtils.bytesToFloat(src, 4));
System.out.println("z: "+ByteUtils.bytesToFloat(src, 8));
src[8] = (byte) 0x59;
src[9] = (byte) 0x3c;
src[10] = (byte) 0x1d;
src[11] = (byte) 0x3d;
System.out.println("x: " + ByteUtils.bytesToFloat(src, 0));
System.out.println("y: " + ByteUtils.bytesToFloat(src, 4));
System.out.println("z: " + ByteUtils.bytesToFloat(src, 8));
}
public LocationStatusInfo(byte[] src) {
this.src = src;
for (byte b : src) {
System.out.print(byteToHex(b) + " ");
}
public LocationStatusInfo(byte[] src) {
this.src = src;
for (byte b:src){
System.out.print(byteToHex(b)+" ");
}
//[115, -34, -70, -67, 52, -65, -48, 64, 89, 60, 29, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
this.globalX = ByteUtils.bytesToFloat(src, 0);
this.globalY = ByteUtils.bytesToFloat(src, 4);
this.absoluteDirecAngle = ByteUtils.bytesToFloat(src, 8);
this.lastPassPointId = ByteUtils.bytesToInt(src, 12);
this.lastPassEdgeId = ByteUtils.bytesToInt(src, 16);
this.serialNumber = ByteUtils.bytesToInt(src, 20);
this.confidenceLevel = src[24];
this.remain = new byte[7];
for (int i = 0; i < 7; i++) {
this.remain[i] = src[25 + i];
}
//[115, -34, -70, -67, 52, -65, -48, 64, 89, 60, 29, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
this.globalX = ByteUtils.bytesToFloat(src, 0);
this.globalY = ByteUtils.bytesToFloat(src, 4);
this.absoluteDirecAngle = ByteUtils.bytesToFloat(src, 8);
this.lastPassPointId = ByteUtils.bytesToInt(src, 12);
this.lastPassEdgeId = ByteUtils.bytesToInt(src, 16);
this.serialNumber = ByteUtils.bytesToInt(src, 20);
this.confidenceLevel = src[24];
this.remain = new byte[7];
for (int i = 0; i < 7; i++) {
this.remain[i] = src[25 + i];
}
}
public static String byteToHex(byte b) {
// 将byte转换为无符号整数
int unsignedByte = b & 0xFF;
// 使用Integer.toHexString方法转换为十六进制字符串
String hexString = Integer.toHexString(unsignedByte);
// 如果字符串长度为1需要在前面补0
if (hexString.length() == 1) {
return "0" + hexString;
}
return hexString;
public static String byteToHex(byte b) {
// 将byte转换为无符号整数
int unsignedByte = b & 0xFF;
// 使用Integer.toHexString方法转换为十六进制字符串
String hexString = Integer.toHexString(unsignedByte);
// 如果字符串长度为1需要在前面补0
if (hexString.length() == 1) {
return "0" + hexString;
}
return hexString;
}
}

View File

@ -2,21 +2,17 @@ package org.opentcs.kc.udp.agv.param.function.af;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/20 15:49
*/
public class PathStateSequence {
//src
private byte[] src;
//序列号,4个字节
public Integer serialNumber;
//序列号
public Integer pathId;
public PathStateSequence(byte[] src) {
this.src = src;
this.serialNumber = ByteUtils.bytesToInt(src, 0);
this.pathId = ByteUtils.bytesToInt(src, 4);
}
//src
private byte[] src;
//序列号,4个字节
public Integer serialNumber;
//序列号
public Integer pathId;
public PathStateSequence(byte[] src) {
this.src = src;
this.serialNumber = ByteUtils.bytesToInt(src, 0);
this.pathId = ByteUtils.bytesToInt(src, 4);
}
}

View File

@ -2,21 +2,17 @@ package org.opentcs.kc.udp.agv.param.function.af;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/20 15:49
*/
public class PointStateSequence {
//src
private byte[] src;
//序列号,4个字节
public Integer serialNumber;
//序列号
public Integer pointId;
public PointStateSequence(byte[] src) {
this.src = src;
this.serialNumber = ByteUtils.bytesToInt(src, 0);
this.pointId = ByteUtils.bytesToInt(src, 4);
}
//src
private byte[] src;
//序列号,4个字节
public Integer serialNumber;
//序列号
public Integer pointId;
public PointStateSequence(byte[] src) {
this.src = src;
this.serialNumber = ByteUtils.bytesToInt(src, 0);
this.pointId = ByteUtils.bytesToInt(src, 4);
}
}

View File

@ -1,50 +1,65 @@
package org.opentcs.kc.udp.agv.param.function.af;
import java.util.ArrayList;
import java.util.List;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/20 14:55
*/
public class QueryRobotStatusRsp {
private byte[] src;
public byte abnormal_size;
public byte action_size;
//预留2个字节
public byte[] remain;
public LocationStatusInfo locationStatusInfo;
public RunningStatusInfo runningStatusInfo;
public TaskStatusInfo taskStatusInfo;
public BatteryStatusInfo batteryStatusInfo;
public List<AbnormalEventStatusInfo> abnormalEventStatusInfoList;
public List<ActionInfo> actionInfoList;
public QueryRobotStatusRsp(byte[] src) {
this.src = src;
this.abnormal_size = src[0];
this.action_size = src[1];
this.remain = ByteUtils.copyBytes(src,2,2); //index 2
this.locationStatusInfo = new LocationStatusInfo(ByteUtils.copyBytes(src,4,32));
this.runningStatusInfo = new RunningStatusInfo(ByteUtils.copyBytes(src,36,20));
Integer pointSize = ByteUtils.toInt(src[60]);
Integer edgeSize = ByteUtils.toInt(src[61]);
Integer taskByteSize = 12+8*(pointSize+edgeSize);
this.taskStatusInfo = new TaskStatusInfo(ByteUtils.copyBytes(src,56,taskByteSize));
this.batteryStatusInfo = new BatteryStatusInfo(ByteUtils.copyBytes(src,56+taskByteSize,20));
if(this.abnormal_size>0){
for(int i=0;i<this.abnormal_size;i++){
this.abnormalEventStatusInfoList.add(new AbnormalEventStatusInfo(ByteUtils.copyBytes(src,56+taskByteSize+20+12*i,12)));
}
}
if(this.action_size>0){
for(int i=0;i<this.action_size;i++){
this.actionInfoList.add(new ActionInfo(ByteUtils.copyBytes(src,56+taskByteSize+20+12*this.abnormal_size+12*i,12)));
}
}
private byte[] src;
public byte abnormal_size;
public byte action_size;
//预留2个字节
public byte[] remain;
public LocationStatusInfo locationStatusInfo;
public RunningStatusInfo runningStatusInfo;
public TaskStatusInfo taskStatusInfo;
public BatteryStatusInfo batteryStatusInfo;
public List<AbnormalEventStatusInfo> abnormalEventStatusInfoList;
public List<ActionInfo> actionInfoList;
public QueryRobotStatusRsp(byte[] src) {
if (src == null) {
throw new RuntimeException("method_QueryRobotStatusRsp_params_src_is_NUll");
}
this.src = src;
this.abnormal_size = src[0];
this.action_size = src[1];
this.remain = ByteUtils.copyBytes(src, 2, 2); //index 2
this.locationStatusInfo = new LocationStatusInfo(ByteUtils.copyBytes(src, 4, 32));
this.runningStatusInfo = new RunningStatusInfo(ByteUtils.copyBytes(src, 36, 20));
Integer pointSize = ByteUtils.toInt(src[60]);
Integer edgeSize = ByteUtils.toInt(src[61]);
Integer taskByteSize = 12 + 8 * (pointSize + edgeSize);
this.taskStatusInfo = new TaskStatusInfo(ByteUtils.copyBytes(src, 56, taskByteSize));
this.batteryStatusInfo = new BatteryStatusInfo(ByteUtils.copyBytes(src, 56 + taskByteSize, 20));
if (this.abnormal_size > 0) {
if (this.abnormalEventStatusInfoList == null) {
this.abnormalEventStatusInfoList = new ArrayList<>();
}
for (int i = 0; i < this.abnormal_size; i++) {
this.abnormalEventStatusInfoList.add(
new AbnormalEventStatusInfo(
ByteUtils.copyBytes(src, 56 + taskByteSize + 20 + 12 * i, 12)
)
);
}
}
if (this.action_size > 0) {
if (this.actionInfoList == null) {
this.actionInfoList = new ArrayList<>();
}
for (int i = 0; i < this.action_size; i++) {
this.actionInfoList.add(
new ActionInfo(
ByteUtils.copyBytes(
src, 56 + taskByteSize + 20 + 12 * this.abnormal_size + 12 * i, 12
)
)
);
}
}
}
}

View File

@ -2,39 +2,34 @@ package org.opentcs.kc.udp.agv.param.function.af;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/20 15:22
*/
public class RunningStatusInfo {
private byte[] src;
//4个字节, 轴x 速度,单位 m/s
public float speedX;
//4个字节, 轴y 速度,单位 m/s
public float speedY;
//车角速度,单位 rad/s
public float angularSpeed;
//工作模式
public byte workMode;
//agv 状态1个字节
public byte agvStatus;
//机器人能力集设置状态,1个字节
public byte abilitySetStatus;
//预留,5个字节
public byte[] remain;
private byte[] src;
//4个字节, 轴x 速度,单位 m/s
public float speedX;
//4个字节, 轴y 速度,单位 m/s
public float speedY;
//车角速度,单位 rad/s
public float angularSpeed;
//工作模式
public byte workMode;
//agv 状态1个字节
public byte agvStatus;
//机器人能力集设置状态,1个字节
public byte abilitySetStatus;
//预留,5个字节
public byte[] remain;
public RunningStatusInfo(byte[] src) {
this.src = src;
this.speedX = ByteUtils.bytesToFloat(src, 0);
this.speedY = ByteUtils.bytesToFloat(src, 4);
this.angularSpeed = ByteUtils.bytesToFloat(src, 8);
this.workMode = src[12];
this.agvStatus = src[13];
this.abilitySetStatus = src[14];
this.remain = new byte[5];
for (int i = 0; i < 5; i++) {
this.remain[i] = src[15 + i];
}
public RunningStatusInfo(byte[] src) {
this.src = src;
this.speedX = ByteUtils.bytesToFloat(src, 0);
this.speedY = ByteUtils.bytesToFloat(src, 4);
this.angularSpeed = ByteUtils.bytesToFloat(src, 8);
this.workMode = src[12];
this.agvStatus = src[13];
this.abilitySetStatus = src[14];
this.remain = new byte[5];
for (int i = 0; i < 5; i++) {
this.remain[i] = src[15 + i];
}
}
}

View File

@ -2,48 +2,44 @@ package org.opentcs.kc.udp.agv.param.function.af;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/20 15:22
*/
public class TaskStatusInfo {
private byte[] src;
//订单 ID
public Integer orderId;
//任务 KEY
public Integer taskKey;
//点状态序列数量
public Integer pointStatusNum;
//段状态序列数量
public Integer edgeStatusNum;
//预留,2个字节
public byte[] remain;
//点状态序列
public PointStateSequence[] pointStatusInfo;
//段状态序列
public PathStateSequence[] pathStatusInfo;
private byte[] src;
//订单 ID
public Integer orderId;
//任务 KEY
public Integer taskKey;
//点状态序列数量
public Integer pointStatusNum;
//段状态序列数量
public Integer edgeStatusNum;
//预留,2个字节
public byte[] remain;
//点状态序列
public PointStateSequence[] pointStatusInfo;
//段状态序列
public PathStateSequence[] pathStatusInfo;
public TaskStatusInfo(byte[] src) {
this.src = src;
this.orderId = ByteUtils.bytesToInt(src, 0);
this.taskKey = ByteUtils.bytesToInt(src, 4);
public TaskStatusInfo(byte[] src) {
this.src = src;
this.orderId = ByteUtils.bytesToInt(src, 0);
this.taskKey = ByteUtils.bytesToInt(src, 4);
this.pointStatusNum = ByteUtils.toInt(src[8]);
this.edgeStatusNum = ByteUtils.toInt(src[9]);
this.remain = ByteUtils.copyBytes(src, 10, 2);
if (pointStatusNum > 0) {
this.pointStatusInfo = new PointStateSequence[pointStatusNum];
for (int i = 0; i < pointStatusNum; i++) {
this.pointStatusInfo[i] = new PointStateSequence(ByteUtils.copyBytes(src, 12 + 8 * i, 8));
}
}
if (edgeStatusNum > 0) {
this.pathStatusInfo = new PathStateSequence[edgeStatusNum];
for (int i = 0; i < edgeStatusNum; i++) {
this.pathStatusInfo[i] = new PathStateSequence(ByteUtils.copyBytes(src, 12 + pointStatusNum*8 + 8 * pointStatusNum + 8 * i, 8));
}
}
this.pointStatusNum = ByteUtils.toInt(src[8]);
this.edgeStatusNum = ByteUtils.toInt(src[9]);
this.remain = ByteUtils.copyBytes(src, 10, 2);
if (pointStatusNum > 0) {
this.pointStatusInfo = new PointStateSequence[pointStatusNum];
for (int i = 0; i < pointStatusNum; i++) {
this.pointStatusInfo[i] = new PointStateSequence(ByteUtils.copyBytes(src, 12 + 8 * i, 8));
}
}
if (edgeStatusNum > 0) {
this.pathStatusInfo = new PathStateSequence[edgeStatusNum];
for (int i = 0; i < edgeStatusNum; i++) {
this.pathStatusInfo[i] = new PathStateSequence(
ByteUtils.copyBytes(src, 12 + pointStatusNum * 8 + 8 * pointStatusNum + 8 * i, 8)
);
}
}
}
}

View File

@ -2,22 +2,17 @@ package org.opentcs.kc.udp.agv.param.function.b0;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/23 13:34
*/
public class QueryCargoStatusRsp {
//src
private byte[] src;
//是否载货
public byte isCargo;
//预留,3个字节
public byte[] reserved;
//src
private byte[] src;
//是否载货
public byte isCargo;
//预留,3个字节
public byte[] reserved;
public QueryCargoStatusRsp(byte[] src) {
this.src = src;
this.isCargo = src[0];
this.reserved = ByteUtils.copyBytes(src, 1, 3);
}
public QueryCargoStatusRsp(byte[] src) {
this.src = src;
this.isCargo = src[0];
this.reserved = ByteUtils.copyBytes(src, 1, 3);
}
}

View File

@ -2,25 +2,20 @@ package org.opentcs.kc.udp.agv.param.function.b1;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/23 14:30
*/
public class SubscribeInfo {
//站控协议命令码2个字节
public byte[] commandCode;
//上报间隔时间 ,单位ms 2个字节
public byte[] intervalTime;
//上报持续时间,单位ms 4个字节
public byte[] durationTime;
//预留,8个字节
public byte[] reserved;
//站控协议命令码2个字节
public byte[] commandCode;
//上报间隔时间 ,单位ms 2个字节
public byte[] intervalTime;
//上报持续时间,单位ms 4个字节
public byte[] durationTime;
//预留,8个字节
public byte[] reserved;
public SubscribeInfo(byte[] commandCode, Short intervalTime, Integer durationTime) {
this.commandCode = commandCode;
this.intervalTime = ByteUtils.shortToBytes(intervalTime);
this.durationTime = ByteUtils.intToBytes(durationTime,4);
this.reserved = new byte[8];
}
public SubscribeInfo(byte[] commandCode, Short intervalTime, Integer durationTime) {
this.commandCode = commandCode;
this.intervalTime = ByteUtils.shortToBytes(intervalTime);
this.durationTime = ByteUtils.intToBytes(durationTime, 4);
this.reserved = new byte[8];
}
}

View File

@ -4,67 +4,63 @@ import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/1/23 14:23
*/
public class SubscribeParam {
private byte[] src;
private List<SubscribeInfo> subscribeInfoList;
//uuid,64个字节
private byte[] uuid;
public SubscribeParam(List<SubscribeInfo> subscribeInfoList) {
this.subscribeInfoList = subscribeInfoList;
this.uuid = generate64ByteUUID();
private byte[] src;
private List<SubscribeInfo> subscribeInfoList;
//uuid,64个字节
private byte[] uuid;
public SubscribeParam(List<SubscribeInfo> subscribeInfoList) {
this.subscribeInfoList = subscribeInfoList;
this.uuid = generate64ByteUUID();
}
public byte[] getUuid() {
return uuid;
}
// 生成 64 字节长度的 UUID返回 byte[] 类型
public static byte[] generate64ByteUUID() {
// 创建 SecureRandom 实例用于生成安全的随机数
SecureRandom secureRandom = new SecureRandom();
// 定义一个长度为 64 的字节数组
byte[] uuidBytes = new byte[64];
// 使用 SecureRandom 生成随机字节填充字节数组
secureRandom.nextBytes(uuidBytes);
return uuidBytes;
}
public byte[] toBytes() {
src = new byte[192];
List<Byte> bytes = new ArrayList<>();
for (SubscribeInfo subscribeInfo : subscribeInfoList) {
bytes.add(subscribeInfo.commandCode[0]);
bytes.add(subscribeInfo.commandCode[1]);
bytes.add(subscribeInfo.intervalTime[0]);
bytes.add(subscribeInfo.intervalTime[1]);
bytes.add(subscribeInfo.durationTime[0]);
bytes.add(subscribeInfo.durationTime[1]);
bytes.add(subscribeInfo.durationTime[2]);
bytes.add(subscribeInfo.durationTime[3]);
bytes.add(subscribeInfo.reserved[0]);
bytes.add(subscribeInfo.reserved[1]);
bytes.add(subscribeInfo.reserved[2]);
bytes.add(subscribeInfo.reserved[3]);
bytes.add(subscribeInfo.reserved[4]);
bytes.add(subscribeInfo.reserved[5]);
bytes.add(subscribeInfo.reserved[6]);
bytes.add(subscribeInfo.reserved[7]);
}
public byte[] getUuid() {
return uuid;
for (int i = 0; i < bytes.size(); i++) {
src[i] = bytes.get(i);
}
for (int i = 0; i < uuid.length; i++) {
src[i + 128] = uuid[i];
}
// 生成 64 字节长度的 UUID返回 byte[] 类型
public static byte[] generate64ByteUUID() {
// 创建 SecureRandom 实例用于生成安全的随机数
SecureRandom secureRandom = new SecureRandom();
// 定义一个长度为 64 的字节数组
byte[] uuidBytes = new byte[64];
// 使用 SecureRandom 生成随机字节填充字节数组
secureRandom.nextBytes(uuidBytes);
return uuidBytes;
}
public byte[] toBytes(){
src = new byte[192];
List<Byte> bytes = new ArrayList<>();
for (SubscribeInfo subscribeInfo : subscribeInfoList) {
bytes.add(subscribeInfo.commandCode[0]);
bytes.add(subscribeInfo.commandCode[1]);
bytes.add(subscribeInfo.intervalTime[0]);
bytes.add(subscribeInfo.intervalTime[1]);
bytes.add(subscribeInfo.durationTime[0]);
bytes.add(subscribeInfo.durationTime[1]);
bytes.add(subscribeInfo.durationTime[2]);
bytes.add(subscribeInfo.durationTime[3]);
bytes.add(subscribeInfo.reserved[0]);
bytes.add(subscribeInfo.reserved[1]);
bytes.add(subscribeInfo.reserved[2]);
bytes.add(subscribeInfo.reserved[3]);
bytes.add(subscribeInfo.reserved[4]);
bytes.add(subscribeInfo.reserved[5]);
bytes.add(subscribeInfo.reserved[6]);
bytes.add(subscribeInfo.reserved[7]);
}
for (int i = 0; i < bytes.size(); i++) {
src[i] = bytes.get(i);
}
for (int i = 0; i < uuid.length; i++) {
src[i+128] = uuid[i];
}
return src;
}
return src;
}
}

View File

@ -2,32 +2,29 @@ package org.opentcs.kc.udp.agv.param.function.b1;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/2/5 14:21
*/
public class SubscribeRsp {
//源数组
private byte[] src;
//uuid 64个字节
private byte[] uuid;
//errCode 1个字节
private byte errCode;
//reserved 3个字节
private byte[] reserved;
public SubscribeRsp(byte[] src) {
this.src = src;
this.uuid = ByteUtils.copyOfRange(src,0,64);
this.errCode = src[64];
this.reserved = ByteUtils.copyOfRange(src,65,3);
}
//源数组
private byte[] src;
//uuid 64个字节
private byte[] uuid;
//errCode 1个字节
private byte errCode;
//reserved 3个字节
private byte[] reserved;
public boolean isOk(){
if(this.errCode==0){
return true;
}else {
return false;
}
public SubscribeRsp(byte[] src) {
this.src = src;
this.uuid = ByteUtils.copyOfRange(src, 0, 64);
this.errCode = src[64];
this.reserved = ByteUtils.copyOfRange(src, 65, 3);
}
public boolean isOk() {
if (this.errCode == 0) {
return true;
}
else {
return false;
}
}
}

View File

@ -4,50 +4,47 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/2/8 10:05
*/
public class Action {
//动作类型,2个字节
private byte[] actionType;
//执行动作并行方式,1个字节
private byte actionParallel;
//预留1个字节
private byte actionRetain;
//动作 id,4个字节actionId 自己定义不要重复就行可以从0开始累加
private byte[] actionId;
//参数长度,1个字节
private byte paramSize;
//预留3个字节
private byte[] paramRetain2;
//参数内容,这里的长度 paramSize 长度,todo 注意 这里的paramContent 需要字节去构建一下 目前 这里还没有
private byte[] paramContent;
//动作类型,2个字节
private byte[] actionType;
//执行动作并行方式,1个字节
private byte actionParallel;
//预留1个字节
private byte actionRetain;
//动作 id,4个字节actionId 自己定义不要重复就行可以从0开始累加
private byte[] actionId;
//参数长度,1个字节
private byte paramSize;
//预留3个字节
private byte[] paramRetain2;
//参数内容,这里的长度 paramSize 长度,todo 注意 这里的paramContent 需要字节去构建一下 目前 这里还没有
private byte[] paramContent;
public Action(byte actionType, byte actionParallel, Integer actionId, Integer paramSize, byte[] paramContent) {
this.actionType = new byte[]{actionType, (byte)0x00};
this.actionParallel = actionParallel;
this.actionRetain = (byte)0x00;
this.actionId = ByteUtils.intToBytes(actionId,1);
this.paramSize = ByteUtils.usintTo1Byte(paramSize);
this.paramRetain2 = new byte[]{(byte)0x00, (byte)0x00,(byte)0x00};
this.paramContent = paramContent;
}
public Action(
byte actionType, byte actionParallel, Integer actionId, Integer paramSize, byte[] paramContent
) {
this.actionType = new byte[]{actionType, (byte) 0x00};
this.actionParallel = actionParallel;
this.actionRetain = (byte) 0x00;
this.actionId = ByteUtils.intToBytes(actionId, 1);
this.paramSize = ByteUtils.usintTo1Byte(paramSize);
this.paramRetain2 = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00};
this.paramContent = paramContent;
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(actionType);
byteBuf.writeByte(actionParallel);
byteBuf.writeByte(actionRetain);
byteBuf.writeBytes(actionId);
byteBuf.writeByte(paramSize);
byteBuf.writeBytes(paramRetain2);
byteBuf.writeBytes(paramContent);
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
return bytes;
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(actionType);
byteBuf.writeByte(actionParallel);
byteBuf.writeByte(actionRetain);
byteBuf.writeBytes(actionId);
byteBuf.writeByte(paramSize);
byteBuf.writeBytes(paramRetain2);
byteBuf.writeBytes(paramContent);
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
return bytes;
}
}

View File

@ -4,74 +4,71 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/2/10 8:56
*/
public class ActionSet {
public static void main(String[] args) {
byte[] stop = stop0x01(1, (byte) 0x01);
System.out.println();
}
public static void main(String[] args) {
byte[] stop = stop0x01(1, (byte) 0x01);
System.out.println();
}
public static byte stop0x01 = 0x01;
public static byte recover0x02 = 0x02;
public static byte cancelTask0x03 = 0x03;
public static byte forkliftElevation0x12 = 0x12;
public static byte trayElevation0x16 = 0x16;
public static byte stop0x01 = 0x01;
public static byte recover0x02 = 0x02;
public static byte cancelTask0x03 = 0x03;
public static byte forkliftElevation0x12 = 0x12;
public static byte trayElevation0x16 = 0x16;
public static Integer stop0x01_paramsize = 8;
public static Integer recover0x02_paramsize = 8;
public static Integer cancelTask0x03_paramsize = 8;
public static Integer forkliftElevation0x12_paramsize = 8;
public static Integer trayElevation0x16_paramsize = 4;
public static Integer stop0x01_paramsize = 8;
public static Integer recover0x02_paramsize = 8;
public static Integer cancelTask0x03_paramsize = 8;
public static Integer forkliftElevation0x12_paramsize = 8;
public static Integer trayElevation0x16_paramsize = 4;
public static byte[] stop0x01(Integer orderId,byte isStopImmediately){
ByteBuf byteBuf = Unpooled.buffer(8);
byteBuf.writeBytes(ByteUtils.intToBytes(orderId,1));
byteBuf.writeByte(isStopImmediately);
return byteBuf.array();
}
public static byte[] stop0x01(Integer orderId, byte isStopImmediately) {
ByteBuf byteBuf = Unpooled.buffer(8);
byteBuf.writeBytes(ByteUtils.intToBytes(orderId, 1));
byteBuf.writeByte(isStopImmediately);
return byteBuf.array();
}
public static byte[] recover0x02(Integer orderId,Integer taskKey){
ByteBuf byteBuf = Unpooled.buffer(8);
byteBuf.writeBytes(ByteUtils.intToBytes(orderId,1));
byteBuf.writeBytes(ByteUtils.intToBytes(taskKey,1));
return byteBuf.array();
}
public static byte[] recover0x02(Integer orderId, Integer taskKey) {
ByteBuf byteBuf = Unpooled.buffer(8);
byteBuf.writeBytes(ByteUtils.intToBytes(orderId, 1));
byteBuf.writeBytes(ByteUtils.intToBytes(taskKey, 1));
return byteBuf.array();
}
//取消任务
public static byte[] cancelTask0x03(Integer orderId,byte isStopImmediately){
ByteBuf byteBuf = Unpooled.buffer(8);
byteBuf.writeBytes(ByteUtils.intToBytes(orderId,1));
byteBuf.writeByte(isStopImmediately);
return byteBuf.array();
}
//取消任务
public static byte[] cancelTask0x03(Integer orderId, byte isStopImmediately) {
ByteBuf byteBuf = Unpooled.buffer(8);
byteBuf.writeBytes(ByteUtils.intToBytes(orderId, 1));
byteBuf.writeByte(isStopImmediately);
return byteBuf.array();
}
/**
* desc:叉齿升降
* 支持的命令0xAE 0xB2
*
* */
/**
* desc:叉齿升降
* 支持的命令0xAE 0xB2
*
*/
public static byte[] forkliftElevation0x12(float lifitingHeight,byte hightMean,byte moveType, byte taskOperationType){
ByteBuf byteBuf = Unpooled.buffer(8);
byteBuf.writeBytes(ByteUtils.floatToBytes(lifitingHeight));
byteBuf.writeByte(hightMean);
byteBuf.writeByte(moveType);
byteBuf.writeByte(taskOperationType);
return byteBuf.array();
}
public static byte[] forkliftElevation0x12(
float lifitingHeight, byte hightMean, byte moveType, byte taskOperationType
) {
ByteBuf byteBuf = Unpooled.buffer(8);
byteBuf.writeBytes(ByteUtils.floatToBytes(lifitingHeight));
byteBuf.writeByte(hightMean);
byteBuf.writeByte(moveType);
byteBuf.writeByte(taskOperationType);
return byteBuf.array();
}
//托盘升降
public static byte[] trayElevation0x16(byte palletMovementMode){
ByteBuf byteBuf = Unpooled.buffer(4);
byteBuf.writeByte(palletMovementMode);
return byteBuf.array();
}
//托盘升降
public static byte[] trayElevation0x16(byte palletMovementMode) {
ByteBuf byteBuf = Unpooled.buffer(4);
byteBuf.writeByte(palletMovementMode);
return byteBuf.array();
}
}

View File

@ -4,54 +4,51 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: "0xAE 导航参数"
* @Author: caixiang
* @DATE: 2024/12/30 15:44
*/
public class NavigationParam {
//订单 ID,4个字节 ,Integer,从1开始依次累加
private byte[] orderId;
//任务 KEY,4个字节,Integer,从1开始依次累加
private byte[] taskKey;
//路径点信息个数单条任务最大支持 8 个路径点,1个字节 ,byte
private byte pointNum;
//路径信息个数单条任务最大支持 8 个路径点,1个字节,byte
private byte pathNum;
//保留,2个字节
private byte[] retain;
//任务中路径点信息结构体,长度 pointNum
private Point[] points;
//任务中路径信息结构体长度 pathNum
private Path[] paths;
//订单 ID,4个字节 ,Integer,从1开始依次累加
private byte[] orderId;
//任务 KEY,4个字节,Integer,从1开始依次累加
private byte[] taskKey;
//路径点信息个数单条任务最大支持 8 个路径点,1个字节 ,byte
private byte pointNum;
//路径信息个数单条任务最大支持 8 个路径点,1个字节,byte
private byte pathNum;
//保留,2个字节
private byte[] retain;
//任务中路径点信息结构体,长度 pointNum
private Point[] points;
//任务中路径信息结构体长度 pathNum
private Path[] paths;
public NavigationParam(Integer orderId, Integer taskKey, byte pointNum, byte pathNum, Point[] points, Path[] paths) {
this.orderId = ByteUtils.intToBytes(orderId,1);
this.taskKey = ByteUtils.intToBytes(taskKey,1);
this.pointNum = pointNum;
this.pathNum = pathNum;
this.retain = new byte[]{(byte)0x00, (byte)0x00};
this.points = points;
this.paths = paths;
public NavigationParam(
Integer orderId, Integer taskKey, byte pointNum, byte pathNum, Point[] points, Path[] paths
) {
this.orderId = ByteUtils.intToBytes(orderId, 1);
this.taskKey = ByteUtils.intToBytes(taskKey, 1);
this.pointNum = pointNum;
this.pathNum = pathNum;
this.retain = new byte[]{(byte) 0x00, (byte) 0x00};
this.points = points;
this.paths = paths;
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(orderId);
byteBuf.writeBytes(taskKey);
byteBuf.writeByte(pointNum);
byteBuf.writeByte(pathNum);
byteBuf.writeBytes(retain);
for (Point point : points) {
byteBuf.writeBytes(point.toBytes());
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(orderId);
byteBuf.writeBytes(taskKey);
byteBuf.writeByte(pointNum);
byteBuf.writeByte(pathNum);
byteBuf.writeBytes(retain);
for (Point point : points) {
byteBuf.writeBytes(point.toBytes());
}
for (Path path : paths) {
byteBuf.writeBytes(path.toBytes());
}
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
return bytes;
for (Path path : paths) {
byteBuf.writeBytes(path.toBytes());
}
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
return bytes;
}
}

View File

@ -4,71 +4,71 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/2/8 9:39
*/
public class Path {
//序列号,4个字节,Integer,用于定位段在整个任务中的位置 1 开始奇数递增 135......point 2 4 6这样path 和point就可以结合起来了以区分同一个段 ID 在任务中是否多次出现
private byte[] serialNum;
// ID,4个字节,Integer
private byte[] pathId;
//指定角度时路径点的车头角度,4个字节,float , isSpecifyAngle==1 的时候这个字段才生效
private byte[] angle;
//是否指定路径点角度,1个字节,byte,1 表示指定0 表示不指定
private byte isSpecifyAngle;
//序列号,4个字节,Integer,用于定位段在整个任务中的位置 1 开始奇数递增 135......point 2 4 6这样path 和point就可以结合起来了以区分同一个段 ID 在任务中是否多次出现
private byte[] serialNum;
// ID,4个字节,Integer
private byte[] pathId;
//指定角度时路径点的车头角度,4个字节,float , isSpecifyAngle==1 的时候这个字段才生效
private byte[] angle;
//是否指定路径点角度,1个字节,byte,1 表示指定0 表示不指定
private byte isSpecifyAngle;
//行驶姿态,1个字节,byte
private byte drivePose;
//任务中边上动作信息个数,1个字节,byte
private byte pathActionSize;
//保留,1个字节
private byte pathRetain;
//指定的目标最大速度,4个字节,float
private byte[] maxSpeed;
//指定的目标最大角速度,4个字节,float
private byte[] maxAngularSpeed;
//预留4个字节
private byte[] pathRetain2;
//行驶姿态,1个字节,byte
private byte drivePose;
//任务中边上动作信息个数,1个字节,byte
private byte pathActionSize;
//保留,1个字节
private byte pathRetain;
//指定的目标最大速度,4个字节,float
private byte[] maxSpeed;
//指定的目标最大角速度,4个字节,float
private byte[] maxAngularSpeed;
//预留4个字节
private byte[] pathRetain2;
//任务中点上动作结构体,这里数组的长度是 pathActionSize 长度
private Action[] actions;
//任务中点上动作结构体,这里数组的长度是 pathActionSize 长度
private Action[] actions;
public Path(Integer serialNum, Integer pathId, float angle, byte isSpecifyAngle, byte drivePose, byte pathActionSize, float maxSpeed, float maxAngularSpeed, Action[] actions) {
this.serialNum = ByteUtils.intToBytes(serialNum,1);
this.pathId = ByteUtils.intToBytes(pathId,1);
this.angle = ByteUtils.floatToBytes(angle);
this.isSpecifyAngle = isSpecifyAngle;
this.drivePose = drivePose;
this.pathActionSize = pathActionSize;
this.pathRetain = (byte)0x00;
this.maxSpeed = ByteUtils.floatToBytes(maxSpeed);
this.maxAngularSpeed = ByteUtils.floatToBytes(maxAngularSpeed);
this.pathRetain2 = new byte[]{(byte)0x00, (byte)0x00,(byte)0x00,(byte)0x00};
this.actions = actions;
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(serialNum);
byteBuf.writeBytes(pathId);
byteBuf.writeBytes(angle);
byteBuf.writeByte(isSpecifyAngle);
byteBuf.writeByte(drivePose);
byteBuf.writeByte(pathActionSize);
byteBuf.writeByte(pathRetain);
byteBuf.writeBytes(maxSpeed);
byteBuf.writeBytes(maxAngularSpeed);
byteBuf.writeBytes(pathRetain2);
for (Action action : actions) {
byteBuf.writeBytes(action.toBytes());
}
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
return bytes;
public Path(
Integer serialNum, Integer pathId, float angle, byte isSpecifyAngle, byte drivePose,
byte pathActionSize, float maxSpeed, float maxAngularSpeed, Action[] actions
) {
this.serialNum = ByteUtils.intToBytes(serialNum, 1);
this.pathId = ByteUtils.intToBytes(pathId, 1);
this.angle = ByteUtils.floatToBytes(angle);
this.isSpecifyAngle = isSpecifyAngle;
this.drivePose = drivePose;
this.pathActionSize = pathActionSize;
this.pathRetain = (byte) 0x00;
this.maxSpeed = ByteUtils.floatToBytes(maxSpeed);
this.maxAngularSpeed = ByteUtils.floatToBytes(maxAngularSpeed);
this.pathRetain2 = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
this.actions = actions;
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(serialNum);
byteBuf.writeBytes(pathId);
byteBuf.writeBytes(angle);
byteBuf.writeByte(isSpecifyAngle);
byteBuf.writeByte(drivePose);
byteBuf.writeByte(pathActionSize);
byteBuf.writeByte(pathRetain);
byteBuf.writeBytes(maxSpeed);
byteBuf.writeBytes(maxAngularSpeed);
byteBuf.writeBytes(pathRetain2);
if (actions != null) {
for (Action action : actions) {
byteBuf.writeBytes(action.toBytes());
}
}
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
return bytes;
}
}

View File

@ -4,51 +4,52 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/2/8 9:39
*/
public class Point {
//序列号,4个字节,Integer,用于定位点在整个任务中的位置 0 开始偶数递增 0246......以区分同一个点 ID 在任务中是否多次出现
private byte[] serialNum;
//路径点 ID,4个字节,Integer
private byte[] pointId;
//指定角度时路径点的车头角度,4个字节,float , isSpecifyAngle==1 的时候这个字段才生效
private byte[] angle;
//是否指定路径点角度,1个字节,byte,1 表示指定0 表示不指定
private byte isSpecifyAngle;
//任务中点上动作信息个数,1个字节,byte
private byte pointActionSize;
//保留,6个字节
private byte[] pointRetain;
//任务中点上动作结构体,这里数组的长度是 pointActionSize 长度
private Action[] actions;
//序列号,4个字节,Integer,用于定位点在整个任务中的位置 0 开始偶数递增 0246......以区分同一个点 ID 在任务中是否多次出现
private byte[] serialNum;
//路径点 ID,4个字节,Integer
private byte[] pointId;
//指定角度时路径点的车头角度,4个字节,float , isSpecifyAngle==1 的时候这个字段才生效
private byte[] angle;
//是否指定路径点角度,1个字节,byte,1 表示指定0 表示不指定
private byte isSpecifyAngle;
//任务中点上动作信息个数,1个字节,byte
private byte pointActionSize;
//保留,6个字节
private byte[] pointRetain;
//任务中点上动作结构体,这里数组的长度是 pointActionSize 长度
private Action[] actions;
public Point(Integer serialNum, Integer pointId, float angle, byte isSpecifyAngle, byte pointActionSize, Action[] actions) {
this.serialNum = ByteUtils.intToBytes(serialNum,1);
this.pointId = ByteUtils.intToBytes(pointId,1);
this.angle = ByteUtils.floatToBytes(angle);
this.isSpecifyAngle = isSpecifyAngle;
this.pointActionSize = pointActionSize;
this.pointRetain = new byte[]{(byte)0x00, (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00};
this.actions = actions;
}
public Point(
Integer serialNum, Integer pointId, float angle, byte isSpecifyAngle, byte pointActionSize,
Action[] actions
) {
this.serialNum = ByteUtils.intToBytes(serialNum, 1);
this.pointId = ByteUtils.intToBytes(pointId, 1);
this.angle = ByteUtils.floatToBytes(angle);
this.isSpecifyAngle = isSpecifyAngle;
this.pointActionSize = pointActionSize;
this.pointRetain = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00};
this.actions = actions;
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(serialNum);
byteBuf.writeBytes(pointId);
byteBuf.writeBytes(angle);
byteBuf.writeByte(isSpecifyAngle);
byteBuf.writeByte(pointActionSize);
byteBuf.writeBytes(pointRetain);
for (Action action : actions) {
byteBuf.writeBytes(action.toBytes());
}
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
return bytes;
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(serialNum);
byteBuf.writeBytes(pointId);
byteBuf.writeBytes(angle);
byteBuf.writeByte(isSpecifyAngle);
byteBuf.writeByte(pointActionSize);
byteBuf.writeBytes(pointRetain);
if (actions != null) {
for (Action action : actions) {
byteBuf.writeBytes(action.toBytes());
}
}
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
return bytes;
}
}

View File

@ -4,48 +4,44 @@ import java.util.ArrayList;
import java.util.List;
import org.opentcs.kc.common.byteutils.ByteUtil;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2024/12/30 15:44
*/
public class ReadParam {
private byte valueNum;
private byte[] retain;
private byte[] valueId;
private byte[] readStrValues;
public ReadParam(byte[] valueId, List<ReadStrValue> rvalues) {
// 这里的valueId 也是 header里面的 transationId
valueNum = ByteUtil.intTo1Byte(rvalues.size());
retain = new byte[]{0x00,0x00,0x00};
private byte valueNum;
private byte[] retain;
private byte[] valueId;
private byte[] readStrValues;
this.valueId = new byte[]{valueId[0],valueId[1],0x00,0x00};
List<Byte> bytes = new ArrayList<>();
for (ReadStrValue b : rvalues) {
bytes.addAll(b.toBytes());
}
readStrValues = new byte[bytes.size()];
for (int i = 0; i < bytes.size(); i++) {
readStrValues[i] = bytes.get(i);
}
}
public ReadParam(byte[] valueId, List<ReadStrValue> rvalues) {
// 这里的valueId 也是 header里面的 transationId
valueNum = ByteUtil.intTo1Byte(rvalues.size());
retain = new byte[]{0x00, 0x00, 0x00};
public byte[] toBytes() {
List<Byte> bytes = new ArrayList<>();
bytes.add(valueNum);
for (byte b : retain) {
bytes.add(b);
}
for (byte b : valueId) {
bytes.add(b);
}
for (byte b : readStrValues) {
bytes.add(b);
}
byte[] b = new byte[bytes.size()];
for (int i = 0; i < bytes.size(); i++) {
b[i] = bytes.get(i);
}
return b;
this.valueId = new byte[]{valueId[0], valueId[1], 0x00, 0x00};
List<Byte> bytes = new ArrayList<>();
for (ReadStrValue b : rvalues) {
bytes.addAll(b.toBytes());
}
readStrValues = new byte[bytes.size()];
for (int i = 0; i < bytes.size(); i++) {
readStrValues[i] = bytes.get(i);
}
}
public byte[] toBytes() {
List<Byte> bytes = new ArrayList<>();
bytes.add(valueNum);
for (byte b : retain) {
bytes.add(b);
}
for (byte b : valueId) {
bytes.add(b);
}
for (byte b : readStrValues) {
bytes.add(b);
}
byte[] b = new byte[bytes.size()];
for (int i = 0; i < bytes.size(); i++) {
b[i] = bytes.get(i);
}
return b;
}
}

View File

@ -2,36 +2,32 @@ package org.opentcs.kc.udp.agv.param.function.read;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/2/5 14:55
*/
public class ReadRsp {
//源数组
private byte[] src;
//ValueID ,4个字节
public byte[] valueId;
//应答数据总长度,2个字节
public short valueByteLength;
//预留,2个字节
public byte[] reserved;
//变量值,长度是 valueByteLength
public byte[] dataValue;
//源数组
private byte[] src;
//ValueID ,4个字节
public byte[] valueId;
//应答数据总长度,2个字节
public short valueByteLength;
//预留,2个字节
public byte[] reserved;
//变量值,长度是 valueByteLength
public byte[] dataValue;
public ReadRsp(byte[] src) {
this.src = src;
this.valueId = ByteUtils.copyBytes(src, 0, 4);
this.valueByteLength = ByteUtils.bytesToShort(ByteUtils.copyBytes(src, 4, 2),1);
this.reserved = ByteUtils.copyBytes(src, 6, 2);
this.dataValue = ByteUtils.copyBytes(src, 8, valueByteLength-8);
}
public ReadRsp(byte[] src) {
this.src = src;
this.valueId = ByteUtils.copyBytes(src, 0, 4);
this.valueByteLength = ByteUtils.bytesToShort(ByteUtils.copyBytes(src, 4, 2), 1);
this.reserved = ByteUtils.copyBytes(src, 6, 2);
this.dataValue = ByteUtils.copyBytes(src, 8, valueByteLength - 8);
}
public boolean isOk(){
if(valueByteLength<=0){
return false;
}else {
return true;
}
public boolean isOk() {
if (valueByteLength <= 0) {
return false;
}
else {
return true;
}
}
}

View File

@ -4,46 +4,43 @@ import java.util.ArrayList;
import java.util.List;
import org.opentcs.kc.common.byteutils.ByteUtil;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2024/12/30 15:46
*/
public class ReadStrValue {
//变量名16个字节( 以这个变量名来定位变量的)
private byte[] varName;
//成员变量数量4个字节
private byte[] memberVarNum;
private byte[] memberList;
public ReadStrValue(String varName, Integer memberVarNum, List<ReadValueMember> memberList) {
this.varName = ByteUtil.stringTo16Byte(varName);
this.memberVarNum = ByteUtil.intToBytes(memberVarNum);
List<Byte> bytes = new ArrayList<>();
for (ReadValueMember member : memberList) {
bytes.addAll(member.toBytes());
}
this.memberList = new byte[bytes.size()];
for (int i = 0; i < bytes.size(); i++) {
this.memberList[i] = bytes.get(i);
}
}
public ReadStrValue(String varName) {
this.varName = ByteUtil.stringTo16Byte(varName);
this.memberVarNum = ByteUtil.intToBytes(0);
this.memberList = new byte[0];
}
//变量名16个字节( 以这个变量名来定位变量的)
private byte[] varName;
//成员变量数量4个字节
private byte[] memberVarNum;
private byte[] memberList;
public List<Byte> toBytes() {
List<Byte> bytes = new ArrayList<>();
for (byte b : varName) {
bytes.add(b);
}
for (byte b : memberVarNum) {
bytes.add(b);
}
for (byte b : memberList) {
bytes.add(b);
}
return bytes;
public ReadStrValue(String varName, Integer memberVarNum, List<ReadValueMember> memberList) {
this.varName = ByteUtil.stringTo16Byte(varName);
this.memberVarNum = ByteUtil.intToBytes(memberVarNum);
List<Byte> bytes = new ArrayList<>();
for (ReadValueMember member : memberList) {
bytes.addAll(member.toBytes());
}
this.memberList = new byte[bytes.size()];
for (int i = 0; i < bytes.size(); i++) {
this.memberList[i] = bytes.get(i);
}
}
public ReadStrValue(String varName) {
this.varName = ByteUtil.stringTo16Byte(varName);
this.memberVarNum = ByteUtil.intToBytes(0);
this.memberList = new byte[0];
}
public List<Byte> toBytes() {
List<Byte> bytes = new ArrayList<>();
for (byte b : varName) {
bytes.add(b);
}
for (byte b : memberVarNum) {
bytes.add(b);
}
for (byte b : memberList) {
bytes.add(b);
}
return bytes;
}
}

View File

@ -4,31 +4,26 @@ import java.util.ArrayList;
import java.util.List;
import org.opentcs.kc.common.byteutils.ByteUtil;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2024/12/30 15:49
*/
public class ReadValueMember {
//偏移值就是以这个变量的起始点为基准偏移几个字节来读取数组里的后面几个变量基本上用于数组变量单体变量用不着 2个字节
private byte[] offsetValue;
//变量成员长度就是你要读取的content长度可以是1个变量的长度也可以是n个变量的长度(就是数据类型 的字节长度)
private byte[] memberVarLength;
//偏移值就是以这个变量的起始点为基准偏移几个字节来读取数组里的后面几个变量基本上用于数组变量单体变量用不着 2个字节
private byte[] offsetValue;
//变量成员长度就是你要读取的content长度可以是1个变量的长度也可以是n个变量的长度(就是数据类型 的字节长度)
private byte[] memberVarLength;
public ReadValueMember(Short offsetValue, Short memberVarLength) {
this.offsetValue = ByteUtil.shortToBytes(offsetValue);
this.memberVarLength = ByteUtil.shortToBytes(memberVarLength);
}
public ReadValueMember(Short offsetValue, Short memberVarLength) {
this.offsetValue = ByteUtil.shortToBytes(offsetValue);
this.memberVarLength = ByteUtil.shortToBytes(memberVarLength);
}
public List<Byte> toBytes() {
List<Byte> bytes = new ArrayList<>();
for (byte b : offsetValue) {
bytes.add(b);
}
for (byte b : memberVarLength) {
bytes.add(b);
}
return bytes;
public List<Byte> toBytes() {
List<Byte> bytes = new ArrayList<>();
for (byte b : offsetValue) {
bytes.add(b);
}
for (byte b : memberVarLength) {
bytes.add(b);
}
return bytes;
}
}

View File

@ -5,35 +5,31 @@ import io.netty.buffer.Unpooled;
import java.util.List;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/2/5 16:41
*/
public class WriteParam {
//变量数量 1个字节 ,最大只支持 15 个变量
private byte valueNum;
//保留 3个字节
private byte[] retain;
//这里的length 就是 valueNum
private List<WriteStrValue> values;
public WriteParam(Integer valueNum, List<WriteStrValue> values) {
this.valueNum = ByteUtils.usintTo1Byte(valueNum);
this.retain = new byte[]{(byte)0x00,(byte)0x00,(byte)0x00};
this.values = values;
}
//变量数量 1个字节 ,最大只支持 15 个变量
private byte valueNum;
//保留 3个字节
private byte[] retain;
//这里的length 就是 valueNum
private List<WriteStrValue> values;
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeByte(valueNum);
byteBuf.writeBytes(retain);
for (WriteStrValue value : values) {
byteBuf.writeBytes(value.toBytes());
}
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
return bytes;
public WriteParam(Integer valueNum, List<WriteStrValue> values) {
this.valueNum = ByteUtils.usintTo1Byte(valueNum);
this.retain = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00};
this.values = values;
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeByte(valueNum);
byteBuf.writeBytes(retain);
for (WriteStrValue value : values) {
byteBuf.writeBytes(value.toBytes());
}
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
return bytes;
}
}

View File

@ -5,37 +5,32 @@ import io.netty.buffer.Unpooled;
import java.util.List;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/2/5 16:43
*/
public class WriteStrValue {
//变量名 16个字节
private String valueName;
//变量成员数量 4个字节
private Integer valueNum;
private List<WriteValueMember> members;
//变量名 16个字节
private String valueName;
//变量成员数量 4个字节
private Integer valueNum;
private List<WriteValueMember> members;
public WriteStrValue(String valueName, Integer valueNum, List<WriteValueMember> members) {
this.valueName = valueName;
this.valueNum = valueNum;
this.members = members;
public WriteStrValue(String valueName, Integer valueNum, List<WriteValueMember> members) {
this.valueName = valueName;
this.valueNum = valueNum;
this.members = members;
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(ByteUtils.stringToBytes(valueName, 16));
byteBuf.writeBytes(ByteUtils.intToBytes(valueNum, 1));
for (WriteValueMember member : members) {
byteBuf.writeBytes(member.toBytes());
}
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(ByteUtils.stringToBytes(valueName, 16));
byteBuf.writeBytes(ByteUtils.intToBytes(valueNum,1));
for (WriteValueMember member : members) {
byteBuf.writeBytes(member.toBytes());
}
int i = byteBuf.writerIndex();
byte[] bytes = new byte[i];
byteBuf.readBytes(bytes);
return bytes;
}
return bytes;
}
}

View File

@ -4,29 +4,25 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/2/5 16:44
*/
public class WriteValueMember {
//变量成员偏移 2个字节
private byte[] valueOffset;
//变量成员长度 2个字节
private byte[] valueLength;
//变量成员值 4个字节
private byte[] newValue;
public WriteValueMember(Short valueOffset, Short valueLength, byte[] newValue) {
this.valueOffset = ByteUtils.shortToBytes(valueOffset);
this.valueLength = ByteUtils.shortToBytes(valueLength);
this.newValue = newValue;
}
//变量成员偏移 2个字节
private byte[] valueOffset;
//变量成员长度 2个字节
private byte[] valueLength;
//变量成员值 4个字节
private byte[] newValue;
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer(8);
byteBuf.writeBytes(valueOffset);
byteBuf.writeBytes(valueLength);
byteBuf.writeBytes(newValue);
return byteBuf.array();
}
public WriteValueMember(Short valueOffset, Short valueLength, byte[] newValue) {
this.valueOffset = ByteUtils.shortToBytes(valueOffset);
this.valueLength = ByteUtils.shortToBytes(valueLength);
this.newValue = newValue;
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer(8);
byteBuf.writeBytes(valueOffset);
byteBuf.writeBytes(valueLength);
byteBuf.writeBytes(newValue);
return byteBuf.array();
}
}

View File

@ -4,29 +4,25 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.opentcs.kc.common.byteutils.ByteUtil;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/2/7 9:21
*/
public class RobotSetPosition {
//机器人 x 坐标 ,8 个字节
private byte[] robotX;
//机器人 y 坐标 ,8 个字节
private byte[] robotY;
//机器人朝向角度 ,8 个字节
private byte[] robotAngle;
//机器人 x 坐标 ,8 个字节
private byte[] robotX;
//机器人 y 坐标 ,8 个字节
private byte[] robotY;
//机器人朝向角度 ,8 个字节
private byte[] robotAngle;
public RobotSetPosition(double robotX, double robotY, double robotAngle) {
this.robotX = ByteUtil.doubleToBytes(robotX);
this.robotY = ByteUtil.doubleToBytes(robotY);
this.robotAngle = ByteUtil.doubleToBytes(robotAngle);
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer(24);
byteBuf.writeBytes(robotX);
byteBuf.writeBytes(robotY);
byteBuf.writeBytes(robotAngle);
return byteBuf.array();
}
public RobotSetPosition(double robotX, double robotY, double robotAngle) {
this.robotX = ByteUtil.doubleToBytes(robotX);
this.robotY = ByteUtil.doubleToBytes(robotY);
this.robotAngle = ByteUtil.doubleToBytes(robotAngle);
}
public byte[] toBytes() {
ByteBuf byteBuf = Unpooled.buffer(24);
byteBuf.writeBytes(robotX);
byteBuf.writeBytes(robotY);
byteBuf.writeBytes(robotAngle);
return byteBuf.array();
}
}

View File

@ -3,128 +3,123 @@ package org.opentcs.kc.udp.agv.param.function.x17;
import java.util.Arrays;
import org.opentcs.kc.common.byteutils.ByteUtils;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2025/2/7 9:43
*/
public class QueryRobotRunStatusRsp {
//本体温度 ,8个字节 ,double
private double temp;
//位置的 X 坐标 , 8个字节 ,double
private double currentX;
//位置的 Y 坐标,8个字节 ,double
private double currentY;
//位置的 角度 ,8个字节 ,double
private double currentAngle;
//电池电量,,8个字节 ,double
private double battery;
//是否被阻挡,1个字节,byte
private byte isBlocked;
//是否在充电,1个字节,byte
private byte isCharging;
//运行模式,1个字节,byte
private byte runMode;
//地图载入状态,1个字节,byte
private byte mapLoadState;
//当前的目标点 id,U32 ,4个字节
private Integer currentTargetId;
//本体温度 ,8个字节 ,double
private double temp;
//位置的 X 坐标 , 8个字节 ,double
private double currentX;
//位置的 Y 坐标,8个字节 ,double
private double currentY;
//位置的 角度 ,8个字节 ,double
private double currentAngle;
//电池电量,,8个字节 ,double
private double battery;
//是否被阻挡,1个字节,byte
private byte isBlocked;
//是否在充电,1个字节,byte
private byte isCharging;
//运行模式,1个字节,byte
private byte runMode;
//地图载入状态,1个字节,byte
private byte mapLoadState;
//当前的目标点 id,U32 ,4个字节
private Integer currentTargetId;
//前进速度,8个字节,double
private double forwardSpeed;
//转弯速度,8个字节,double
private double turnSpeed;
//电池电压充电为正放电为负,8个字节,double
private double batteryVoltage;
//电流充电为正放电为负,double
private double electricCurrent;
//当前任务状态,1个字节,byte
private byte taskState;
//保留1个字节
private byte retain1;
//地图版本号,2个字节
private short mapVersion;
//保留4个字节
private byte[] retain2;
//累计行驶里程单位 m,8个字节
private double cumulativeMileage;
//本次运行时间单位 ms,8个字节
private double currentRunTime;
//累计运行时间单位 ms,8个字节
private double cumulativeRunTime;
//机器人定位状态,1个字节
public byte robotLocalizationState;
//保留3个字节
private byte[] retain3;
//地图数量U32,4个字节
private Integer mapNum;
//当前地图名称,64字节
private String currentMapName;
//置信度,4个字节
private float confidence;
//保留4个字节
private byte[] retain4;
//前进速度,8个字节,double
private double forwardSpeed;
//转弯速度,8个字节,double
private double turnSpeed;
//电池电压充电为正放电为负,8个字节,double
private double batteryVoltage;
//电流充电为正放电为负,double
private double electricCurrent;
//当前任务状态,1个字节,byte
private byte taskState;
//保留1个字节
private byte retain1;
//地图版本号,2个字节
private short mapVersion;
//保留4个字节
private byte[] retain2;
//累计行驶里程单位 m,8个字节
private double cumulativeMileage;
//本次运行时间单位 ms,8个字节
private double currentRunTime;
//累计运行时间单位 ms,8个字节
private double cumulativeRunTime;
//机器人定位状态,1个字节
public byte robotLocalizationState;
//保留3个字节
private byte[] retain3;
//地图数量U32,4个字节
private Integer mapNum;
//当前地图名称,64字节
private String currentMapName;
//置信度,4个字节
private float confidence;
//保留4个字节
private byte[] retain4;
public QueryRobotRunStatusRsp(byte[] src) {
this.temp = ByteUtils.bytesToDouble(src, 0);
this.currentX = ByteUtils.bytesToDouble(src, 8);
this.currentY = ByteUtils.bytesToDouble(src, 16);
this.currentAngle = ByteUtils.bytesToDouble(src, 24);
this.battery = ByteUtils.bytesToDouble(src, 32);
this.isBlocked = src[40];
this.isCharging = src[41];
this.runMode = src[42];
this.mapLoadState = src[43];
this.currentTargetId = ByteUtils.bytesToInt(src, 44);
this.forwardSpeed = ByteUtils.bytesToDouble(src, 48);
this.turnSpeed = ByteUtils.bytesToDouble(src, 56);
this.batteryVoltage = ByteUtils.bytesToDouble(src, 64);
this.electricCurrent = ByteUtils.bytesToDouble(src, 72);
this.taskState = src[80];
this.retain1 = src[81];
this.mapVersion = ByteUtils.bytesToShortLitt(src, 82);
this.retain2 = ByteUtils.copyBytes(src, 84, 4);
this.cumulativeMileage = ByteUtils.bytesToDouble(src, 88);
this.currentRunTime = ByteUtils.bytesToDouble(src, 96);
this.cumulativeRunTime = ByteUtils.bytesToDouble(src, 104);
this.robotLocalizationState = src[112];
this.retain3 = ByteUtils.copyBytes(src, 113, 3);
this.mapNum = ByteUtils.bytesToInt(src, 116);
this.currentMapName = ByteUtils.bytesToString(src, 120, 64);
this.confidence = ByteUtils.bytesToFloat(src, 184);
this.retain4 = ByteUtils.copyBytes(src, 188, 4);
}
public QueryRobotRunStatusRsp(byte[] src) {
this.temp = ByteUtils.bytesToDouble(src, 0);
this.currentX = ByteUtils.bytesToDouble(src, 8);
this.currentY = ByteUtils.bytesToDouble(src, 16);
this.currentAngle = ByteUtils.bytesToDouble(src, 24);
this.battery = ByteUtils.bytesToDouble(src, 32);
this.isBlocked = src[40];
this.isCharging = src[41];
this.runMode = src[42];
this.mapLoadState = src[43];
this.currentTargetId = ByteUtils.bytesToInt(src, 44);
this.forwardSpeed = ByteUtils.bytesToDouble(src, 48);
this.turnSpeed = ByteUtils.bytesToDouble(src, 56);
this.batteryVoltage = ByteUtils.bytesToDouble(src, 64);
this.electricCurrent = ByteUtils.bytesToDouble(src, 72);
this.taskState = src[80];
this.retain1 = src[81];
this.mapVersion = ByteUtils.bytesToShortLitt(src, 82);
this.retain2 = ByteUtils.copyBytes(src, 84, 4);
this.cumulativeMileage = ByteUtils.bytesToDouble(src, 88);
this.currentRunTime = ByteUtils.bytesToDouble(src, 96);
this.cumulativeRunTime = ByteUtils.bytesToDouble(src, 104);
this.robotLocalizationState = src[112];
this.retain3 = ByteUtils.copyBytes(src, 113, 3);
this.mapNum = ByteUtils.bytesToInt(src, 116);
this.currentMapName = ByteUtils.bytesToString(src, 120, 64);
this.confidence = ByteUtils.bytesToFloat(src, 184);
this.retain4 = ByteUtils.copyBytes(src, 188, 4);
}
@Override
public String toString() {
return "QueryRobotRunStatusRsp{" +
"temp=" + temp +
", currentX=" + currentX +
", currentY=" + currentY +
", currentAngle=" + currentAngle +
", battery=" + battery +
", isBlocked=" + isBlocked +
", isCharging=" + isCharging +
", runMode=" + runMode +
", mapLoadState=" + mapLoadState +
", currentTargetId=" + currentTargetId +
", forwardSpeed=" + forwardSpeed +
", turnSpeed=" + turnSpeed +
", batteryVoltage=" + batteryVoltage +
", electricCurrent=" + electricCurrent +
", taskState=" + taskState +
", retain1=" + retain1 +
", mapVersion=" + mapVersion +
", retain2=" + Arrays.toString(retain2) +
", cumulativeMileage=" + cumulativeMileage +
", cuttentRunTime=" + currentRunTime +
", cumulativeRunTime=" + cumulativeRunTime +
", robotLocalizationState=" + robotLocalizationState +
", retain3=" + Arrays.toString(retain3) +
", mapNum=" + mapNum +
", currentMapName='" + currentMapName + '\'' +
", confidence=" + confidence +
", retain4=" + Arrays.toString(retain4) +
'}';
}
@Override
public String toString() {
return "QueryRobotRunStatusRsp{" +
"temp=" + temp +
", currentX=" + currentX +
", currentY=" + currentY +
", currentAngle=" + currentAngle +
", battery=" + battery +
", isBlocked=" + isBlocked +
", isCharging=" + isCharging +
", runMode=" + runMode +
", mapLoadState=" + mapLoadState +
", currentTargetId=" + currentTargetId +
", forwardSpeed=" + forwardSpeed +
", turnSpeed=" + turnSpeed +
", batteryVoltage=" + batteryVoltage +
", electricCurrent=" + electricCurrent +
", taskState=" + taskState +
", retain1=" + retain1 +
", mapVersion=" + mapVersion +
", retain2=" + Arrays.toString(retain2) +
", cumulativeMileage=" + cumulativeMileage +
", cuttentRunTime=" + currentRunTime +
", cumulativeRunTime=" + cumulativeRunTime +
", robotLocalizationState=" + robotLocalizationState +
", retain3=" + Arrays.toString(retain3) +
", mapNum=" + mapNum +
", currentMapName='" + currentMapName + '\'' +
", confidence=" + confidence +
", retain4=" + Arrays.toString(retain4) +
'}';
}
}

View File

@ -4,86 +4,90 @@ package org.opentcs.kc.udp.agv.param.rsp;
import org.opentcs.kc.common.byteutils.ByteUtils;
import org.opentcs.kc.udp.agv.param.AgvEventHeader;
/**
* @Desc: "通用的数据传输底层类"
* @Author: caixiang
* @DATE: 2022/10/18 16:22
*/
public class RcvEventPackage {
private boolean isOk;
private byte[] value;
private String content;
// header size = 授权码16 + 报文头12(包括报文数据长度2个字节+保留2个字节) = 28
private AgvEventHeader header;
private byte[] dataBytes;
private boolean isOk;
private byte[] value;
private String content;
// header size = 授权码16 + 报文头12(包括报文数据长度2个字节+保留2个字节) = 28
private AgvEventHeader header;
private byte[] dataBytes;
private String getContent(byte i) {
if(i==0x00){
return "成功执行";
}else if(i==0x01){
return "执行失败,原因未知";
}else if(i==0x02){
return "服务码错误";
}else if(i==0x03){
return "命令码错误";
}else if(i==0x04){
return "报文头部错误";
}else if(i==0x80){
return "无法执行命令,因为当前车辆导航状态与命令冲突";
}else if(i==0xFF){
return "协议授权码错误";
}else {
return "未知错误";
}
private String getContent(byte i) {
if (i == 0x00) {
return "成功执行";
}
else if (i == 0x01) {
return "执行失败,原因未知";
}
else if (i == 0x02) {
return "服务码错误";
}
else if (i == 0x03) {
return "命令码错误";
}
else if (i == 0x04) {
return "报文头部错误";
}
else if (i == 0x80) {
return "无法执行命令,因为当前车辆导航状态与命令冲突";
}
else if (i == 0xFF) {
return "协议授权码错误";
}
else {
return "未知错误";
}
public RcvEventPackage(byte executionCode, byte[] value) {
if(executionCode == 0x00){
this.isOk = true;
this.header = new AgvEventHeader(ByteUtils.copyBytes(value,0,28));
this.dataBytes = ByteUtils.copyBytes(value,28,value.length-28);
}else {
this.isOk = false;
}
this.value = value;
this.content = getContent(executionCode);
}
public RcvEventPackage() {
}
}
public boolean isOk() {
return isOk;
public RcvEventPackage(byte executionCode, byte[] value) {
if (executionCode == 0x00) {
this.isOk = true;
this.header = new AgvEventHeader(ByteUtils.copyBytes(value, 0, 28));
this.dataBytes = ByteUtils.copyBytes(value, 28, value.length - 28);
}
else {
this.isOk = false;
}
this.value = value;
this.content = getContent(executionCode);
}
public void setValue(byte[] value) {
this.value = value;
}
public RcvEventPackage() {
}
public byte[] getValue() {
return value;
}
public boolean isOk() {
return isOk;
}
public String getContent() {
return content;
}
public void setValue(byte[] value) {
this.value = value;
}
public AgvEventHeader getHeader() {
return header;
}
public byte[] getValue() {
return value;
}
public byte[] getDataBytes() {
return dataBytes;
}
public String getContent() {
return content;
}
@Override
public String toString() {
return "RcvPackage{" +
"isOk=" + isOk +
", value=" + value +
", content='" + content + '\'' +
'}';
}
public AgvEventHeader getHeader() {
return header;
}
public byte[] getDataBytes() {
return dataBytes;
}
@Override
public String toString() {
return "RcvPackage{" +
"isOk=" + isOk +
", value=" + value +
", content='" + content + '\'' +
'}';
}
}

View File

@ -9,6 +9,7 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Set;
import org.opentcs.access.KernelServicePortal;
import org.opentcs.access.rmi.KernelServicePortalBuilder;
@ -27,250 +28,265 @@ import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Desc: ""
* @Author: caixiang
* @DATE: 2022/1/15 13:01
*/
public enum UDPClient {
//如果要配置多个链接 local1 local2 .... 这样排下去好了
//如果要配置多个链接 local1 local2 .... 这样排下去好了
localAGV("1","192.168.0.211",17804,55678),
//local("127.0.0.1",502,true),
;
localAGV("50", "192.168.124.124", 17804, 55678),
;
// 服务端地址+端口
private String SERVICE_HOST = "192.168.0.123";
private Integer SERVICE_PORT = 1099;
// 服务端用户名+密码+地址+端口
private String SERVICE_USER = GuestUserCredentials.USER;
private String SERVICE_PWD = GuestUserCredentials.PASSWORD;
private String SERVICE_HOST = GuestUserCredentials.IP;
private Integer SERVICE_PORT = GuestUserCredentials.PORT;
private String name;
private String host;
//默认 0 port
private Integer port;
private Integer bindPort;
private Bootstrap bootstrap;
private NioEventLoopGroup group;
private String name;
private String host;
//默认 0 port
private Integer port;
private Integer bindPort;
private Bootstrap bootstrap;
private NioEventLoopGroup group;
private Channel conn;
private boolean isOnline;
private Channel conn;
private boolean isOnline;
private static final Logger logger = LoggerFactory.getLogger("AGVLOGGER");
// private static final Logger logger = LoggerFactory.getLogger("AGVLOGGER");
private static final Logger logger = LoggerFactory.getLogger(UDPClient.class);
// ==== 连接节点配置信息 ===== 开始
// ==== 连接节点配置信息 ===== 结束
UDPClient() {
}
//coreSize 是线程池的数量
UDPClient(String name, String host, Integer port, Integer bindPort) {
this.name = name;
this.host = host;
this.port = port;
this.conn = null;
this.bindPort = bindPort;
initClient();
}
public String getHost() {
return this.host;
}
// ==== 连接节点配置信息 ===== 开始
public String getName() {
return this.name;
}
// ==== 连接节点配置信息 ===== 结束
public void setIsOnline(boolean isOnline) {
this.isOnline = isOnline;
}
UDPClient() {
/**
* desc : 判断此链接 健康状况
* return
* true : 此tcp连接 正常
* false : 此tcp连接 异常
*/
public boolean isOnline() {
return isOnline;
}
public void close() {
//手动关闭连接会出发InActivite 事件
group.shutdownGracefully();
}
public static ByteBuf byteArrayToByteBuf(byte[] byteArray) {
// 使用Unpooled类创建ByteBuf
ByteBuf byteBuf = Unpooled.buffer(byteArray.length);
// 将byte[]写入ByteBuf
byteBuf.writeBytes(byteArray);
return byteBuf;
}
/**
* --线程安全的--
*
*
* 如果返回null就代表出现了异常并且尝试了 retryMax 次数并且尝试重置连接
*/
public RcvEventPackage send(AgvEvent event) {
try {
//sendread 报文
//应该是ReadRequestFrame 继承 Packet 然后直接 Tio.bSend(this.conn, ReadRequestFrame)
Package mbPackage = event.toBytes();
AsyncFuture<Package> add = SendedList.add(mbPackage.getTransationId(), null);
this.conn.writeAndFlush(
new DatagramPacket(
byteArrayToByteBuf(mbPackage.getBody()),
new InetSocketAddress(this.host, this.port)
)
)
.sync();
Package aPackage = add.get(5000L, mbPackage.getTransationId());
byte[] body = aPackage.getBody();
String errMsg = " [ AGVclient - send success ] [ " + name + " host: " + this.host
+ " ]" + event.toString();
logger.info(errMsg);
//注意这里的body 是整个 response结构包括 : 授权码 + header + body
return new RcvEventPackage(body[22], body);
}
catch (Throwable e) {
//e.printStackTrace();
String errMsg = " [ AGVclient - Read ] [ " + name + " host: " + this.host
+ " ] ( occur err ) errTime: " + " ; send errMsg : " + e.getMessage()
+ " ; event :" + event.toString();
logger.info(errMsg);
throw new RuntimeException(errMsg);
}
}
//coreSize 是线程池的数量
UDPClient(String name, String host, Integer port, Integer bindPort) {
this.name = name;
this.host = host;
this.port = port;
this.conn = null;
this.bindPort = bindPort;
initClient();
public void subscribeKC(RcvEventPackage rcv, byte[] body) {
if (rcv.isOk()) {
KernelServicePortal servicePortal = new KernelServicePortalBuilder(
SERVICE_USER, SERVICE_PWD
).build();
servicePortal.login(SERVICE_HOST, SERVICE_PORT);
VehicleService vehicleService = servicePortal.getVehicleService();
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
vehicleService.sendCommAdapterMessage(vehicle.getReference(), body);
servicePortal.logout();
}
else {
System.out.println();
System.out.println("subscribe received transationId : " + "isok:" + rcv.isOk());
}
}
public void subscribe0xB0(RcvEventPackage rcv, byte[] body) {
if (rcv.isOk()) {
this.achieveSub0xB0(body);
}
else {
System.out.println();
System.out.println("subscribe0xB0 received transationId : " + "isok:" + rcv.isOk());
}
}
public String getHost(){
return this.host;
public void subscribe0xAF(RcvEventPackage rcv, byte[] body) {
if (rcv.isOk()) {
this.achieveSub0xAF(body);
}
public String getName(){
return this.name;
}
public void setIsOnline(boolean isOnline){
this.isOnline = isOnline;
}
/**
* desc : 判断此链接 健康状况
* return
* true : 此tcp连接 正常
* false : 此tcp连接 异常
* */
public boolean isOnline(){
return isOnline;
}
public void close(){
//手动关闭连接会出发InActivite 事件
group.shutdownGracefully();
}
public static ByteBuf byteArrayToByteBuf(byte[] byteArray) {
// 使用Unpooled类创建ByteBuf
ByteBuf byteBuf = Unpooled.buffer(byteArray.length);
// 将byte[]写入ByteBuf
byteBuf.writeBytes(byteArray);
return byteBuf;
}
/**
* --线程安全的--
*
* 如果返回null就代表出现了异常并且尝试了 retryMax 次数并且尝试重置连接
* */
public RcvEventPackage send(AgvEvent event) {
try {
//sendread 报文
//应该是ReadRequestFrame 继承 Packet 然后直接 Tio.bSend(this.conn, ReadRequestFrame)
Package mbPackage = event.toBytes();
AsyncFuture<Package> add = SendedList.add(mbPackage.getTransationId(),null);
this.conn.writeAndFlush(
new DatagramPacket(
byteArrayToByteBuf(mbPackage.getBody()),
new InetSocketAddress(this.host,this.port)))
.sync();
Package aPackage = add.get(5000L, mbPackage.getTransationId());
byte[] body = aPackage.getBody();
String errMsg = " [ AGVclient - send success ] [ "+name+" host: "+ this.host +" ]"+event.toString();
logger.info(errMsg);
//注意这里的body 是整个 response结构包括 : 授权码 + header + body
return new RcvEventPackage(body[22],body);
}catch (Throwable e) {
//e.printStackTrace();
String errMsg = " [ AGVclient - Read ] [ "+name+" host: "+ this.host +" ] ( occur err ) errTime: "+" ; send errMsg : "+e.getMessage()+" ; event :"+event.toString();
logger.info(errMsg);
throw new RuntimeException(errMsg);
}
}
public void subscribe0xB0(RcvEventPackage rcv){
if (rcv.isOk()) {
if(name.equals("1")){
this.achieveSub0xB0(name, rcv);
}else if(name.equals("2")){
this.achieveSub0xB0(name, rcv);
}
} else {
System.out.println();
System.out.println("subscribe0xB0 received transationId : "+ "isok:"+rcv.isOk());
}
}
public void subscribe0xAF(RcvEventPackage rcv){
if (rcv.isOk()) {
if (name.equals("1")) {
this.achieveSub0xAF(name, rcv);
} else if (name.equals("2")) {
this.achieveSub0xAF(name, rcv);
}
} else {
System.out.println();
System.out.println("subscribe0xAF received transationId : "+ "isok:"+rcv.isOk());
}
else {
System.out.println();
System.out.println("subscribe0xAF received transationId : " + "isok:" + rcv.isOk());
}
}
/**
* 0xAF上报信息传入通讯适配器
* @param vehicleName 车辆名称
* @param rcv 响应数据
*
* @param body 响应数据
*/
private void achieveSub0xAF(String vehicleName ,RcvEventPackage rcv){
QueryRobotStatusRsp queryRobotStatusRsp = new QueryRobotStatusRsp(rcv.getDataBytes());
System.out.println();
System.out.println("received subscribe 0xAF List : "+ "isok:"+rcv.isOk());
for (byte b:rcv.getValue()){
System.out.print(byteToHex(b)+" ");
}
KernelServicePortal servicePortal = new KernelServicePortalBuilder(GuestUserCredentials.USER, GuestUserCredentials.PASSWORD).build();
servicePortal.login(SERVICE_HOST, SERVICE_PORT);
VehicleService vehicleService = servicePortal.getVehicleService();
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, vehicleName);
//将AGV控制器上报信息传入通讯适配器
vehicleService.sendCommAdapterMessage(vehicle.getReference(), queryRobotStatusRsp);
servicePortal.logout();
}
private void achieveSub0xAF(byte[] body) {
// QueryRobotStatusRsp queryRobotStatusRsp = new QueryRobotStatusRsp(rcv.getDataBytes());
KernelServicePortal servicePortal = new KernelServicePortalBuilder(
SERVICE_USER, SERVICE_PWD
).build();
servicePortal.login(SERVICE_HOST, SERVICE_PORT);
VehicleService vehicleService = servicePortal.getVehicleService();
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
vehicleService.sendCommAdapterMessage(vehicle.getReference(), body);
}
/**
* 0xB0上报信息传入通讯适配器
* @param vehicleName 车辆名称
* @param rcv 响应数据
*
* @param body 响应数据
*/
private void achieveSub0xB0(String vehicleName ,RcvEventPackage rcv){
private void achieveSub0xB0(byte[] body) {
QueryCargoStatusRsp queryCargoStatusRsp = new QueryCargoStatusRsp(rcv.getDataBytes());
System.out.println();
System.out.println("received subscribe 0xB0 List : "+ "isok:"+rcv.isOk());
for (byte b:rcv.getValue()){
System.out.print(byteToHex(b)+" ");
}
// QueryCargoStatusRsp queryCargoStatusRsp = new QueryCargoStatusRsp(rcv.getDataBytes());
// System.out.println();
// System.out.println("received subscribe 0xB0 List : " + "isok:" + rcv.isOk());
// for (byte b : rcv.getValue()) {
// System.out.print(byteToHex(b) + " ");
// }
KernelServicePortal servicePortal = new KernelServicePortalBuilder(GuestUserCredentials.USER, GuestUserCredentials.PASSWORD).build();
servicePortal.login(SERVICE_HOST, SERVICE_PORT);
VehicleService vehicleService = servicePortal.getVehicleService();
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, vehicleName);
//将AGV控制器上报信息传入通讯适配器
vehicleService.sendCommAdapterMessage(vehicle.getReference(), queryCargoStatusRsp);
KernelServicePortal servicePortal = new KernelServicePortalBuilder(
SERVICE_USER, SERVICE_PWD
).build();
servicePortal.login(SERVICE_HOST, SERVICE_PORT);
VehicleService vehicleService = servicePortal.getVehicleService();
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
servicePortal.logout();
if (vehicle == null) {
throw new RuntimeException("vehicle name:" + name + ",does not exist");
}
public static void printInfo(AgvEvent agvEvent){
System.out.println("sended transationId : "+agvEvent.getTransationIdString());
for (byte b:agvEvent.toBytes().getBody()){
System.out.print(byteToHex(b)+" ");
}
}
public static String byteToHex(byte b) {
// 将byte转换为无符号整数
int unsignedByte = b & 0xFF;
// 使用Integer.toHexString方法转换为十六进制字符串
String hexString = Integer.toHexString(unsignedByte);
// 如果字符串长度为1需要在前面补0
if (hexString.length() == 1) {
return "0" + hexString;
}
return hexString;
}
/**
* decs: 在项目启动的时候初始化 后面就不会初始化了
* */
private void initClient() {
//NioEventLoopGroup Bootstrap 这些资源其实是不用 release的因为全局共用一份的你释放了 下次还得再new
NioEventLoopGroup group = new NioEventLoopGroup();
this.bootstrap = new Bootstrap();
this.bootstrap.group(group)
/*由于我们用的是UDP协议所以要用NioDatagramChannel来创建*/
.channel(NioDatagramChannel.class)
.handler(new ChannelInitializer<NioDatagramChannel>() {
@Override
protected void initChannel(NioDatagramChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//0 代表禁用 readerIdleTime 事件的监听
//这两个是固定的
//pipeline.addLast(new IdleStateHandler(0,0,10, TimeUnit.SECONDS));
//将AGV控制器上报信息传入通讯适配器
vehicleService.sendCommAdapterMessage(vehicle.getReference(), body);
//协议层的handler 这里要做以区分
servicePortal.logout();
}
pipeline.addLast(new AgvUdpChannelInitializer(UDPClient.this));
}
});
try {
this.conn = this.bootstrap.bind(this.bindPort).sync().channel();
}catch (Exception e){
logger.info("AGV UDP Initial Exception : "+e.getMessage());
}
public static void printInfo(AgvEvent agvEvent) {
System.out.println("sended transationId : " + agvEvent.getTransationIdString());
for (byte b : agvEvent.toBytes().getBody()) {
System.out.print(byteToHex(b) + " ");
}
}
public static String byteToHex(byte b) {
// 将byte转换为无符号整数
int unsignedByte = b & 0xFF;
// 使用Integer.toHexString方法转换为十六进制字符串
String hexString = Integer.toHexString(unsignedByte);
// 如果字符串长度为1需要在前面补0
if (hexString.length() == 1) {
return "0" + hexString;
}
return hexString;
}
/**
* decs: 在项目启动的时候初始化 后面就不会初始化了
*/
private void initClient() {
//NioEventLoopGroup Bootstrap 这些资源其实是不用 release的因为全局共用一份的你释放了 下次还得再new
NioEventLoopGroup group = new NioEventLoopGroup();
this.bootstrap = new Bootstrap();
this.bootstrap.group(group)
/* 由于我们用的是UDP协议所以要用NioDatagramChannel来创建 */
.channel(NioDatagramChannel.class)
.handler(new ChannelInitializer<NioDatagramChannel>() {
@Override
protected void initChannel(NioDatagramChannel ch)
throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//0 代表禁用 readerIdleTime 事件的监听
//这两个是固定的
//pipeline.addLast(new IdleStateHandler(0,0,10, TimeUnit.SECONDS));
//协议层的handler 这里要做以区分
pipeline.addLast(new AgvUdpChannelInitializer(UDPClient.this));
}
});
try {
this.conn = this.bootstrap.bind(this.bindPort).sync().channel();
}
catch (Exception e) {
logger.info("AGV UDP Initial Exception : " + e.getMessage());
}
}
}

View File

@ -86,40 +86,46 @@ class SameThreadExecutorServiceTest {
verify(task).call();
}
@Test
void testVehicle(){
//获取车辆对象代码
KernelServicePortal servicePortal = new KernelServicePortalBuilder(GuestUserCredentials.USER,GuestUserCredentials.PASSWORD).build();
servicePortal.login(GuestUserCredentials.IP, GuestUserCredentials.PORT);
// servicePortal.getPlantModelService().up
PlantModelService plantModelService = servicePortal.getPlantModelService();
VehicleService vehicleService = servicePortal.getVehicleService();
Set<Vehicle> vehicles = vehicleService.fetchObjects(Vehicle.class);
for (Vehicle vehicle : vehicles) {
System.out.println("vehicle:"+vehicle);
}
}
/*
* @Test
* void testVehicle() {
* //获取车辆对象代码
* KernelServicePortal servicePortal = new KernelServicePortalBuilder(
* GuestUserCredentials.USER, GuestUserCredentials.PASSWORD
* ).build();
* servicePortal.login(GuestUserCredentials.IP, GuestUserCredentials.PORT);
* // servicePortal.getPlantModelService().up
* PlantModelService plantModelService = servicePortal.getPlantModelService();
* VehicleService vehicleService = servicePortal.getVehicleService();
* Set<Vehicle> vehicles = vehicleService.fetchObjects(Vehicle.class);
* for (Vehicle vehicle : vehicles) {
* System.out.println("vehicle:" + vehicle);
* }
* }
*/
@Test
void testRemoveVehicle(){
@Test
void testRemoveVehicle() {
HashMap<String, Object> map = new HashMap<>();
int energy = 54;
map.put("energy", energy);
long positionX = -100;
map.put("positionX", positionX);
long positionY = 6510;
map.put("positionY", positionY);
double positionAngle = 0.0;
map.put("positionAngle", positionAngle);
HashMap<String, Object> map = new HashMap<>();
int energy = 52;
map.put("energy", energy);
long positionX = 3040;
map.put("positionX", positionX);
long positionY = -40;
map.put("positionY", positionY);
double positionAngle = 0.0;
map.put("positionAngle", positionAngle);
//向车辆对应的通讯适配器发送消息
KernelServicePortal servicePortal = new KernelServicePortalBuilder(GuestUserCredentials.USER,GuestUserCredentials.PASSWORD).build();
servicePortal.login(GuestUserCredentials.IP, GuestUserCredentials.PORT);
VehicleService vehicleService = servicePortal.getVehicleService();
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, "2");
vehicleService.sendCommAdapterMessage(vehicle.getReference(), map);
//向车辆对应的通讯适配器发送消息
KernelServicePortal servicePortal = new KernelServicePortalBuilder(
GuestUserCredentials.USER, GuestUserCredentials.PASSWORD
).build();
servicePortal.login(GuestUserCredentials.IP, GuestUserCredentials.PORT);
VehicleService vehicleService = servicePortal.getVehicleService();
Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, "50");
vehicleService.sendCommAdapterMessage(vehicle.getReference(), map);
}
}
}

View File

@ -42,6 +42,7 @@ public class DefaultPropertySuggestions
keySuggestions.add(LoopbackAdapterConstants.AGV_AUTHORIZE_CODE);
keySuggestions.add(LoopbackAdapterConstants.AGV_IP);
keySuggestions.add(LoopbackAdapterConstants.AGV_PORT);
keySuggestions.add(LoopbackAdapterConstants.POINT_TYPE);
}
@Override