Skip to content

Commit 8079328

Browse files
committed
Merge pull request #527 from JLLeitschuh/feat/rosNetworkPublishing
GRIP publish as a ROS Node
2 parents 6ef68aa + 86c69c6 commit 8079328

Some content is hidden

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

51 files changed

+1806
-410
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,6 @@ node_modules
8585
bower_components
8686

8787
#Generated files should be ignored as the are regenerated as a build step
88-
*/src/generated
88+
**/generated
89+
*/generated_tests
8990
/bin/

build.gradle

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@ def getGitCommit = { ->
2121
return COMMIT_HASH
2222
}
2323

24+
idea.project {
25+
ipr.withXml { provider ->
26+
def node = provider.asNode()
27+
def compilerConfig = node.component.find { it.'@name' == 'CompilerConfiguration'}
28+
compilerConfig.annotationProcessing[0].'@enabled' = 'true'
29+
// def ccfg = node.component.find { it.@name == 'CompilerConfiguration' }
30+
// ccfg.remove(ccfg.annotationProcessing)
31+
// ccfg.append(new NodeBuilder().annotationProcessing() {
32+
// profile(default: true, name: 'Default', enabled: true) {
33+
// processorPath(useClasspath: true)
34+
// }
35+
// })
36+
}
37+
}
38+
2439
/*
2540
* Gets the version name from the latest Git tag
2641
* http://ryanharter.com/blog/2013/07/30/automatic-versioning-with-git-and-gradle/
@@ -145,6 +160,9 @@ project(":core") {
145160
maven {
146161
url = "http://first.wpi.edu/FRC/roborio/maven/development"
147162
}
163+
maven {
164+
url = "https://github.com/WPIRoboticsProjects/rosjava_mvn_repo/raw/master"
165+
}
148166
}
149167
}
150168

@@ -159,11 +177,16 @@ project(":core") {
159177
compile group: 'com.thoughtworks.xstream', name: 'xstream', version: '1.4.8'
160178
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.4'
161179
compile group: 'com.google.guava', name: 'guava', version: '19.0'
180+
compile group: 'com.google.auto.value', name: 'auto-value', version: '1.1'
162181
// We use the no_aop version of Guice because the aop isn't avaiable in arm java
163182
// http://stackoverflow.com/a/15235190/3708426
164183
// https://github.com/google/guice/wiki/OptionalAOP
165184
compile group: 'com.google.inject', name: 'guice', version: '4.0', classifier: 'no_aop'
166185
compile group: 'com.google.inject.extensions', name: 'guice-assistedinject', version: '4.0'
186+
187+
// Network publishing dependencies
188+
compile group: 'org.ros.rosjava_core', name: 'rosjava', version: '[0.2,0.3)'
189+
compile group: 'org.ros.rosjava_messages', name: 'grip_msgs', version: '0.0.1'
167190
compile group: 'edu.wpi.first.wpilib.networktables.java', name: 'NetworkTables', version: '3.0.0-SNAPSHOT', classifier: 'desktop'
168191
compile group: 'edu.wpi.first.wpilib.networktables.java', name: 'NetworkTables', version: '3.0.0-SNAPSHOT', classifier: 'arm'
169192
}
@@ -232,8 +255,8 @@ project(":core") {
232255

233256
idea.module {
234257
sourceDirs += sourceSets.generated.java.srcDirs
258+
sourceDirs += file('generated')
235259
}
236-
// End IDE setup
237260
}
238261

239262
project(":ui") {

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
/**

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

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
import edu.wpi.grip.core.events.RenderEvent;
1414
import edu.wpi.grip.core.events.RunPipelineEvent;
1515
import edu.wpi.grip.core.events.StopPipelineEvent;
16+
import edu.wpi.grip.core.util.SinglePermitSemaphore;
1617
import edu.wpi.grip.core.util.service.AutoRestartingService;
1718
import edu.wpi.grip.core.util.service.LoggingListener;
1819
import edu.wpi.grip.core.util.service.RestartableService;
1920

2021
import javax.annotation.Nullable;
2122
import javax.inject.Inject;
2223
import java.util.concurrent.Executor;
23-
import java.util.concurrent.Semaphore;
2424
import java.util.concurrent.TimeUnit;
2525
import java.util.concurrent.TimeoutException;
2626
import java.util.function.Supplier;
@@ -37,7 +37,7 @@ public class PipelineRunner implements RestartableService {
3737
/**
3838
* This is used to flag that the pipeline needs to run because of an update
3939
*/
40-
private final Semaphore pipelineFlag = new Semaphore(0);
40+
private final SinglePermitSemaphore pipelineFlag = new SinglePermitSemaphore();
4141
private final Supplier<ImmutableList<Source>> sourceSupplier;
4242
private final Supplier<ImmutableList<Step>> stepSupplier;
4343
private final AutoRestartingService pipelineService;
@@ -62,13 +62,7 @@ public class PipelineRunner implements RestartableService {
6262
protected void runOneIteration() throws InterruptedException {
6363
if (!super.isRunning()) return;
6464

65-
// Acquire the first this one should permit if there is at least one permit
6665
pipelineFlag.acquire();
67-
// Acquire the rest of the permits from the flag
68-
// Every time release is called another permit is added.
69-
// We need to clean up any old permits that we may have been given.
70-
pipelineFlag.acquire(
71-
Math.max(0, pipelineFlag.availablePermits()));
7266

7367
if (!super.isRunning()) return;
7468
runPipeline(super::isRunning);
Lines changed: 84 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,99 @@
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.MapNetworkPublisherFactory;
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.NTPublishAnnotatedOperation;
16+
import edu.wpi.grip.core.operations.network.ros.JavaToMessageConverter;
17+
import edu.wpi.grip.core.operations.network.ros.ROSNetworkPublisherFactory;
18+
import edu.wpi.grip.core.operations.network.ros.ROSPublishOperation;
919
import edu.wpi.grip.core.operations.opencv.MatFieldAccessor;
1020
import edu.wpi.grip.core.operations.opencv.MinMaxLoc;
1121
import edu.wpi.grip.core.operations.opencv.NewPointOperation;
1222
import edu.wpi.grip.core.operations.opencv.NewSizeOperation;
1323

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

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

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

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()));
35+
@Inject
36+
Operations(EventBus eventBus, @Named("ntManager") MapNetworkPublisherFactory ntPublisherFactory, @Named("rosManager") ROSNetworkPublisherFactory rosPublishFactory) {
37+
this.eventBus = checkNotNull(eventBus, "EventBus cannot be null");
38+
checkNotNull(ntPublisherFactory, "ntPublisherFactory cannot be null");
39+
checkNotNull(rosPublishFactory, "rosPublishFactory cannot be null");
40+
this.operations = ImmutableList.of(
41+
ResizeOperation::new,
42+
BlurOperation::new,
43+
DesaturateOperation::new,
44+
RGBThresholdOperation::new,
45+
HSVThresholdOperation::new,
46+
HSLThresholdOperation::new,
47+
FindContoursOperation::new,
48+
FilterContoursOperation::new,
49+
ConvexHullsOperation::new,
50+
FindBlobsOperation::new,
51+
FindLinesOperation::new,
52+
FilterLinesOperation::new,
53+
MaskOperation::new,
54+
MinMaxLoc::new,
55+
MatFieldAccessor::new,
56+
NewPointOperation::new,
57+
NewSizeOperation::new,
58+
() -> new NTPublishAnnotatedOperation<Number, NumberPublishable, Double>(ntPublisherFactory, NumberPublishable::new) {
59+
},
60+
() -> new NTPublishAnnotatedOperation<Boolean, BooleanPublishable, Boolean>(ntPublisherFactory, BooleanPublishable::new) {
61+
},
62+
() -> new NTPublishAnnotatedOperation<Point, Vector2D, Double>(ntPublisherFactory, Vector2D::new) {
63+
},
64+
() -> new NTPublishAnnotatedOperation<Size, Vector2D, Double>(ntPublisherFactory, Vector2D::new) {
65+
},
66+
() -> new NTPublishAnnotatedOperation<ContoursReport, ContoursReport, double[]>(ntPublisherFactory) {
67+
},
68+
() -> new NTPublishAnnotatedOperation<BlobsReport, BlobsReport, double[]>(ntPublisherFactory) {
69+
},
70+
() -> new NTPublishAnnotatedOperation<LinesReport, LinesReport, double[]>(ntPublisherFactory) {
71+
},
72+
() -> new ROSPublishOperation<Number>(rosPublishFactory, JavaToMessageConverter.FLOAT) {
73+
},
74+
() -> new ROSPublishOperation<Boolean>(rosPublishFactory, JavaToMessageConverter.BOOL) {
75+
},
76+
// () -> new ROSPublishOperation<Point, Vector2D, Double>(rosManager, Vector2D::new) {
77+
// },
78+
// () -> new ROSPublishOperation<Size, Vector2D, Double>(rosManager, Vector2D::new) {
79+
// },
80+
() -> new ROSPublishOperation<ContoursReport>(rosPublishFactory, JavaToMessageConverter.CONTOURS) {
81+
},
82+
() -> new ROSPublishOperation<BlobsReport>(rosPublishFactory, JavaToMessageConverter.BLOBS) {
83+
},
84+
() -> new ROSPublishOperation<LinesReport>(rosPublishFactory, JavaToMessageConverter.LINES) {
85+
},
86+
PublishVideoOperation::new,
87+
DistanceTransformOperation::new,
88+
NormalizeOperation::new,
89+
WatershedOperation::new
90+
);
91+
}
92+
93+
public void addOperations() {
94+
operations.stream()
95+
.map(s -> s.get())
96+
.map(OperationAddedEvent::new)
97+
.forEach(eventBus::post);
4998
}
5099
}

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++) {

0 commit comments

Comments
 (0)