Skip to content

Commit da02353

Browse files
committed
Adds ROS Publish Operations
Allows for publishing the same values over ROS as can be published to NetworkTables
1 parent 6ef68aa commit da02353

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1593
-400
lines changed

build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ project(":core") {
145145
maven {
146146
url = "http://first.wpi.edu/FRC/roborio/maven/development"
147147
}
148+
maven {
149+
url = "https://github.com/rosjava/rosjava_mvn_repo/raw/master"
150+
}
148151
}
149152
}
150153

@@ -164,6 +167,9 @@ project(":core") {
164167
// https://github.com/google/guice/wiki/OptionalAOP
165168
compile group: 'com.google.inject', name: 'guice', version: '4.0', classifier: 'no_aop'
166169
compile group: 'com.google.inject.extensions', name: 'guice-assistedinject', version: '4.0'
170+
171+
// Network publishing dependencies
172+
compile group: 'org.ros.rosjava_core', name: 'rosjava', version: '[0.2,0.3)'
167173
compile group: 'edu.wpi.first.wpilib.networktables.java', name: 'NetworkTables', version: '3.0.0-SNAPSHOT', classifier: 'desktop'
168174
compile group: 'edu.wpi.first.wpilib.networktables.java', name: 'NetworkTables', version: '3.0.0-SNAPSHOT', classifier: 'arm'
169175
}

core/src/main/java/edu/wpi/grip/core/GRIPCoreModule.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import com.google.inject.spi.TypeEncounter;
1111
import com.google.inject.spi.TypeListener;
1212
import edu.wpi.grip.core.events.UnexpectedThrowableEvent;
13-
import edu.wpi.grip.core.operations.networktables.NTManager;
1413
import edu.wpi.grip.core.serialization.Project;
1514
import edu.wpi.grip.core.sources.CameraSource;
1615
import edu.wpi.grip.core.sources.ImageFileSource;
@@ -101,8 +100,6 @@ public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
101100

102101
bind(EventBus.class).toInstance(eventBus);
103102

104-
bind(NTManager.class).asEagerSingleton();
105-
106103
install(new FactoryModuleBuilder().build(new TypeLiteral<Connection.Factory<Object>>() {
107104
}));
108105

core/src/main/java/edu/wpi/grip/core/Main.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import edu.wpi.grip.core.events.ExceptionClearedEvent;
88
import edu.wpi.grip.core.events.ExceptionEvent;
99
import edu.wpi.grip.core.operations.Operations;
10+
import edu.wpi.grip.core.operations.network.GRIPNetworkModule;
1011
import edu.wpi.grip.core.serialization.Project;
1112
import edu.wpi.grip.generated.CVOperations;
1213

