Skip to content

Commit 6cd1e6d

Browse files
swltrmartingr
authored andcommitted
Introduce pluggable position deviation policies
Use new injectable component `PositionDeviationPolicy` to provide the allowed deviation for a vehicle at a point. This way, we can e.g. respect VDA5050 deviation properties for position resolution, too. Also, fix the use of orientation angles for deviation calculation: properly treat angles to be in degrees, not in radians. Furthermore, when resolving coordinates to a logical position, ensure that we pick the closest of the matching points in the plant model, not the first one we find. Merged-by: Martin Grzenia <martin.grzenia@iml.fraunhofer.de>
1 parent 01195fa commit 6cd1e6d

File tree

15 files changed

+566
-110
lines changed

15 files changed

+566
-110
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// SPDX-FileCopyrightText: The openTCS Authors
2+
// SPDX-License-Identifier: MIT
3+
package org.opentcs.components.kernel;
4+
5+
import jakarta.annotation.Nonnull;
6+
import org.opentcs.data.model.Point;
7+
8+
/**
9+
* Provides allowed position deviation data for a single vehicle on given points.
10+
* <p>
11+
* Which vehicle this policy provides deviation data for is determined when the policy is created by
12+
* a {@link PositionDeviationPolicyFactory}.
13+
* </p>
14+
*/
15+
public interface PositionDeviationPolicy {
16+
17+
/**
18+
* Returns the allowed deviation distance for the given point, in millimeters.
19+
*
20+
* @param point The point.
21+
* @return The allowed deviation distance.
22+
*/
23+
long allowedDeviationDistance(
24+
@Nonnull
25+
Point point
26+
);
27+
28+
/**
29+
* Returns the allowed deviation angle for the given point, in degrees.
30+
*
31+
* @param point The point.
32+
* @return The allowed deviation angle.
33+
*/
34+
long allowedDeviationAngle(
35+
@Nonnull
36+
Point point
37+
);
38+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// SPDX-FileCopyrightText: The openTCS Authors
2+
// SPDX-License-Identifier: MIT
3+
package org.opentcs.components.kernel;
4+
5+
import jakarta.annotation.Nonnull;
6+
import java.util.Optional;
7+
import org.opentcs.data.model.Vehicle;
8+
9+
/**
10+
* A factory for position deviation policies.
11+
*/
12+
public interface PositionDeviationPolicyFactory {
13+
14+
/**
15+
* Returns a policy instance for the given vehicle, or an empty optional if no such policy can be
16+
* provided for this vehicle.
17+
*
18+
* @param vehicle The vehicle.
19+
* @return A policy instance for the given vehicle, or an empty optional if no such policy can be
20+
* provided for this vehicle.
21+
*/
22+
Optional<PositionDeviationPolicy> createPolicyFor(
23+
@Nonnull
24+
Vehicle vehicle
25+
);
26+
}

opentcs-api-injection/src/main/java/org/opentcs/customizations/kernel/KernelInjectionModule.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.opentcs.components.kernel.OrderSequenceCleanupApproval;
1212
import org.opentcs.components.kernel.PeripheralJobCleanupApproval;
1313
import org.opentcs.components.kernel.PeripheralJobDispatcher;
14+
import org.opentcs.components.kernel.PositionDeviationPolicyFactory;
1415
import org.opentcs.components.kernel.Router;
1516
import org.opentcs.components.kernel.Scheduler;
1617
import org.opentcs.components.kernel.TransportOrderCleanupApproval;
@@ -101,6 +102,15 @@ protected Multibinder<VehicleCommAdapterFactory> vehicleCommAdaptersBinder() {
101102
return Multibinder.newSetBinder(binder(), VehicleCommAdapterFactory.class);
102103
}
103104

105+
/**
106+
* Returns a multibinder that can be used to register position deviation policy factories.
107+
*
108+
* @return The multibinder.
109+
*/
110+
protected Multibinder<PositionDeviationPolicyFactory> positionDeviationPolicyFactoryBinder() {
111+
return Multibinder.newSetBinder(binder(), PositionDeviationPolicyFactory.class);
112+
}
113+
104114
/**
105115
* Returns a multibinder that can be used to register vehicle data transformer factories.
106116
*

opentcs-documentation/src/docs/developers-guide/04_extending-kernel.adoc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,33 @@ include::{kernel-guiceSrc}/org/opentcs/kernel/DefaultKernelInjectionModule.java[
7272

7373
Finally, to select your transformer (factory) to be used for a specific vehicle, set a property on the vehicle element in the plant model with key `tcs:vehicleDataTransformer` to the value that your factory's `getName()` method provides.
7474

75+
=== Customizing allowed deviation for vehicle positions
76+
77+
When a vehicle reports its position not with a logical point name but as coordinates only, the openTCS kernel checks whether the reported position is within an allowed deviation from any known point in the plant model.
78+
The allowed deviation can be set globally for all vehicles at all points via the kernel configuration -- see the reference documentation for configuration parameters in the User's Guide.
79+
For more flexible and fine-grained control over the allowed deviation, you can integrate a custom implementation of the `PositionDeviationPolicy` and `PositionDeviationPolicyFactory` interfaces.
80+
To do so, follow these steps:
81+
82+
. Create a custom implementation of `PositionDeviationPolicy` that implements the logic for determining the allowed deviation for a given vehicle and point.
83+
It could e.g. read specific properties from the vehicle or point objects to determine the allowed deviation.
84+
. Create an implementation of `PositionDeviationPolicyFactory` that provides instances of your `PositionDeviationPolicy` implementation.
85+
It should return instances only for vehicles your factory is supposed to handle.
86+
. Register your factory implementation as a binding for `PositionDeviationPolicyFactory` in your `KernelInjectionModule` implementation.
87+
This would look like this:
88+
+
89+
[source, java]
90+
----
91+
@Override
92+
protected void configure() {
93+
positionDeviationPolicyFactoryBinder()
94+
.addBinding()
95+
.to(MyPositionDeviationPolicyFactory.class);
96+
}
97+
----
98+
99+
IMPORTANT: Avoid registering multiple factories that provide policies for the same vehicle.
100+
Which factory is used is undefined in that case.
101+
75102
=== Developing vehicle drivers
76103

77104
openTCS supports integration of custom vehicle drivers that implement vehicle-specific communication protocols and thus mediate between the kernel and the vehicle.

opentcs-documentation/src/docs/release-notes/changelog.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ This change log lists the most relevant changes for past releases in reverse chr
2222
** Allow order sequences to contain multiple types of transport orders.
2323
Instead of a single type, order sequences now define a set of order types.
2424
Additionally, transport orders whose type is included in this set of order types can be added to the order sequence.
25+
** Use new injectable component `PositionDeviationPolicy` to provide the allowed deviation for a vehicle at a point.
26+
This way, we can e.g. respect VDA5050 deviation properties for position resolution, too.
27+
** When resolving coordinates to a logical position, ensure that the closest of the matching points in the plant model is picked.
2528
** Add support for customizable window icons.
2629
For more information, please refer to the developer's guide.
2730
** Update web API specification and implementation to version 1.14.0:
@@ -32,6 +35,7 @@ This change log lists the most relevant changes for past releases in reverse chr
3235
** Actually add given properties to newly-created plant models' visual layouts.
3336
** Ensure failed transport orders in order sequences are skipped correctly.
3437
** Respect integration level for all updates of a vehicle's logical position.
38+
** When resolving coordinates to logical positions, properly treat orientation angles to be in degrees, not in radians.
3539
* Changes affecting developers:
3640
** Update JUnit to 6.0.2.
3741
** Update Mockito to 5.21.0.

opentcs-kernel/src/guiceConfig/java/org/opentcs/kernel/DefaultKernelInjectionModule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import org.opentcs.kernel.services.StandardVehicleService;
6565
import org.opentcs.kernel.vehicles.DefaultVehicleControllerPool;
6666
import org.opentcs.kernel.vehicles.LocalVehicleControllerPool;
67+
import org.opentcs.kernel.vehicles.PositionDeviationPolicyRegistry;
6768
import org.opentcs.kernel.vehicles.VehicleCommAdapterRegistry;
6869
import org.opentcs.kernel.vehicles.VehicleControllerComponentsFactory;
6970
import org.opentcs.kernel.vehicles.VehicleControllerFactory;
@@ -157,6 +158,9 @@ protected void configure() {
157158
vehicleDataTransformersBinder().addBinding().to(CoordinateSystemMapperFactory.class);
158159
// end::documentation_registerTransformerFactory[]
159160

161+
bind(PositionDeviationPolicyRegistry.class)
162+
.in(Singleton.class);
163+
160164
configureKernelStatesDependencies();
161165
configureKernelStarterDependencies();
162166
configureSslParameters();
@@ -168,6 +172,7 @@ protected void configure() {
168172
extensionsBinderOperating();
169173
vehicleCommAdaptersBinder();
170174
peripheralCommAdaptersBinder();
175+
positionDeviationPolicyFactoryBinder();
171176

172177
configureWatchdogExtension();
173178
}

opentcs-kernel/src/main/java/org/opentcs/kernel/vehicles/DefaultVehicleController.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public class DefaultVehicleController
177177
* @param configuration The configuration to use.
178178
* @param commandProcessingTracker Track processing of movement commands.
179179
* @param dataTransformerRegistry A registry for data transformer factories.
180-
* @param vehiclePositionResolver Resolves the vehicle precise position to an openTCS point.
180+
* @param positionDeviationPolicyRegistry A registry for position deviation policies.
181181
*/
182182
@Inject
183183
public DefaultVehicleController(
@@ -211,7 +211,7 @@ public DefaultVehicleController(
211211
@Nonnull
212212
VehicleDataTransformerRegistry dataTransformerRegistry,
213213
@Nonnull
214-
VehiclePositionResolver vehiclePositionResolver
214+
PositionDeviationPolicyRegistry positionDeviationPolicyRegistry
215215
) {
216216
this.vehicle = requireNonNull(vehicle, "vehicle");
217217
this.commAdapter = requireNonNull(adapter, "adapter");
@@ -237,8 +237,10 @@ public DefaultVehicleController(
237237
= dataTransformerRegistry
238238
.findFactoryFor(vehicle)
239239
.createIncomingPoseTransformer(vehicle);
240-
this.vehiclePositionResolver
241-
= requireNonNull(vehiclePositionResolver, "vehiclePositionResolver");
240+
requireNonNull(positionDeviationPolicyRegistry, "positionDeviationPolicyRegistry");
241+
this.vehiclePositionResolver = componentsFactory.createVehiclePositionResolver(
242+
positionDeviationPolicyRegistry.getPolicyForVehicle(vehicle)
243+
);
242244
}
243245

244246
@Override
@@ -962,7 +964,7 @@ private void mapPrecisePositionToLocalPosition(
962964
vehiclePositionResolver.resolveVehiclePosition(
963965
incomingPoseTransformer.apply(pose),
964966
(vehicle.getCurrentPosition() != null) ? vehicle.getCurrentPosition().getName() : null
965-
)
967+
).orElse(null)
966968
);
967969
}
968970

@@ -975,7 +977,10 @@ private void updateVehiclePose(
975977
vehicleService.updateVehiclePose(vehicle.getReference(), incomingPoseTransformer.apply(pose));
976978
}
977979

978-
private void setVehiclePosition(String position) {
980+
private void setVehiclePosition(
981+
@Nullable
982+
String position
983+
) {
979984
Vehicle currVehicle = vehicleService.fetch(Vehicle.class, vehicle.getReference()).orElseThrow();
980985

981986
boolean acceptPosition = switch (currVehicle.getIntegrationLevel()) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// SPDX-FileCopyrightText: The openTCS Authors
2+
// SPDX-License-Identifier: MIT
3+
package org.opentcs.kernel.vehicles;
4+
5+
import jakarta.annotation.Nonnull;
6+
import org.opentcs.components.kernel.PositionDeviationPolicy;
7+
import org.opentcs.data.model.Point;
8+
9+
/**
10+
* A position deviation policy with a fixed given deviation.
11+
*
12+
* @param distance The allowed deviation distance in millimeters.
13+
* @param angle The allowed deviation angle in degrees.
14+
*/
15+
public record FixedPositionDeviationPolicy(long distance, long angle)
16+
implements
17+
PositionDeviationPolicy {
18+
19+
@Override
20+
public long allowedDeviationDistance(
21+
@Nonnull
22+
Point point
23+
) {
24+
return distance;
25+
}
26+
27+
@Override
28+
public long allowedDeviationAngle(
29+
@Nonnull
30+
Point point
31+
) {
32+
return angle;
33+
}
34+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// SPDX-FileCopyrightText: The openTCS Authors
2+
// SPDX-License-Identifier: MIT
3+
package org.opentcs.kernel.vehicles;
4+
5+
import static java.util.Objects.requireNonNull;
6+
7+
import jakarta.annotation.Nonnull;
8+
import jakarta.inject.Inject;
9+
import java.util.Optional;
10+
import java.util.Set;
11+
import org.opentcs.components.kernel.PositionDeviationPolicy;
12+
import org.opentcs.components.kernel.PositionDeviationPolicyFactory;
13+
import org.opentcs.data.model.Vehicle;
14+
import org.slf4j.Logger;
15+
import org.slf4j.LoggerFactory;
16+
17+
/**
18+
* A registry for position deviation policy factories.
19+
*/
20+
public class PositionDeviationPolicyRegistry {
21+
/**
22+
* This class's Logger.
23+
*/
24+
private static final Logger LOG = LoggerFactory.getLogger(PositionDeviationPolicyRegistry.class);
25+
/**
26+
* The available factories.
27+
*/
28+
private final Set<PositionDeviationPolicyFactory> factories;
29+
/**
30+
* Our configuration.
31+
*/
32+
private final VehiclePositionResolverConfiguration configuration;
33+
34+
/**
35+
* Creates a new instance.
36+
*
37+
* @param positionDeviationPolicyFactories The available position factories.
38+
* @param configuration The configuration.
39+
*/
40+
@Inject
41+
public PositionDeviationPolicyRegistry(
42+
@Nonnull
43+
Set<PositionDeviationPolicyFactory> positionDeviationPolicyFactories,
44+
@Nonnull
45+
VehiclePositionResolverConfiguration configuration
46+
) {
47+
this.factories = requireNonNull(
48+
positionDeviationPolicyFactories, "positionDeviationPolicyFactories"
49+
);
50+
this.configuration = requireNonNull(configuration, "configuration");
51+
52+
for (PositionDeviationPolicyFactory factory : factories) {
53+
LOG.info("Registered position deviation policy factory: {}", factory.getClass().getName());
54+
}
55+
if (factories.isEmpty()) {
56+
LOG.info("No position deviation policy factories registered.");
57+
}
58+
}
59+
60+
/**
61+
* Returns a position deviation policy for the given vehicle.
62+
*
63+
* @param vehicle The vehicle.
64+
* @return A policy for the given vehicle.
65+
*/
66+
@Nonnull
67+
public PositionDeviationPolicy getPolicyForVehicle(
68+
@Nonnull
69+
Vehicle vehicle
70+
) {
71+
requireNonNull(vehicle, "vehicle");
72+
73+
Optional<PositionDeviationPolicy> result = factories.stream()
74+
.map(factory -> factory.createPolicyFor(vehicle))
75+
.filter(Optional::isPresent)
76+
.map(Optional::get)
77+
.findFirst();
78+
79+
if (result.isPresent()) {
80+
LOG.info(
81+
"Selecting position deviation policy '{}' for vehicle '{}'.",
82+
result.get().getClass().getName(),
83+
vehicle.getName()
84+
);
85+
return result.get();
86+
}
87+
88+
LOG.info(
89+
"Falling back to fixed deviation policy (distance={}, angle={}) for vehicle '{}'.",
90+
configuration.deviationXY(),
91+
configuration.deviationTheta(),
92+
vehicle.getName()
93+
);
94+
95+
return new FixedPositionDeviationPolicy(
96+
configuration.deviationXY(),
97+
configuration.deviationTheta()
98+
);
99+
}
100+
}

opentcs-kernel/src/main/java/org/opentcs/kernel/vehicles/VehicleControllerComponentsFactory.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: MIT
33
package org.opentcs.kernel.vehicles;
44

5+
import org.opentcs.components.kernel.PositionDeviationPolicy;
56
import org.opentcs.data.TCSObjectReference;
67
import org.opentcs.data.model.Vehicle;
78

@@ -17,4 +18,12 @@ public interface VehicleControllerComponentsFactory {
1718
* @return A new peripheral interactor.
1819
*/
1920
PeripheralInteractor createPeripheralInteractor(TCSObjectReference<Vehicle> vehicleRef);
21+
22+
/**
23+
* Creates a new {@link VehiclePositionResolver} instance.
24+
*
25+
* @param policy The position deviation policy to be used.
26+
* @return A new vehicle position resolver.
27+
*/
28+
VehiclePositionResolver createVehiclePositionResolver(PositionDeviationPolicy policy);
2029
}

0 commit comments

Comments
 (0)