Skip to content

Commit dcc63c5

Browse files
committed
Version 4.20 (2020-12-18)
Fixes: Default Scheduler: Properly handle requests for same-direction blocks for some edge cases. Default Scheduler: Really free all resources when taking a vehicle out of the driving course. Other changes: Plant Overview: Improve performance for vehicle state updates. 版本4.20 (2020-12-18) 修复: 默认调度器:适当地处理一些边缘情况下的相同方向管制区的请求。 默认调度器:真正释放所有资源时,采取车辆的行驶线路。 其他变化: 模型视图:改善车辆状态更新的性能。
1 parent b5554b1 commit dcc63c5

File tree

32 files changed

+1054
-287
lines changed

32 files changed

+1054
-287
lines changed

.github/workflows/gradle.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,9 @@ jobs:
4646
prerelease: false
4747
- name: Upload Release Asset
4848
id: upload-release-asset
49-
uses: actions/upload-release-asset@v1
49+
uses: actions/upload-release-asset@v2
5050
env:
5151
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5252
with:
5353
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
54-
asset_path: ./build/distributions/openTCS-4.19.0-SNAPSHOT-bin.zip
55-
asset_name: openTCS-4.19.0-SNAPSHOT-bin.zip
56-
asset_content_type: application/zip
54+
asset_path: ./build/distributions/openTCS-*-SNAPSHOT-bin.zip

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ target/
3535
/.gradle/4.10.3/
3636
/.gradle/buildOutputCleanup/
3737
/.gradle/vcs-1/
38+
*/bin/*
39+
.DS_Store
40+
*/venv/*
3841
/Simulation/build/
3942
/openTCS-Strategies-Default/build/
4043
/openTCS-PlantOverview-Themes-Default/build/

OpenTCS.md

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
juice 如何使用注入
2+
在opentcs中使用注入非常的简单,只需要在类的构造方法中指定参数即可。例如需要用到TCSObjectService这个服务,在参数中指定,然后接收此参数,需要检测非空。
3+
```@Inject
4+
public OrderHandler(TransportOrderService orderService,
5+
VehicleService vehicleService,
6+
DispatcherService dispatcherService,
7+
@KernelExecutor ExecutorService kernelExecutor,
8+
// @ServiceCallWrapper CallWrapper callWrapper,
9+
@Nonnull TCSObjectService objectService) {
10+
this.orderService = requireNonNull(orderService, "orderService");
11+
this.vehicleService = requireNonNull(vehicleService, "vehicleService");
12+
this.dispatcherService = requireNonNull(dispatcherService, "dispatcherService");
13+
this.kernelExecutor = requireNonNull(kernelExecutor, "kernelExecutor");
14+
// this.callWrapper = requireNonNull(callWrapper, "callWrapper");
15+
this.objectService = requireNonNull(objectService, "objectService");
16+
}
17+
```
18+
扩展HTTP接口
19+
20+
通过HTTP接口发送指令给指定车辆
21+
22+
发送指令给适配器需要获取车辆名称的引用,再调用VehicleService的sendCommAdapter方法即可。在适配器中重写BasicVehicleCommAdapter中的
23+
excute方法,接收VehicleCommAdapterEvent事件。
24+
25+
```
26+
public String sendCommand(String name, Command command) {
27+
try {
28+
TCSObjectReference<Vehicle> vehicleReference = vehicleService.fetchObject(Vehicle.class, name).getReference();
29+
VehicleCommAdapterEvent event = new VehicleCommAdapterEvent(name, command.getCommand());
30+
try {
31+
// callWrapper.call(() -> vehicleService.sendCommAdapterCommand(vehicleReference, new PublishEventCommand(event)));
32+
vehicleService.sendCommAdapterCommand(vehicleReference, new PublishEventCommand(event));
33+
34+
} catch (Exception e) {
35+
LOG.warn("Can't send command to vehicle");
36+
e.getMessage();
37+
throw new ObjectUnknownException(("Can't send command to vehicle"));
38+
}
39+
40+
} catch (Exception e) {
41+
e.getMessage();
42+
LOG.warn("Can't found vechile name: {}", name);
43+
throw new ObjectUnknownException("Unknow Vehicle name: " + name);
44+
}
45+
return String.format("Send command: %s to Vehicle: %s success.", command.getCommand(),name);
46+
}
47+
```
48+
49+
```
50+
@Override
51+
public void execute(AdapterCommand command) {
52+
PublishEventCommand publishCommand = (PublishEventCommand) command;
53+
```
54+
55+
适配器任务
56+
57+
基础适配器有两个列表分别是移动指令列表和以发送指令列表,当判断适配器可以发送命令则从移动指令列表取出添加到已发送列表
58+
59+
```
60+
BasicVehicleCommAdapter
61+
/**
62+
* This adapter's command queue.
63+
*/
64+
private final Queue<MovementCommand> commandQueue = new LinkedBlockingQueue<>();
65+
/**
66+
* Contains the orders which have been sent to the vehicle but which haven't
67+
* been executed by it, yet.
68+
*/
69+
private final Queue<MovementCommand> sentQueue = new LinkedBlockingQueue<>();
70+
71+
if (getSentQueue().size() < sentQueueCapacity) && !getCommandQueue().isEmpty()
72+
curCmd = getCommandQueue().poll();
73+
if (curCmd != null) {
74+
try {
75+
sendCommand(curCmd);
76+
//send driver order,adapter implement sendCommand,receive curCmd
77+
getSentQueue().add(curCmd);
78+
//add driving order to the queue of sent orders
79+
getProcessModel().commandSent(curCmd);
80+
//Notify the kernel that the drive order has been sent to the vehicle
81+
```
82+
83+
跟车辆通行的适配器只操作已发送指令列表,使用peek获取要发送的命令,车辆到达预期地点则使用poll删除已发送指令头部,再使用ProcessModel通知内核,代表车辆执行此命令成功。然后获取下一个指令安装上面的步骤重复执行,知道将所有指令执行情况都上报给内核,此时才会判断路径执行成功。
84+
85+
```
86+
ExampleCommAdapter
87+
curCommand = getSentQueue().peek();
88+
MovementCommand sentcmd = getSentQueue().poll();
89+
getProcessModel().commandExecuted(curCommand);
90+
```
91+
92+
车辆执行完的移动命令如何通知到内核
93+
94+
```
95+
/**
96+
* Notifies observers that the given command has been executed by the comm adapter/vehicle.
97+
*
98+
* @param executedCommand The command that has been executed.
99+
*/
100+
public void commandExecuted(@Nonnull MovementCommand executedCommand) {
101+
getPropertyChangeSupport().firePropertyChange(Attribute.COMMAND_EXECUTED.name(),
102+
null,
103+
executedCommand);
104+
}
105+
106+
/**
107+
* Notifies observers that the given command could not be executed by the comm adapter/vehicle.
108+
*
109+
* @param failedCommand The command that could not be executed.
110+
*/
111+
public void commandFailed(@Nonnull MovementCommand failedCommand) {
112+
getPropertyChangeSupport().firePropertyChange(Attribute.COMMAND_FAILED.name(),
113+
null,
114+
failedCommand);
115+
}
116+
```
117+
118+
DefaultVehicleController 重写PropertyChangeListener的方法实现监听适配器发送过来的事件,如果执行命令失败会取消此车辆的订单
119+
```
120+
DefaultVehicleController
121+
//属性变更回调函数,使用getProcessModel发送车辆消息监听到车辆属性变更时调用
122+
@Override
123+
public void propertyChange(PropertyChangeEvent evt) {
124+
if (evt.getSource() != commAdapter.getProcessModel()) {
125+
return;
126+
}
127+
128+
handleProcessModelEvent(evt);
129+
}
130+
131+
//处理驱动器消息类型,调用不同的处理函数,如指令发送成功或位置变更
132+
private void handleProcessModelEvent(PropertyChangeEvent evt) {
133+
eventBus.onEvent(new ProcessModelEvent(evt.getPropertyName(),
134+
commAdapter.createTransferableProcessModel()));
135+
136+
if (Objects.equals(evt.getPropertyName(), VehicleProcessModel.Attribute.POSITION.name())) {
137+
updateVehiclePosition((String) evt.getNewValue());
138+
}
139+
else if (Objects.equals(evt.getPropertyName(),
140+
VehicleProcessModel.Attribute.PRECISE_POSITION.name())) {
141+
updateVehiclePrecisePosition((Triple) evt.getNewValue());
142+
}
143+
else if (Objects.equals(evt.getPropertyName(),
144+
VehicleProcessModel.Attribute.ORIENTATION_ANGLE.name())) {
145+
vehicleService.updateVehicleOrientationAngle(vehicle.getReference(),
146+
(Double) evt.getNewValue());
147+
}
148+
else if (Objects.equals(evt.getPropertyName(),
149+
VehicleProcessModel.Attribute.ENERGY_LEVEL.name())) {
150+
vehicleService.updateVehicleEnergyLevel(vehicle.getReference(), (Integer) evt.getNewValue());
151+
}
152+
else if (Objects.equals(evt.getPropertyName(),
153+
VehicleProcessModel.Attribute.LOAD_HANDLING_DEVICES.name())) {
154+
vehicleService.updateVehicleLoadHandlingDevices(vehicle.getReference(),
155+
(List<LoadHandlingDevice>) evt.getNewValue());
156+
}
157+
else if (Objects.equals(evt.getPropertyName(), VehicleProcessModel.Attribute.STATE.name())) {
158+
updateVehicleState((Vehicle.State) evt.getNewValue());
159+
}
160+
else if (Objects.equals(evt.getPropertyName(),
161+
VehicleProcessModel.Attribute.COMM_ADAPTER_STATE.name())) {
162+
updateCommAdapterState((VehicleCommAdapter.State) evt.getNewValue());
163+
}
164+
else if (Objects.equals(evt.getPropertyName(),
165+
VehicleProcessModel.Attribute.COMMAND_EXECUTED.name())) {
166+
commandExecuted((MovementCommand) evt.getNewValue());
167+
}
168+
else if (Objects.equals(evt.getPropertyName(),
169+
VehicleProcessModel.Attribute.COMMAND_FAILED.name())) {
170+
dispatcherService.withdrawByVehicle(vehicle.getReference(), true, false);
171+
}
172+
else if (Objects.equals(evt.getPropertyName(),
173+
VehicleProcessModel.Attribute.USER_NOTIFICATION.name())) {
174+
notificationService.publishUserNotification((UserNotification) evt.getNewValue());
175+
}
176+
else if (Objects.equals(evt.getPropertyName(),
177+
VehicleProcessModel.Attribute.COMM_ADAPTER_EVENT.name())) {
178+
eventBus.onEvent((VehicleCommAdapterEvent) evt.getNewValue());
179+
}
180+
else if (Objects.equals(evt.getPropertyName(),
181+
VehicleProcessModel.Attribute.VEHICLE_PROPERTY.name())) {
182+
VehicleProcessModel.VehiclePropertyUpdate propUpdate
183+
= (VehicleProcessModel.VehiclePropertyUpdate) evt.getNewValue();
184+
vehicleService.updateObjectProperty(vehicle.getReference(),
185+
propUpdate.getKey(),
186+
propUpdate.getValue());
187+
}
188+
else if (Objects.equals(evt.getPropertyName(),
189+
VehicleProcessModel.Attribute.TRANSPORT_ORDER_PROPERTY.name())) {
190+
VehicleProcessModel.TransportOrderPropertyUpdate propUpdate
191+
= (VehicleProcessModel.TransportOrderPropertyUpdate) evt.getNewValue();
192+
if (currentDriveOrder != null) {
193+
vehicleService.updateObjectProperty(currentDriveOrder.getTransportOrder(),
194+
propUpdate.getKey(),
195+
propUpdate.getValue());
196+
}
197+
}
198+
}
199+
200+
```
201+
202+
commandExcuted 判断移动指令是否真的执行成功
203+
204+
```
205+
private void commandExecuted(MovementCommand executedCommand) {
206+
requireNonNull(executedCommand, "executedCommand");
207+
208+
synchronized (commAdapter) {
209+
// Check if the executed command is the one we expect at this point.
210+
MovementCommand expectedCommand = commandsSent.peek();
211+
if (!Objects.equals(expectedCommand, executedCommand)) {
212+
LOG.warn("{}: Communication adapter executed unexpected command: {} != {}",
213+
vehicle.getName(),
214+
executedCommand,
215+
expectedCommand);
216+
// XXX The communication adapter executed an unexpected command. Do something!
217+
}
218+
// Remove the command from the queue, since it has been processed successfully.
219+
lastCommandExecuted = commandsSent.remove();
220+
// Free resources allocated for the command before the one now executed.
221+
Set<TCSResource<?>> oldResources = allocatedResources.poll();
222+
if (oldResources != null) {
223+
LOG.debug("{}: Freeing resources: {}", vehicle.getName(), oldResources);
224+
scheduler.free(this, oldResources);
225+
}
226+
else {
227+
LOG.debug("{}: Nothing to free.", vehicle.getName());
228+
}
229+
// Check if there are more commands to be processed for the current drive order.
230+
if (pendingCommand == null && futureCommands.isEmpty()) {
231+
LOG.debug("{}: No more commands in current drive order", vehicle.getName());
232+
// Check if there are still commands that have been sent to the communication adapter but
233+
// not yet executed. If not, the whole order has been executed completely - let the kernel
234+
// know about that so it can give us the next drive order.
235+
if (commandsSent.isEmpty() && !waitingForAllocation) {
236+
LOG.debug("{}: Current drive order processed", vehicle.getName());
237+
currentDriveOrder = null;
238+
// Let the kernel/dispatcher know that the drive order has been processed completely (by
239+
// setting its state to AWAITING_ORDER).
240+
vehicleService.updateVehicleRouteProgressIndex(vehicle.getReference(),
241+
Vehicle.ROUTE_INDEX_DEFAULT);
242+
vehicleService.updateVehicleProcState(vehicle.getReference(),
243+
Vehicle.ProcState.AWAITING_ORDER);
244+
}
245+
}
246+
// There are more commands to be processed.
247+
// Check if we can send another command to the comm adapter.
248+
else if (canSendNextCommand()) {
249+
allocateForNextCommand();
250+
}
251+
}
252+
}
253+
```
254+
255+
```
256+
/**
257+
* Sets the point which a vehicle is expected to occupy next.
258+
*
259+
* @param vehicleRef A reference to the vehicle to be modified.
260+
* @param pointRef A reference to the point which the vehicle is expected to
261+
* occupy next.
262+
* @throws ObjectUnknownException If the referenced vehicle does not exist.
263+
* @deprecated Use{@link InternalVehicleService#updateVehicleNextPosition(
264+
* org.opentcs.data.TCSObjectReference, org.opentcs.data.TCSObjectReference)} instead.
265+
*/
266+
@Deprecated
267+
void setVehicleNextPosition(TCSObjectReference<Vehicle> vehicleRef,
268+
TCSObjectReference<Point> pointRef)
269+
throws ObjectUnknownException;
270+
271+
/**
272+
* Sets a vehicle's index of the last route step travelled for the current
273+
* drive order of its current transport order.
274+
*
275+
* @param vehicleRef A reference to the vehicle to be modified.
276+
* @param index The new index.
277+
* @throws ObjectUnknownException If the referenced vehicle does not exist.
278+
* @deprecated Use{@link InternalVehicleService#updateVehicleRouteProgressIndex(
279+
* org.opentcs.data.TCSObjectReference, int)} instead.
280+
*/
281+
@Deprecated
282+
void setVehicleRouteProgressIndex(TCSObjectReference<Vehicle> vehicleRef,
283+
int index)
284+
throws ObjectUnknownException;
285+
286+
/**
287+
* Sets a transport order's state.
288+
* Note that transport order states are intended to be manipulated by the
289+
* dispatcher only. Calling this method from any other parts of the kernel may
290+
* result in undefined behaviour.
291+
*
292+
* @param ref A reference to the transport order to be modified.
293+
* @param newState The transport order's new state.
294+
* @throws ObjectUnknownException If the referenced transport order does not
295+
* exist.
296+
* @deprecated Use {@link InternalTransportOrderService#updateTransportOrderState(
297+
* org.opentcs.data.TCSObjectReference, org.opentcs.data.order.TransportOrder.State)} instead.
298+
*/
299+
@Deprecated
300+
void setTransportOrderState(TCSObjectReference<TransportOrder> ref,
301+
TransportOrder.State newState)
302+
throws ObjectUnknownException;
303+
```

gradle/common.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def versionBuild = System.env.BUILD_NUMBER ? "b" + System.env.BUILD_NUMBER : "SN
1111
// - The minor version number should be incremented when new feature were added.
1212
// - The patch level should be incremented with every small change to the code
1313
// (e.g. bugfixes).
14-
project.version = "4.19.0"
14+
project.version = "4.20.0"
1515
if (!(project.hasProperty("NO_BUILD_NUMBER")
1616
&& Boolean.valueOf(project.getProperties().get("NO_BUILD_NUMBER")))) {
1717
project.version += "-$versionBuild"

gradle/java-project.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
apply plugin: 'java'
22

33
sourceCompatibility = '1.8'
4+
targetCompatibility = '1.8'
45
archivesBaseName = name.toLowerCase()
56

67
repositories {

gradlew

100644100755
File mode changed.

openTCS-CommAdapter-Loopback/src/main/java/org/opentcs/virtualvehicle/LoopbackCommAdapterPanel.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ private void initComponents() {
421421
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 3);
422422
vehiclePropsPanel.add(maxFwdVeloTxt, gridBagConstraints);
423423

424-
maxFwdVeloUnitLbl.setText("mmM/s");
424+
maxFwdVeloUnitLbl.setText("mm/s");
425425
gridBagConstraints = new java.awt.GridBagConstraints();
426426
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
427427
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 3);
@@ -863,7 +863,7 @@ public void itemStateChanged(java.awt.event.ItemEvent evt) {
863863

864864
appendixTxt.setEditable(false);
865865
appendixTxt.setColumns(10);
866-
appendixTxt.setText("XYZZ");
866+
appendixTxt.setText("XYZ");
867867
gridBagConstraints = new java.awt.GridBagConstraints();
868868
gridBagConstraints.weightx = 1.0;
869869
gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);

openTCS-CommAdapter-Loopback/src/main/java/org/opentcs/virtualvehicle/LoopbackCommunicationAdapterPanel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1221,7 +1221,7 @@ private void setPrecisePosText(Long x, Long y, Long z) {
12211221
StringBuilder text = new StringBuilder("");
12221222
text.append("X: ").append(xS).append("\n")
12231223
.append("Y: ").append(yS).append("\n")
1224-
.append("ZZ: ").append(zS);
1224+
.append("Z: ").append(zS);
12251225
precisePosTextArea.setText(text.toString());
12261226
}
12271227
// Variables declaration - do not modify//GEN-BEGIN:variables

openTCS-CommAdapter-Loopback/src/main/java/org/opentcs/virtualvehicle/LoopbackVehicleModel.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
*
1818
* @author Stefan Walter (Fraunhofer IML)
1919
*/
20-
public class LoopbackVehicleModel extends VehicleProcessModel implements VelocityListener {
20+
public class LoopbackVehicleModel
21+
extends VehicleProcessModel
22+
implements VelocityListener {
2123

2224
/**
2325
* Indicates whether this communication adapter is in single step mode or not (i.e. in automatic

openTCS-CommAdapter-Loopback/src/main/java/org/opentcs/virtualvehicle/LoopbackVehicleModelTO.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
*
1515
* @author Martin Grzenia (Fraunhofer IML)
1616
*/
17-
public class LoopbackVehicleModelTO extends VehicleProcessModelTO {
17+
public class LoopbackVehicleModelTO
18+
extends VehicleProcessModelTO {
1819

1920
/**
2021
* Whether this communication adapter is in single step mode or not (i.e. in automatic mode).

0 commit comments

Comments
 (0)