@@ -24,11 +25,12 @@ public class Main {
2425
@Inject private Project project;
2526
@Inject private PipelineRunner pipelineRunner;
2627
@Inject private EventBus eventBus;
28+
@Inject private Operations operations;
2729
@Inject private Logger logger;
2830

2931
@SuppressWarnings("PMD.SystemPrintln")
3032
public static void main(String[] args) throws IOException, InterruptedException {
31-
final Injector injector = Guice.createInjector(new GRIPCoreModule());
33+
final Injector injector = Guice.createInjector(new GRIPCoreModule(), new GRIPNetworkModule());
3234
injector.getInstance(Main.class).start(args);
3335
}
3436

@@ -41,7 +43,7 @@ public void start(String[] args) throws IOException, InterruptedException {
4143
logger.log(Level.INFO, "Loading file " + args[0]);
4244
}
4345

44-
Operations.addOperations(eventBus);
46+
operations.addOperations();
4547
CVOperations.addOperations(eventBus);
4648

4749
final String projectPath = args[0];

core/src/main/java/edu/wpi/grip/core/Operation.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package edu.wpi.grip.core;
22

3+
import com.google.common.collect.ImmutableSet;
34
import com.google.common.eventbus.EventBus;
45

56
import java.io.InputStream;
@@ -24,6 +25,14 @@ enum Category {
2425
*/
2526
String getName();
2627

28+
/**
29+
* @return Any old unique user-facing names of the operation. This is used to preserve compatibility with
30+
* old versions of GRIP if the operation name changes.
31+
*/
32+
default ImmutableSet<String> getAliases() {
33+
return ImmutableSet.of();
34+
}
35+
2736

2837
/**
2938
* @return A description of the operation.

core/src/main/java/edu/wpi/grip/core/Palette.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.Map;
1212
import java.util.Optional;
1313

14+
import static com.google.common.base.Preconditions.checkArgument;
1415
import static com.google.common.base.Preconditions.checkNotNull;
1516

1617
/**
@@ -31,7 +32,21 @@ public class Palette {
3132
@Subscribe
3233
public void onOperationAdded(OperationAddedEvent event) {
3334
final Operation operation = event.getOperation();
34-
this.operations.put(operation.getName(), operation);
35+
map(operation.getName(), operation);
36+
for(String alias : operation.getAliases()) {
37+
map(alias, operation);
38+
}
39+
}
40+
41+
/**
42+
* Maps the key to the given operation
43+
* @param key The key the operation should be mapped to
44+
* @param operation The operation to map the key to
45+
* @throws IllegalArgumentException if the key is already in the {@link #operations} map.
46+
*/
47+
private void map(String key, Operation operation) {
48+
checkArgument(!operations.containsKey(key), "Operation name or alias already exists: " + key);
49+
operations.put(key, operation);
3550
}
3651

3752
/**
Lines changed: 82 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,97 @@
11
package edu.wpi.grip.core.operations;
22

3+
import com.google.common.collect.ImmutableList;
34
import com.google.common.eventbus.EventBus;
5+
import com.google.inject.Inject;
6+
import com.google.inject.Singleton;
7+
import com.google.inject.name.Named;
8+
import edu.wpi.grip.core.Operation;
49
import edu.wpi.grip.core.events.OperationAddedEvent;
510
import edu.wpi.grip.core.operations.composite.*;
6-
import edu.wpi.grip.core.operations.networktables.NTNumber;
7-
import edu.wpi.grip.core.operations.networktables.NTPublishOperation;
8-
import edu.wpi.grip.core.operations.networktables.NTVector2D;
11+
import edu.wpi.grip.core.operations.network.BooleanPublishable;
12+
import edu.wpi.grip.core.operations.network.Manager;
13+
import edu.wpi.grip.core.operations.network.NumberPublishable;
14+
import edu.wpi.grip.core.operations.network.Vector2D;
15+
import edu.wpi.grip.core.operations.network.networktables.NTKeyValuePublishOperation;
16+
import edu.wpi.grip.core.operations.network.ros.ROSKeyValuePublishOperation;
917
import edu.wpi.grip.core.operations.opencv.MatFieldAccessor;
1018
import edu.wpi.grip.core.operations.opencv.MinMaxLoc;
1119
import edu.wpi.grip.core.operations.opencv.NewPointOperation;
1220
import edu.wpi.grip.core.operations.opencv.NewSizeOperation;
1321

14-
import static org.bytedeco.javacpp.opencv_core.*;
22+
import java.util.function.Supplier;
1523

16-
public final class Operations {
24+
import static com.google.common.base.Preconditions.checkNotNull;
25+
import static org.bytedeco.javacpp.opencv_core.Point;
26+
import static org.bytedeco.javacpp.opencv_core.Size;
1727

18-
private Operations() { /* no op */}
28+
@Singleton
29+
public class Operations {
30+
private final EventBus eventBus;
31+
private final ImmutableList<Supplier<Operation>> operations;
1932

20-
public static void addOperations(EventBus eventBus) {
21-
// Add the default built-in operations to the palette
22-
eventBus.post(new OperationAddedEvent(new ResizeOperation()));
23-
eventBus.post(new OperationAddedEvent(new BlurOperation()));
24-
eventBus.post(new OperationAddedEvent(new DesaturateOperation()));
25-
eventBus.post(new OperationAddedEvent(new RGBThresholdOperation()));
26-
eventBus.post(new OperationAddedEvent(new HSVThresholdOperation()));
27-
eventBus.post(new OperationAddedEvent(new HSLThresholdOperation()));
28-
eventBus.post(new OperationAddedEvent(new FindContoursOperation()));
29-
eventBus.post(new OperationAddedEvent(new FilterContoursOperation()));
30-
eventBus.post(new OperationAddedEvent(new ConvexHullsOperation()));
31-
eventBus.post(new OperationAddedEvent(new FindBlobsOperation()));
32-
eventBus.post(new OperationAddedEvent(new FindLinesOperation()));
33-
eventBus.post(new OperationAddedEvent(new FilterLinesOperation()));
34-
eventBus.post(new OperationAddedEvent(new MaskOperation()));
35-
eventBus.post(new OperationAddedEvent(new MinMaxLoc()));
36-
eventBus.post(new OperationAddedEvent(new MatFieldAccessor()));
37-
eventBus.post(new OperationAddedEvent(new NewPointOperation()));
38-
eventBus.post(new OperationAddedEvent(new NewSizeOperation()));
39-
eventBus.post(new OperationAddedEvent(new NTPublishOperation<>(Number.class, NTNumber.class, NTNumber::new)));
40-
eventBus.post(new OperationAddedEvent(new NTPublishOperation<>(Point.class, NTVector2D.class, NTVector2D::new)));
41-
eventBus.post(new OperationAddedEvent(new NTPublishOperation<>(Size.class, NTVector2D.class, NTVector2D::new)));
42-
eventBus.post(new OperationAddedEvent(new NTPublishOperation<>(ContoursReport.class)));
43-
eventBus.post(new OperationAddedEvent(new NTPublishOperation<>(BlobsReport.class)));
44-
eventBus.post(new OperationAddedEvent(new NTPublishOperation<>(LinesReport.class)));
45-
eventBus.post(new OperationAddedEvent(new PublishVideoOperation()));
46-
eventBus.post(new OperationAddedEvent(new DistanceTransformOperation()));
47-
eventBus.post(new OperationAddedEvent(new NormalizeOperation()));
48-
eventBus.post(new OperationAddedEvent(new WatershedOperation()));
33+
@Inject
34+
Operations(EventBus eventBus, @Named("ntManager") Manager ntManager, @Named("rosManager") Manager rosManager) {
35+
this.eventBus = checkNotNull(eventBus, "EventBus cannot be null");
36+
checkNotNull(ntManager, "ntManager cannot be null");
37+
checkNotNull(rosManager, "rosManager cannot be null");
38+
this.operations = ImmutableList.of(
39+
ResizeOperation::new,
40+
BlurOperation::new,
41+
DesaturateOperation::new,
42+
RGBThresholdOperation::new,
43+
HSVThresholdOperation::new,
44+
HSLThresholdOperation::new,
45+
FindContoursOperation::new,
46+
FilterContoursOperation::new,
47+
ConvexHullsOperation::new,
48+
FindBlobsOperation::new,
49+
FindLinesOperation::new,
50+
FilterLinesOperation::new,
51+
MaskOperation::new,
52+
MinMaxLoc::new,
53+
MatFieldAccessor::new,
54+
NewPointOperation::new,
55+
NewSizeOperation::new,
56+
() -> new NTKeyValuePublishOperation<Number, NumberPublishable, Number>(ntManager, NumberPublishable::new) {
57+
},
58+
() -> new NTKeyValuePublishOperation<Boolean, BooleanPublishable, Boolean>(ntManager, BooleanPublishable::new) {
59+
},
60+
() -> new NTKeyValuePublishOperation<Point, Vector2D, Double>(ntManager, Vector2D::new) {
61+
},
62+
() -> new NTKeyValuePublishOperation<Size, Vector2D, Double>(ntManager, Vector2D::new) {
63+
},
64+
() -> new NTKeyValuePublishOperation<ContoursReport, ContoursReport, double[]>(ntManager) {
65+
},
66+
() -> new NTKeyValuePublishOperation<BlobsReport, BlobsReport, double[]>(ntManager) {
67+
},
68+
() -> new NTKeyValuePublishOperation<LinesReport, LinesReport, double[]>(ntManager) {
69+
},
70+
() -> new ROSKeyValuePublishOperation<Number, NumberPublishable, Number>(ntManager, NumberPublishable::new) {
71+
},
72+
() -> new ROSKeyValuePublishOperation<Boolean, BooleanPublishable, Boolean>(ntManager, BooleanPublishable::new) {
73+
},
74+
() -> new ROSKeyValuePublishOperation<Point, Vector2D, Double>(ntManager, Vector2D::new) {
75+
},
76+
() -> new ROSKeyValuePublishOperation<Size, Vector2D, Double>(ntManager, Vector2D::new) {
77+
},
78+
() -> new ROSKeyValuePublishOperation<ContoursReport, ContoursReport, double[]>(ntManager) {
79+
},
80+
() -> new ROSKeyValuePublishOperation<BlobsReport, BlobsReport, double[]>(ntManager) {
81+
},
82+
() -> new ROSKeyValuePublishOperation<LinesReport, LinesReport, double[]>(ntManager) {
83+
},
84+
PublishVideoOperation::new,
85+
DistanceTransformOperation::new,
86+
NormalizeOperation::new,
87+
WatershedOperation::new
88+
);
89+
}
90+
91+
public void addOperations() {
92+
operations.stream()
93+
.map(s -> s.get())
94+
.map(OperationAddedEvent::new)
95+
.forEach(eventBus::post);
4996
}
5097
}

core/src/main/java/edu/wpi/grip/core/operations/composite/BlobsReport.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import com.google.common.base.MoreObjects;
44
import edu.wpi.grip.core.NoSocketTypeLabel;
5-
import edu.wpi.grip.core.operations.networktables.NTPublishable;
6-
import edu.wpi.grip.core.operations.networktables.NTValue;
5+
import edu.wpi.grip.core.operations.network.PublishValue;
6+
import edu.wpi.grip.core.operations.network.Publishable;
77

88
import java.util.Collections;
99
import java.util.List;
@@ -14,7 +14,7 @@
1414
* This class is used as the output of operations that detect blobs in an image
1515
*/
1616
@NoSocketTypeLabel
17-
public class BlobsReport implements NTPublishable {
17+
public class BlobsReport implements Publishable {
1818
private final Mat input;
1919
private final List<Blob> blobs;
2020

@@ -60,7 +60,7 @@ public Mat getInput() {
6060
return this.input;
6161
}
6262

63-
@NTValue(key = "x", weight = 0)
63+
@PublishValue(key = "x", weight = 0)
6464
public double[] getX() {
6565
final double[] x = new double[blobs.size()];
6666
for (int i = 0; i < blobs.size(); i++) {
@@ -69,7 +69,7 @@ public double[] getX() {
6969
return x;
7070
}
7171

72-
@NTValue(key = "y", weight = 1)
72+
@PublishValue(key = "y", weight = 1)
7373
public double[] getY() {
7474
final double[] y = new double[blobs.size()];
7575
for (int i = 0; i < blobs.size(); i++) {
@@ -78,7 +78,7 @@ public double[] getY() {
7878
return y;
7979
}
8080

81-
@NTValue(key = "size", weight = 2)
81+
@PublishValue(key = "size", weight = 2)
8282
public double[] getSize() {
8383
final double[] sizes = new double[blobs.size()];
8484
for (int i = 0; i < blobs.size(); i++) {

core/src/main/java/edu/wpi/grip/core/operations/composite/ContoursReport.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package edu.wpi.grip.core.operations.composite;
22

33
import edu.wpi.grip.core.NoSocketTypeLabel;
4-
import edu.wpi.grip.core.operations.networktables.NTPublishable;
5-
import edu.wpi.grip.core.operations.networktables.NTValue;
4+
import edu.wpi.grip.core.operations.network.Publishable;
5+
import edu.wpi.grip.core.operations.network.PublishValue;
66

77
import java.util.Optional;
88

@@ -15,7 +15,7 @@
1515
* points.
1616
*/
1717
@NoSocketTypeLabel
18-
public final class ContoursReport implements NTPublishable {
18+
public final class ContoursReport implements Publishable {
1919
private final int rows, cols;
2020
private final MatVector contours;
2121
private Optional<Rect[]> boundingBoxes = Optional.empty();
@@ -63,7 +63,7 @@ private synchronized Rect[] computeBoundingBoxes() {
6363
return boundingBoxes.get();
6464
}
6565

66-
@NTValue(key = "area", weight = 0)
66+
@PublishValue(key = "area", weight = 0)
6767
public double[] getArea() {
6868
final double[] areas = new double[(int) contours.size()];
6969
for (int i = 0; i < contours.size(); i++) {
@@ -72,7 +72,7 @@ public double[] getArea() {
7272
return areas;
7373
}
7474

75-
@NTValue(key = "centerX", weight = 1)
75+
@PublishValue(key = "centerX", weight = 1)
7676
public double[] getCenterX() {
7777
final double[] centers = new double[(int) contours.size()];
7878
final Rect[] boundingBoxes = computeBoundingBoxes();
@@ -82,7 +82,7 @@ public double[] getCenterX() {
8282
return centers;
8383
}
8484

85-
@NTValue(key = "centerY", weight = 2)
85+
@PublishValue(key = "centerY", weight = 2)
8686
public double[] getCenterY() {
8787
final double[] centers = new double[(int) contours.size()];
8888
final Rect[] boundingBoxes = computeBoundingBoxes();
@@ -92,7 +92,7 @@ public double[] getCenterY() {
9292
return centers;
9393
}
9494

95-
@NTValue(key = "width", weight = 3)
95+
@PublishValue(key = "width", weight = 3)
9696
public synchronized double[] getWidth() {
9797
final double[] widths = new double[(int) contours.size()];
9898
final Rect[] boundingBoxes = computeBoundingBoxes();
@@ -102,7 +102,7 @@ public synchronized double[] getWidth() {
102102
return widths;
103103
}
104104

105-
@NTValue(key = "height", weight = 4)
105+
@PublishValue(key = "height", weight = 4)
106106
public synchronized double[] getHeights() {
107107
final double[] heights = new double[(int) contours.size()];
108108
final Rect[] boundingBoxes = computeBoundingBoxes();
@@ -112,7 +112,7 @@ public synchronized double[] getHeights() {
112112
return heights;
113113
}
114114

115-
@NTValue(key = "solidity", weight = 5)
115+
@PublishValue(key = "solidity", weight = 5)
116116
public synchronized double[] getSolidity() {
117117
final double[] solidities = new double[(int) contours.size()];
118118
Mat hull = new Mat();

0 commit comments

Comments
 (0)