Provide a generic way to receive zmq updates for lidar and slam.
This commit is contained in:
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_9" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 9.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 9.8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
<activity android:name=".SLAM.SlamController"></activity>
|
<activity android:name=".SLAM.SlamController"></activity>
|
||||||
<activity android:name=".LidarTrackingController" />
|
<activity android:name=".LIDAR.LidarTrackingController" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".SettingsActivity"
|
android:name=".SettingsActivity"
|
||||||
android:label="@string/title_activity_settings"
|
android:label="@string/title_activity_settings"
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.example.carcontroller;
|
package com.example.carcontroller.LIDAR;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import com.example.carcontroller.R;
|
||||||
|
|
||||||
public class LidarTrackingController extends AppCompatActivity {
|
public class LidarTrackingController extends AppCompatActivity {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.carcontroller;
|
package com.example.carcontroller.LIDAR;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@@ -8,6 +8,8 @@ import android.view.MotionEvent;
|
|||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
|
|
||||||
|
import com.example.carcontroller.PersonTrackingGrpc;
|
||||||
|
|
||||||
public class LidarView extends SurfaceView implements Runnable {
|
public class LidarView extends SurfaceView implements Runnable {
|
||||||
|
|
||||||
private boolean running;
|
private boolean running;
|
||||||
@@ -1,22 +1,17 @@
|
|||||||
package com.example.carcontroller;
|
package com.example.carcontroller;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.appcompat.widget.Toolbar;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.SeekBar;
|
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
|
||||||
|
import com.example.carcontroller.LIDAR.LidarTrackingController;
|
||||||
import com.example.carcontroller.SLAM.SlamController;
|
import com.example.carcontroller.SLAM.SlamController;
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
|
|
||||||
import io.grpc.stub.StreamObserver;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
package com.example.carcontroller.SLAM;
|
|
||||||
|
|
||||||
import com.example.carcontroller.SlamLocation;
|
|
||||||
import com.example.carcontroller.SlamScan;
|
|
||||||
import com.google.protobuf.ByteString;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public abstract class SlamUpdater implements Runnable {
|
|
||||||
|
|
||||||
private Set<MapChangedListener> listeners;
|
|
||||||
|
|
||||||
public SlamUpdater() {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void init() {
|
|
||||||
listeners = new HashSet<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addMapChangedListener(MapChangedListener listener) {
|
|
||||||
listeners.add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void fireMapChanged(SlamScan scan) {
|
|
||||||
listeners.forEach(listener -> listener.mapChanged(scan.getMap(), scan.getLocation()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void stop();
|
|
||||||
|
|
||||||
public interface MapChangedListener {
|
|
||||||
void mapChanged(ByteString map, SlamLocation location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,21 +16,25 @@ import com.example.carcontroller.Empty;
|
|||||||
import com.example.carcontroller.SlamControlGrpc;
|
import com.example.carcontroller.SlamControlGrpc;
|
||||||
import com.example.carcontroller.SlamDetails;
|
import com.example.carcontroller.SlamDetails;
|
||||||
import com.example.carcontroller.SlamLocation;
|
import com.example.carcontroller.SlamLocation;
|
||||||
|
import com.example.carcontroller.SlamScan;
|
||||||
|
import com.example.carcontroller.Updaters.AbstractUpdater;
|
||||||
|
import com.example.carcontroller.Updaters.ZmqUpdater;
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
import io.grpc.ManagedChannel;
|
import io.grpc.ManagedChannel;
|
||||||
import io.grpc.ManagedChannelBuilder;
|
import io.grpc.ManagedChannelBuilder;
|
||||||
import io.grpc.stub.StreamObserver;
|
import io.grpc.stub.StreamObserver;
|
||||||
|
|
||||||
public class SlamView extends SurfaceView implements SlamUpdater.MapChangedListener {
|
public class SlamView extends SurfaceView implements AbstractUpdater.MapChangedListener<SlamScan> {
|
||||||
|
|
||||||
private SlamUpdater slam;
|
private static final String SLAM_TOPIC = "slam_map";
|
||||||
|
|
||||||
|
private AbstractUpdater<SlamScan> slam;
|
||||||
private Thread mapThread;
|
private Thread mapThread;
|
||||||
private Context context;
|
private Context context;
|
||||||
private SurfaceHolder surfaceHolder;
|
private SurfaceHolder surfaceHolder;
|
||||||
private Paint paint;
|
private Paint paint;
|
||||||
private SlamControlGrpc.SlamControlStub stub;
|
private SlamControlGrpc.SlamControlStub stub;
|
||||||
private ManagedChannel channel;
|
|
||||||
private int mapSizePixels;
|
private int mapSizePixels;
|
||||||
private int mapSizeMeters;
|
private int mapSizeMeters;
|
||||||
private String port;
|
private String port;
|
||||||
@@ -60,15 +64,14 @@ public class SlamView extends SurfaceView implements SlamUpdater.MapChangedListe
|
|||||||
String gRPCPort = prefs.getString("port", "50051");
|
String gRPCPort = prefs.getString("port", "50051");
|
||||||
mapSizePixels = Integer.parseInt(prefs.getString("MAPSIZEPIXELS", "540"));
|
mapSizePixels = Integer.parseInt(prefs.getString("MAPSIZEPIXELS", "540"));
|
||||||
mapSizeMeters = Integer.parseInt(prefs.getString("MAPSIZEMETRES", "10"));
|
mapSizeMeters = Integer.parseInt(prefs.getString("MAPSIZEMETRES", "10"));
|
||||||
slam = new ZmqSlamUpdater(host, port);
|
slam = new ZmqUpdater<>(SlamScan.getDefaultInstance().getParserForType(), SLAM_TOPIC, host, port);
|
||||||
slam.addMapChangedListener(this);
|
slam.addMapChangedListener(this);
|
||||||
surfaceHolder = getHolder();
|
surfaceHolder = getHolder();
|
||||||
paint = new Paint();
|
paint = new Paint();
|
||||||
paint.setColor(Color.BLUE);
|
paint.setColor(Color.BLUE);
|
||||||
mapThread = new Thread(slam);
|
mapThread = new Thread(slam);
|
||||||
channel = ManagedChannelBuilder.forAddress(host, Integer.parseInt(gRPCPort)).usePlaintext().build();
|
ManagedChannel channel = ManagedChannelBuilder.forAddress(host, Integer.parseInt(gRPCPort)).usePlaintext().build();
|
||||||
stub = SlamControlGrpc.newStub(channel);
|
stub = SlamControlGrpc.newStub(channel);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,12 +109,15 @@ public class SlamView extends SurfaceView implements SlamUpdater.MapChangedListe
|
|||||||
try {
|
try {
|
||||||
mapThread.join();
|
mapThread.join();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapChanged(ByteString map, SlamLocation location) {
|
public void mapChanged(SlamScan scan) {
|
||||||
|
updateView(scan.getMap(), scan.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateView(ByteString map, SlamLocation location) {
|
||||||
if (surfaceHolder.getSurface().isValid()) {
|
if (surfaceHolder.getSurface().isValid()) {
|
||||||
Canvas canvas = surfaceHolder.lockCanvas();
|
Canvas canvas = surfaceHolder.lockCanvas();
|
||||||
canvas.save();
|
canvas.save();
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.example.carcontroller.Updaters;
|
||||||
|
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
import com.google.protobuf.MessageLite;
|
||||||
|
import com.google.protobuf.Parser;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an abstract way to receive updates from a remote host (i.e. the rc car).
|
||||||
|
* Subclasses of this implement the approriate connection mechanisms to continuously receive
|
||||||
|
* new updates of messages.
|
||||||
|
* Specifically, protobuf serialisation support is provided
|
||||||
|
*
|
||||||
|
* @param <T> The message type that will continuously be received
|
||||||
|
*/
|
||||||
|
public abstract class AbstractUpdater<T extends MessageLite> implements Runnable {
|
||||||
|
|
||||||
|
private Set<MapChangedListener<T>> listeners;
|
||||||
|
private Parser<T> parser;
|
||||||
|
|
||||||
|
public AbstractUpdater(Parser<T> parser) {
|
||||||
|
this.parser = parser;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void init() {
|
||||||
|
listeners = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMapChangedListener(MapChangedListener<T> listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void fireMapChanged(T scan) {
|
||||||
|
listeners.forEach(listener -> listener.mapChanged(scan));
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void stop();
|
||||||
|
|
||||||
|
public interface MapChangedListener<T extends MessageLite> {
|
||||||
|
void mapChanged(T points);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected T parseMessage(byte[] messageBytes) throws InvalidProtocolBufferException {
|
||||||
|
return parser.parseFrom(messageBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package com.example.carcontroller.SLAM;
|
package com.example.carcontroller.Updaters;
|
||||||
|
|
||||||
import com.example.carcontroller.SlamScan;
|
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
import com.google.protobuf.MessageLite;
|
||||||
|
import com.google.protobuf.Parser;
|
||||||
|
|
||||||
import org.zeromq.SocketType;
|
import org.zeromq.SocketType;
|
||||||
import org.zeromq.ZContext;
|
import org.zeromq.ZContext;
|
||||||
@@ -10,20 +11,21 @@ import org.zeromq.ZMQ;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects to Pi and retrieves updates of the SLAM map,
|
* Provides a way to easily deal with zeromq sub sockets that use protobuf
|
||||||
* notifying listeners of changes to the map when they arrive.
|
*
|
||||||
* Uses 0MQ for the transport.
|
* @param <T>
|
||||||
*/
|
*/
|
||||||
public class ZmqSlamUpdater extends SlamUpdater {
|
public class ZmqUpdater<T extends MessageLite> extends AbstractUpdater<T> {
|
||||||
|
|
||||||
private ZContext context;
|
private ZContext context;
|
||||||
private String host;
|
private String host;
|
||||||
private String port;
|
private String port;
|
||||||
private boolean running = false;
|
private boolean running = false;
|
||||||
private static final byte[] SLAM_SUBSCRIPTION = "slam_map".getBytes();
|
private final byte[] SUBSCRIPTION;
|
||||||
|
|
||||||
public ZmqSlamUpdater(String host, String port) {
|
public ZmqUpdater(Parser<T> parser, String topic, String host, String port) {
|
||||||
super();
|
super(parser);
|
||||||
|
this.SUBSCRIPTION = topic.getBytes();
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
init();
|
init();
|
||||||
@@ -42,12 +44,12 @@ public class ZmqSlamUpdater extends SlamUpdater {
|
|||||||
// Receive map from zmq and update appropriately.
|
// Receive map from zmq and update appropriately.
|
||||||
try (ZMQ.Socket socket = context.createSocket(SocketType.SUB)) {
|
try (ZMQ.Socket socket = context.createSocket(SocketType.SUB)) {
|
||||||
socket.connect("tcp://" + host + ":" + port);
|
socket.connect("tcp://" + host + ":" + port);
|
||||||
socket.subscribe(SLAM_SUBSCRIPTION);
|
socket.subscribe(SUBSCRIPTION);
|
||||||
while (running) {
|
while (running) {
|
||||||
byte[] map = socket.recv();
|
byte[] map = socket.recv();
|
||||||
// Don't want to do the event when we just receive the header.
|
// Don't want to do the event when we just receive the header.
|
||||||
if (!Arrays.equals(map, SLAM_SUBSCRIPTION)) {
|
if (!Arrays.equals(map, SUBSCRIPTION)) {
|
||||||
fireMapChanged(SlamScan.parseFrom(map));
|
fireMapChanged(parseMessage(map));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (InvalidProtocolBufferException e) {
|
} catch (InvalidProtocolBufferException e) {
|
||||||
@@ -4,9 +4,9 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".LidarTrackingController">
|
tools:context=".LIDAR.LidarTrackingController">
|
||||||
|
|
||||||
<com.example.carcontroller.LidarView
|
<com.example.carcontroller.LIDAR.LidarView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:id="@+id/lidarMap"/>
|
android:id="@+id/lidarMap"/>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".LidarTrackingController">
|
tools:context=".LIDAR.LidarTrackingController">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
Reference in New Issue
Block a user