This commit is contained in:
parent
ece8013fec
commit
17c28a5a7f
@ -29,6 +29,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates a vehicle's energy level.
|
||||
* 更新车辆的能级。
|
||||
*
|
||||
* @param ref A reference to the vehicle to be modified.
|
||||
* @param energyLevel The vehicle's new energy level.
|
||||
@ -39,6 +40,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates a vehicle's load handling devices.
|
||||
* 更新车辆的负载处理设备。
|
||||
*
|
||||
* @param ref A reference to the vehicle to be modified.
|
||||
* @param devices The vehicle's new load handling devices.
|
||||
@ -52,6 +54,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates the point which a vehicle is expected to occupy next.
|
||||
* 更新了预计接下来将占用的车辆的点。
|
||||
*
|
||||
* @param vehicleRef A reference to the vehicle to be modified.
|
||||
* @param pointRef A reference to the point which the vehicle is expected to occupy next.
|
||||
@ -65,6 +68,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates a vehicle's order sequence.
|
||||
* 更新车辆的订单序列。
|
||||
*
|
||||
* @param vehicleRef A reference to the vehicle to be modified.
|
||||
* @param sequenceRef A reference to the order sequence the vehicle processes.
|
||||
@ -79,6 +83,7 @@ public interface InternalVehicleService
|
||||
/**
|
||||
* Updates the vehicle's current orientation angle (-360..360 degrees, or {@link Double#NaN}, if
|
||||
* the vehicle doesn't provide an angle).
|
||||
* 如果车辆不提供角度,则更新车辆的当前方向角(-360..360度,或{@link double},如果车辆不提供角度)。
|
||||
*
|
||||
* @param ref A reference to the vehicle to be modified.
|
||||
* @param angle The vehicle's orientation angle.
|
||||
@ -92,6 +97,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Places a vehicle on a point.
|
||||
* 将车辆放在一个点上。
|
||||
*
|
||||
* @param vehicleRef A reference to the vehicle to be modified.
|
||||
* @param pointRef A reference to the point on which the vehicle is to be placed.
|
||||
@ -105,6 +111,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates the vehicle's current precise position in mm.
|
||||
* 更新车辆在MM中的当前精确位置。
|
||||
*
|
||||
* @param ref A reference to the vehicle to be modified.
|
||||
* @param position The vehicle's precise position in mm.
|
||||
@ -118,6 +125,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates the vehicle's pose.
|
||||
* 更新车辆的姿势。
|
||||
*
|
||||
* @param ref A reference to the vehicle to be modified.
|
||||
* @param pose The vehicle's new pose.
|
||||
@ -135,6 +143,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates a vehicle's processing state.
|
||||
* 更新车辆的处理状态。
|
||||
*
|
||||
* @param ref A reference to the vehicle to be modified.
|
||||
* @param state The vehicle's new processing state.
|
||||
@ -145,6 +154,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates a vehicle's recharge operation.
|
||||
* 更新车辆的充电操作。
|
||||
*
|
||||
* @param ref A reference to the vehicle to be modified.
|
||||
* @param rechargeOperation The vehicle's new recharge action.
|
||||
@ -155,6 +165,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates a vehicle's claimed resources.
|
||||
* 更新车辆声称的资源。
|
||||
*
|
||||
* @param ref A reference to the vehicle to be modified.
|
||||
* @param resources The new resources.
|
||||
@ -168,6 +179,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates a vehicle's allocated resources.
|
||||
* 更新车辆分配的资源。
|
||||
*
|
||||
* @param ref A reference to the vehicle to be modified.
|
||||
* @param resources The new resources.
|
||||
@ -181,6 +193,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates a vehicle's state.
|
||||
* 更新车辆的状态。
|
||||
*
|
||||
* @param ref A reference to the vehicle to be modified.
|
||||
* @param state The vehicle's new state.
|
||||
@ -191,6 +204,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates a vehicle's length.
|
||||
* 更新车辆的长度。
|
||||
*
|
||||
* @param ref A reference to the vehicle to be modified.
|
||||
* @param length The vehicle's new length.
|
||||
@ -204,6 +218,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates the vehicle's bounding box.
|
||||
* 更新车辆的边界框。
|
||||
*
|
||||
* @param ref A reference to the vehicle.
|
||||
* @param boundingBox The vehicle's new bounding box (in mm).
|
||||
@ -219,6 +234,7 @@ public interface InternalVehicleService
|
||||
|
||||
/**
|
||||
* Updates a vehicle's transport order.
|
||||
* 更新车辆的运输订单。
|
||||
*
|
||||
* @param vehicleRef A reference to the vehicle to be modified.
|
||||
* @param orderRef A reference to the transport order the vehicle processes.
|
||||
|
@ -29,6 +29,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Sets the scheduler implementation to be used.
|
||||
* 设置要使用的调度程序实现。
|
||||
*
|
||||
* @param clazz The implementation.
|
||||
*/
|
||||
@ -38,6 +39,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Sets the router implementation to be used.
|
||||
* 设置要使用的路由器实现。
|
||||
*
|
||||
* @param clazz The implementation.
|
||||
*/
|
||||
@ -47,6 +49,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Sets the dispatcher implementation to be used.
|
||||
* 设置要使用的调度程序实现。
|
||||
*
|
||||
* @param clazz The implementation.
|
||||
*/
|
||||
@ -56,6 +59,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Sets the peripheral job dispatcher implementation to be used.
|
||||
* 设置要使用的外围作业调度器实现。
|
||||
*
|
||||
* @param clazz The implementation.
|
||||
*/
|
||||
@ -65,6 +69,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Returns a multibinder that can be used to register kernel extensions for all kernel states.
|
||||
* 返回一个多索引器,可用于为所有内核状态注册内核扩展。
|
||||
*
|
||||
* @return The multibinder.
|
||||
*/
|
||||
@ -75,6 +80,7 @@ public abstract class KernelInjectionModule
|
||||
/**
|
||||
* Returns a multibinder that can be used to register kernel extensions for the kernel's modelling
|
||||
* state.
|
||||
* 返回一个多索引器,可用于为内核的建模状态注册内核扩展。
|
||||
*
|
||||
* @return The multibinder.
|
||||
*/
|
||||
@ -85,6 +91,7 @@ public abstract class KernelInjectionModule
|
||||
/**
|
||||
* Returns a multibinder that can be used to register kernel extensions for the kernel's operating
|
||||
* state.
|
||||
* 返回一个多索引器,可用于为内核的操作状态注册内核扩展。
|
||||
*
|
||||
* @return The multibinder.
|
||||
*/
|
||||
@ -94,6 +101,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Returns a multibinder that can be used to register vehicle communication adapter factories.
|
||||
* 返回一个多索引器,可用于注册车辆通信适配器工厂。
|
||||
*
|
||||
* @return The multibinder.
|
||||
*/
|
||||
@ -103,6 +111,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Returns a multibinder that can be used to register vehicle data transformer factories.
|
||||
* 返回一个多索引器,可用于注册车辆数据转换器工厂。
|
||||
*
|
||||
* @return The multibinder.
|
||||
*/
|
||||
@ -112,6 +121,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Returns a multibinder that can be used to register peripheral communication adapter factories.
|
||||
* 返回一个多索引器,可用于注册外围通信适配器工厂。
|
||||
*
|
||||
* @return The multibinder.
|
||||
*/
|
||||
@ -121,6 +131,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Returns a multibinder that can be used to register transport order cleanup approvals.
|
||||
* 返回一个多索引器,可用于注册运输订单清理批准。
|
||||
*
|
||||
* @return The multibinder.
|
||||
*/
|
||||
@ -130,6 +141,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Returns a multibinder that can be used to register order sequence cleanup approvals.
|
||||
* 返回一个多索引器,可用于注册订单序列清理批准。
|
||||
*
|
||||
* @return The multibinder.
|
||||
*/
|
||||
@ -139,6 +151,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Returns a multibinder that can be used to register peripheral job cleanup approvals.
|
||||
* 返回一个多索引器,可用于注册订单序列清理批准。
|
||||
*
|
||||
* @return The multibinder.
|
||||
*/
|
||||
@ -148,6 +161,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Returns a multibinder that can be used to register scheduler modules.
|
||||
* 返回一个可用于注册调度程序模块的多索引器。
|
||||
*
|
||||
* @return The multibinder.
|
||||
*/
|
||||
@ -157,6 +171,7 @@ public abstract class KernelInjectionModule
|
||||
|
||||
/**
|
||||
* Returns a mapbinder that can be used to register edge evaluators.
|
||||
* 返回一个可用于注册边缘评估器的地图绑定器。
|
||||
*
|
||||
* @return The mapbinder.
|
||||
*/
|
||||
|
@ -0,0 +1,40 @@
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
@ -2,3 +2,4 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
org.opentcs.virtualvehicle.LoopbackCommAdapterModule
|
||||
org.opentcs.kcvehicle.KcCommAdapterModule
|
||||
|
@ -0,0 +1,10 @@
|
||||
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);
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
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());
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
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() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
// 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();
|
||||
}
|
@ -8,6 +8,8 @@ import com.google.inject.assistedinject.Assisted;
|
||||
import jakarta.inject.Inject;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -17,6 +19,8 @@ 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.Pose;
|
||||
import org.opentcs.data.model.Triple;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.Route.Step;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
@ -27,6 +31,19 @@ import org.opentcs.drivers.vehicle.SimVehicleCommAdapter;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
import org.opentcs.drivers.vehicle.VehicleProcessModel;
|
||||
import org.opentcs.drivers.vehicle.management.VehicleProcessModelTO;
|
||||
import org.opentcs.kc.udp.Service.ConfirmRelocation;
|
||||
import org.opentcs.kc.udp.Service.HybridNavigation;
|
||||
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.b0.QueryCargoStatusRsp;
|
||||
import org.opentcs.kc.udp.agv.param.function.x17.QueryRobotRunStatusRsp;
|
||||
import org.opentcs.util.ExplainedBoolean;
|
||||
import org.opentcs.virtualvehicle.VelocityController.WayEntry;
|
||||
import org.slf4j.Logger;
|
||||
@ -44,6 +61,7 @@ public class LoopbackCommunicationAdapter
|
||||
|
||||
/**
|
||||
* The name of the load handling device set by this adapter.
|
||||
* 此适配器设置的负载处理设备的名称。
|
||||
*/
|
||||
public static final String LHD_NAME = "default";
|
||||
/**
|
||||
@ -52,38 +70,68 @@ public class LoopbackCommunicationAdapter
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LoopbackCommunicationAdapter.class);
|
||||
/**
|
||||
* An error code indicating that there's a conflict between a load operation and the vehicle's
|
||||
* 一个错误代码,指示加载作与车辆的
|
||||
* current load state.
|
||||
* 当前负载状态。
|
||||
*/
|
||||
private static final String LOAD_OPERATION_CONFLICT = "cannotLoadWhenLoaded";
|
||||
/**
|
||||
* An error code indicating that there's a conflict between an unload operation and the vehicle's
|
||||
* 一个错误代码,指示卸载作与车辆的
|
||||
* current load state.
|
||||
* 当前负载状态。
|
||||
*/
|
||||
private static final String UNLOAD_OPERATION_CONFLICT = "cannotUnloadWhenNotLoaded";
|
||||
/**
|
||||
* The time (in ms) of a single simulation step.
|
||||
* 单个仿真步骤的时间 (毫秒)。
|
||||
*/
|
||||
private static final int SIMULATION_PERIOD = 100;
|
||||
/**
|
||||
* This instance's configuration.
|
||||
* 此实例的配置。
|
||||
*/
|
||||
private final VirtualVehicleConfiguration configuration;
|
||||
/**
|
||||
* Indicates whether the vehicle simulation is running or not.
|
||||
* 指示车辆模拟是否正在运行。
|
||||
*/
|
||||
private volatile boolean isSimulationRunning;
|
||||
/**
|
||||
* The vehicle to this comm adapter instance.
|
||||
* 车辆到此通信适配器实例。
|
||||
*/
|
||||
private final Vehicle vehicle;
|
||||
/**
|
||||
* The vehicle's load state.
|
||||
* 车辆的负载状态。
|
||||
*/
|
||||
private LoadState loadState = LoadState.EMPTY;
|
||||
/**
|
||||
* Whether the loopback adapter is initialized or not.
|
||||
* 环回适配器是否已初始化。
|
||||
*/
|
||||
private boolean initialized;
|
||||
/**
|
||||
* 上报截止时间
|
||||
*/
|
||||
private long deadline;
|
||||
/**
|
||||
* 上报间隔时间/ms
|
||||
*/
|
||||
private long intervalTime;
|
||||
// /**
|
||||
// * AGV IP
|
||||
// */
|
||||
// private final String IP;
|
||||
// /**
|
||||
// * AGV 端口
|
||||
// */
|
||||
// private final int PORT;
|
||||
// /**
|
||||
// * AGV AUTHORIZE_CODE
|
||||
// */
|
||||
// private final String AUTHORIZE_CODE;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
@ -210,6 +258,42 @@ public class LoopbackCommunicationAdapter
|
||||
public synchronized void sendCommand(MovementCommand cmd) {
|
||||
requireNonNull(cmd, "cmd");
|
||||
|
||||
System.out.println(cmd);
|
||||
|
||||
System.out.println("send cmd print start");
|
||||
|
||||
//订单ID
|
||||
String orderName = cmd.getTransportOrder().getName();
|
||||
System.out.println("orderID:" + orderName);
|
||||
|
||||
//路线名称
|
||||
String pathName = cmd.getStep().getPath().getName();
|
||||
System.out.println("pathName:" + pathName);
|
||||
|
||||
//路线长度
|
||||
long length = cmd.getStep().getPath().getLength();
|
||||
System.out.println("pathLength:" + length);
|
||||
|
||||
//当前点位操作
|
||||
String operation = cmd.getOperation();
|
||||
System.out.println("operation:" + operation);
|
||||
|
||||
//下发起点
|
||||
String sourcePoint = cmd.getStep().getSourcePoint().getName();
|
||||
System.out.println("sourcePoint:" + sourcePoint);
|
||||
|
||||
//下发终点
|
||||
String destinationPoint = cmd.getStep().getDestinationPoint().getName();
|
||||
System.out.println("destinationPoint:" + destinationPoint);
|
||||
|
||||
//拼接起点终点字符串转为Integer类型获取唯一pathID
|
||||
Integer pathID = Integer.parseInt(sourcePoint + destinationPoint);
|
||||
System.out.println("pathID:" + pathID);
|
||||
System.out.println("send cmd print end");
|
||||
|
||||
//AGV控制器执行命令
|
||||
HybridNavigation.command("1", sourcePoint, destinationPoint, operation);
|
||||
|
||||
// Start the simulation task if we're not in single step mode and not simulating already.
|
||||
if (!getProcessModel().isSingleStepModeEnabled()
|
||||
&& !isSimulationRunning) {
|
||||
@ -234,6 +318,75 @@ public class LoopbackCommunicationAdapter
|
||||
|
||||
@Override
|
||||
public void processMessage(Object message) {
|
||||
if (message instanceof String) {
|
||||
//测试使用
|
||||
getProcessModel().setEnergyLevel(66);
|
||||
System.out.println(message);
|
||||
}
|
||||
else if (message instanceof QueryCargoStatusRsp) {
|
||||
//0xB0响应结果
|
||||
QueryCargoStatusRsp queryCargoStatusRsp = (QueryCargoStatusRsp) 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().setState(Vehicle.State.EXECUTING);
|
||||
|
||||
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");
|
||||
getProcessModel().setPose(new Pose(triple, positionAngle));
|
||||
}
|
||||
|
||||
//上报自动续订操作
|
||||
// renewalSubscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅到期,自动续订
|
||||
*/
|
||||
private void renewalSubscribe() {
|
||||
|
||||
Date now = new Date();
|
||||
if (now.getTime() + intervalTime >= deadline) {
|
||||
//开启AGV订阅监听 (0xAF & 0xB0)
|
||||
SubRobotStatue.command();
|
||||
SubCargoStatus.command();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -293,15 +446,21 @@ 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();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void disconnectVehicle() {
|
||||
getProcessModel().setCommAdapterConnected(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized boolean isVehicleConnected() {
|
||||
return true;
|
||||
return getProcessModel().isCommAdapterConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -556,4 +715,59 @@ public class LoopbackCommunicationAdapter
|
||||
EMPTY,
|
||||
FULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化AGV
|
||||
* 步骤:
|
||||
* 1:调度软件启动、机器人启动(无顺序要求)。
|
||||
* 2:等待调度系统以及机器人控制器启动完成,调度系统启动即向机器人发送状态查询,查询成功即为启动完成。
|
||||
* 3:调度软件发送订阅信令至机器人,表明订阅机器人状态信息或载货状态;机器人接收到订阅信令,会依据订阅要求推送订阅信息;度软件需要根据订阅信令中“上报持续时间”提前刷新机器人推送的“上报持续时间”。
|
||||
* 4:调度软件持续监控机器人实时状态。
|
||||
* 5:导航初始化
|
||||
*/
|
||||
private void initAGV() {
|
||||
|
||||
//0xAF获取AGV状态
|
||||
QueryRobotStatusRsp qryRobotStatusRsp = QryRobotStatus.command();
|
||||
|
||||
//设置订阅时间和上报间隔
|
||||
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;
|
||||
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
|
@ -15,4 +15,12 @@ public interface GuestUserCredentials {
|
||||
* The default/guest password.
|
||||
*/
|
||||
String PASSWORD = "xyz";
|
||||
/**
|
||||
* 主机IP
|
||||
*/
|
||||
String IP = "192.168.0.106";
|
||||
/**
|
||||
* 内核开放端口
|
||||
*/
|
||||
Integer PORT = 1099;
|
||||
}
|
||||
|
@ -41,5 +41,17 @@ public interface LoopbackAdapterConstants {
|
||||
* The key of the vehicle property that specifies the maximum decceleration of a vehicle.
|
||||
*/
|
||||
String PROPKEY_DECELERATION = "loopback:deceleration";
|
||||
/**
|
||||
* AGV 控制器授权码
|
||||
*/
|
||||
String AGV_AUTHORIZE_CODE = "AGV:AUTHORIZE_CODE";
|
||||
/**
|
||||
* AGV IP
|
||||
*/
|
||||
String AGV_IP = "AGV:IP";
|
||||
/**
|
||||
* AGV 端口
|
||||
*/
|
||||
String AGV_PORT = "AGV:PORT";
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
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) {
|
||||
// 将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(RcvEventPackage rcv){
|
||||
|
||||
for (byte b: rcv.getDataBytes()){
|
||||
System.out.print(byteToHex(b)+" ");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package org.opentcs.kc.udp.Service;
|
||||
|
||||
import org.opentcs.kc.udp.agv.param.AgvEvent;
|
||||
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{
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
public static void commnd() {
|
||||
//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());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
package org.opentcs.kc.udp.Service;
|
||||
|
||||
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.navigation.Action;
|
||||
import org.opentcs.kc.udp.agv.param.function.navigation.ActionSet;
|
||||
import org.opentcs.kc.udp.agv.param.function.navigation.NavigationParam;
|
||||
import org.opentcs.kc.udp.agv.param.function.navigation.Path;
|
||||
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{
|
||||
|
||||
/**
|
||||
* 测试模式:true=开启测试,false=关闭测试
|
||||
* 测试模式因orderName为String类型数据,无法转换为Integer
|
||||
*/
|
||||
private static boolean TEST_MODEL = false;
|
||||
/**
|
||||
* 订单ID
|
||||
* 订单的唯一标识。用于标识多个任务KEY是否属于同一个订单。机器人单次只能接收同一订单ID的任务,直至订单结束,调度可下发新的订单ID,订单ID从1开始累加,每次+1。
|
||||
* 注:同一订单ID支持不停车更新导航。
|
||||
*/
|
||||
private static Integer orderID = 0;
|
||||
/**
|
||||
* 任务ID
|
||||
* 任务的唯一标识。与订单ID绑定,从1开始,当同一订单下发新的资源时加1;订单ID发生改变,任务KEY需要重新计数。
|
||||
*/
|
||||
private static Integer taskKey;
|
||||
/**
|
||||
* 序列号
|
||||
* 用于定位点在整个任务中的位置。目的是区分同一个点ID是否在一个任务中出现多次。从0开始偶数递增,例如:0->2->4->6……
|
||||
*/
|
||||
private static Integer pointSerialNum = 0;
|
||||
/**
|
||||
* 用于定位段在整个任务中的位置。目的是区分同一个段ID是否在一个任务中出现多次。从1开始奇数递增,例如:1->3->5->7……
|
||||
*/
|
||||
private static Integer pathSerialNum = 1;
|
||||
|
||||
|
||||
/**
|
||||
* decs: 导航控制
|
||||
* 指令: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);
|
||||
//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)
|
||||
};
|
||||
|
||||
//构建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) ,
|
||||
};
|
||||
NavigationParam navigationParam = new NavigationParam(orderID,taskKey,ByteUtils.usintTo1Byte(points.length),ByteUtils.usintTo1Byte(points.length-1),points,paths);
|
||||
agvEvent.setBody(navigationParam.toBytes());
|
||||
|
||||
return agvEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param orderName 订单ID
|
||||
* @param sourcePoint 下发起点
|
||||
* @param destinationPoint 下发终点
|
||||
* @param operation 执行操作
|
||||
*/
|
||||
public static void command(String orderName, String sourcePoint, String destinationPoint, String operation) {
|
||||
if (TEST_MODEL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer newOrderName = Integer.parseInt(orderName);
|
||||
Integer newSourcePoint = Integer.parseInt(sourcePoint);
|
||||
Integer newDestinationPoint = Integer.parseInt(destinationPoint);
|
||||
//拼接起点终点字符串转为Integer类型获取唯一pathID
|
||||
Integer pathID = Integer.parseInt(sourcePoint + destinationPoint);
|
||||
|
||||
if (!orderID.equals(newOrderName)) {
|
||||
//切换订单重置参数
|
||||
initParams(newOrderName);
|
||||
}
|
||||
|
||||
//0xAE(导航控制导航点控制)
|
||||
AgvEvent agvEvent = navigationControl(newSourcePoint, newDestinationPoint, pathID, operation);
|
||||
printInfo(agvEvent);
|
||||
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
|
||||
if(rcv.isOk()){
|
||||
System.out.println("0xAE ok");
|
||||
}else {
|
||||
System.out.println();
|
||||
System.out.println("0xAE fail");
|
||||
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化参数
|
||||
* @param newOrderName 新的订单ID
|
||||
*/
|
||||
private static void initParams(Integer newOrderName) {
|
||||
orderID = newOrderName;
|
||||
taskKey = 1;
|
||||
pointSerialNum = 0;
|
||||
pathSerialNum = 1;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package org.opentcs.kc.udp.Service;
|
||||
|
||||
|
||||
import org.opentcs.kc.udp.agv.param.AgvEvent;
|
||||
import org.opentcs.kc.udp.agv.param.AgvEventConstant;
|
||||
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 static AgvEvent manualLocation(double agvX, double agvY, double agvAngle) {
|
||||
AgvEvent agvEvent = new AgvEvent(AgvEventConstant.CommandCode_ROBOT_SET_POSITION);
|
||||
RobotSetPosition robotSetPosition = new RobotSetPosition(agvX, agvY, agvAngle);
|
||||
byte[] bytes = robotSetPosition.toBytes();
|
||||
agvEvent.setBody(bytes);
|
||||
return agvEvent;
|
||||
}
|
||||
|
||||
public static void command(double agvX, double agvY, double agvAngle) {
|
||||
//0x14(手动定位)
|
||||
AgvEvent agvEvent = manualLocation(agvX, agvY, agvAngle);
|
||||
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());
|
||||
throw new RuntimeException("0x14 failed");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package org.opentcs.kc.udp.Service;
|
||||
|
||||
import org.opentcs.kc.udp.agv.param.AgvEvent;
|
||||
import org.opentcs.kc.udp.agv.param.AgvEventConstant;
|
||||
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{
|
||||
|
||||
/**
|
||||
* 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 QueryRobotRunStatusRsp command() {
|
||||
//0x17(查询机器人运行状态)
|
||||
AgvEvent agvEvent = queryRobotRunStatus();
|
||||
printInfo(agvEvent);
|
||||
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
|
||||
if(rcv.isOk()){
|
||||
//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)+" ");
|
||||
}
|
||||
return queryRobotRunStatusRsp;
|
||||
}else {
|
||||
System.out.println();
|
||||
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
|
||||
throw new RuntimeException("0x17 fail");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package org.opentcs.kc.udp.Service;
|
||||
|
||||
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.rsp.RcvEventPackage;
|
||||
import org.opentcs.kc.udp.io.UDPClient;
|
||||
|
||||
/**
|
||||
* @author xzh
|
||||
* @date 2025/2/21
|
||||
* @desc 查询机器人状态
|
||||
*/
|
||||
public class QryRobotStatus
|
||||
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;
|
||||
}
|
||||
|
||||
public static QueryRobotStatusRsp command() {
|
||||
//0xAF(查询机器人状态)
|
||||
AgvEvent agvEvent = queryStatus();
|
||||
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)+" ");
|
||||
// }
|
||||
}else {
|
||||
System.out.println();
|
||||
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
|
||||
throw new RuntimeException("0xAF fail");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package org.opentcs.kc.udp.Service;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.opentcs.kc.udp.agv.param.AgvEvent;
|
||||
import org.opentcs.kc.udp.agv.param.AgvEventConstant;
|
||||
import org.opentcs.kc.udp.agv.param.function.b0.QueryCargoStatusRsp;
|
||||
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.rsp.RcvEventPackage;
|
||||
import org.opentcs.kc.udp.io.UDPClient;
|
||||
|
||||
/**
|
||||
* @author xzh
|
||||
* @date 2025/2/21
|
||||
* @desc 订阅载货状态
|
||||
*/
|
||||
public class SubCargoStatus extends BaseCommand{
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
public static void command()
|
||||
{
|
||||
// 0xB1(订阅信息)
|
||||
AgvEvent agvEvent = issueSubscribe();
|
||||
printInfo(agvEvent);
|
||||
//todo 订阅参数构建完毕 去写 回调部分
|
||||
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
|
||||
if(rcv.isOk()){
|
||||
System.out.println();
|
||||
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
|
||||
SubscribeRsp subscribeRsp = new SubscribeRsp(rcv.getDataBytes());
|
||||
if(subscribeRsp.isOk()){
|
||||
//...
|
||||
}else {
|
||||
//...
|
||||
}
|
||||
}else {
|
||||
System.out.println();
|
||||
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
|
||||
}
|
||||
}
|
||||
|
||||
//订阅执行操作
|
||||
public void subscribe0xB0Operate(String name,QueryCargoStatusRsp queryCargoStatusRsp)
|
||||
{
|
||||
|
||||
// Vehicle vehicle = vehicleService.fetchObject(Vehicle.class, name);
|
||||
//修改载货状态
|
||||
if (queryCargoStatusRsp.isCargo == 0) {
|
||||
//未载货
|
||||
} else if (queryCargoStatusRsp.isCargo == 1) {
|
||||
//载货
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package org.opentcs.kc.udp.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.opentcs.kc.udp.agv.param.AgvEvent;
|
||||
import org.opentcs.kc.udp.agv.param.AgvEventConstant;
|
||||
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.rsp.RcvEventPackage;
|
||||
import org.opentcs.kc.udp.io.UDPClient;
|
||||
|
||||
/**
|
||||
* @author xzh
|
||||
* @date 2025/2/21
|
||||
* @desc 订阅机器人状态
|
||||
*/
|
||||
public class SubRobotStatue extends BaseCommand {
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
public static void command() {
|
||||
// 0xB1(订阅信息)
|
||||
AgvEvent agvEvent = issueSubscribe();
|
||||
printInfo(agvEvent);
|
||||
//todo 订阅参数构建完毕 去写 回调部分
|
||||
RcvEventPackage rcv = UDPClient.localAGV.send(agvEvent);
|
||||
if(rcv.isOk()){
|
||||
System.out.println();
|
||||
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
|
||||
SubscribeRsp subscribeRsp = new SubscribeRsp(rcv.getDataBytes());
|
||||
if(subscribeRsp.isOk()){
|
||||
//...
|
||||
}else {
|
||||
//...
|
||||
}
|
||||
}else {
|
||||
System.out.println();
|
||||
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package org.opentcs.kc.udp.Service;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
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.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.rsp.RcvEventPackage;
|
||||
import org.opentcs.kc.udp.io.UDPClient;
|
||||
|
||||
/**
|
||||
* @author xzh
|
||||
* @date 2025/2/21
|
||||
* @desc 切换自动模式
|
||||
*/
|
||||
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));
|
||||
valueMemberList.add(valueMember1);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static void command() {
|
||||
//0x03(切换手自动)
|
||||
AgvEvent agvEvent = writeValue();
|
||||
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("write ok");
|
||||
}else {
|
||||
System.out.println("write failed");
|
||||
}
|
||||
}else {
|
||||
System.out.println();
|
||||
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package org.opentcs.kc.udp.Service;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
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.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.rsp.RcvEventPackage;
|
||||
import org.opentcs.kc.udp.io.UDPClient;
|
||||
|
||||
/**
|
||||
* @author xzh
|
||||
* @date 2025/2/21
|
||||
* @desc 切换手动模式
|
||||
*/
|
||||
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));
|
||||
valueMemberList.add(valueMember1);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static void command() {
|
||||
//0x03(切换手自动)
|
||||
AgvEvent agvEvent = writeValue();
|
||||
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("write ok");
|
||||
}else {
|
||||
System.out.println("write failed");
|
||||
}
|
||||
}else {
|
||||
System.out.println();
|
||||
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import java.net.InetSocketAddress;
|
||||
import org.opentcs.kc.common.Package;
|
||||
import org.opentcs.kc.syn.SendedList;
|
||||
import org.opentcs.kc.udp.agv.param.rsp.RcvEventPackage;
|
||||
@ -60,7 +61,12 @@ public class AgvUdpDecode extends SimpleChannelInboundHandler<DatagramPacket> {
|
||||
byte commandCode = body[21];
|
||||
|
||||
if(body[18]==(byte)0x00 && body[19]==(byte)0x00){
|
||||
if(commandCode == (byte)0xAF ){
|
||||
|
||||
//获取响应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));
|
||||
|
@ -53,7 +53,7 @@ public class QueryRobotRunStatusRsp {
|
||||
//累计运行时间(单位 ms),8个字节
|
||||
private double cumulativeRunTime;
|
||||
//机器人定位状态,1个字节
|
||||
private byte robotLocalizationState;
|
||||
public byte robotLocalizationState;
|
||||
//保留,3个字节
|
||||
private byte[] retain3;
|
||||
//地图数量,U32,4个字节
|
||||
|
@ -9,6 +9,12 @@ 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.Set;
|
||||
import org.opentcs.access.KernelServicePortal;
|
||||
import org.opentcs.access.rmi.KernelServicePortalBuilder;
|
||||
import org.opentcs.common.GuestUserCredentials;
|
||||
import org.opentcs.components.kernel.services.VehicleService;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.kc.common.Package;
|
||||
import org.opentcs.kc.common.byteutils.ByteUtil;
|
||||
import org.opentcs.kc.syn.AsyncFuture;
|
||||
@ -29,9 +35,14 @@ import org.slf4j.LoggerFactory;
|
||||
public enum UDPClient {
|
||||
//如果要配置多个链接, local1 local2 .... 这样排下去好了
|
||||
|
||||
localAGV("agv1","192.168.0.211",17804,55678),
|
||||
localAGV("1","192.168.0.211",17804,55678),
|
||||
//local("127.0.0.1",502,true),
|
||||
;
|
||||
|
||||
// 服务端地址+端口
|
||||
private String SERVICE_HOST = "192.168.0.123";
|
||||
private Integer SERVICE_PORT = 1099;
|
||||
|
||||
private String name;
|
||||
private String host;
|
||||
//默认 0 port
|
||||
@ -132,35 +143,88 @@ public enum UDPClient {
|
||||
}
|
||||
|
||||
public void subscribe0xB0(RcvEventPackage rcv){
|
||||
if(name.equals("agv1")){
|
||||
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)+" ");
|
||||
}
|
||||
}else if(name.equals("agv2")){
|
||||
//....
|
||||
|
||||
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(name.equals("agv1")){
|
||||
if(rcv.isOk()){
|
||||
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)+" ");
|
||||
}
|
||||
}else {
|
||||
System.out.println();
|
||||
System.out.println("received transationId : "+ "isok:"+rcv.isOk());
|
||||
}
|
||||
}else if(name.equals("agv2")){
|
||||
//....
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 0xAF上报信息传入通讯适配器
|
||||
* @param vehicleName 车辆名称
|
||||
* @param rcv 响应数据
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 0xB0上报信息传入通讯适配器
|
||||
* @param vehicleName 车辆名称
|
||||
* @param rcv 响应数据
|
||||
*/
|
||||
private void achieveSub0xB0(String vehicleName ,RcvEventPackage rcv){
|
||||
|
||||
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);
|
||||
|
||||
servicePortal.logout();
|
||||
}
|
||||
|
||||
public static void printInfo(AgvEvent agvEvent){
|
||||
System.out.println("sended transationId : "+agvEvent.getTransationIdString());
|
||||
for (byte b:agvEvent.toBytes().getBody()){
|
||||
|
@ -9,11 +9,18 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentcs.access.KernelServicePortal;
|
||||
import org.opentcs.access.rmi.KernelServicePortalBuilder;
|
||||
import org.opentcs.components.kernel.services.PlantModelService;
|
||||
import org.opentcs.components.kernel.services.VehicleService;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
|
||||
/**
|
||||
* Tests for {@link SameThreadExecutorService}.
|
||||
@ -79,4 +86,40 @@ 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 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);
|
||||
|
||||
//向车辆对应的通讯适配器发送消息
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,6 +39,9 @@ public class DefaultPropertySuggestions
|
||||
keySuggestions.add(LoopbackAdapterConstants.PROPKEY_ACCELERATION);
|
||||
keySuggestions.add(LoopbackAdapterConstants.PROPKEY_DECELERATION);
|
||||
keySuggestions.add(ObjectPropConstants.VEHICLE_DATA_TRANSFORMER);
|
||||
keySuggestions.add(LoopbackAdapterConstants.AGV_AUTHORIZE_CODE);
|
||||
keySuggestions.add(LoopbackAdapterConstants.AGV_IP);
|
||||
keySuggestions.add(LoopbackAdapterConstants.AGV_PORT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user