Skip to content

Commit

Permalink
refactoring (no testing)
Browse files Browse the repository at this point in the history
  • Loading branch information
Iosu Sanchez committed May 12, 2021
1 parent 48e1ffc commit 0fb3d73
Show file tree
Hide file tree
Showing 13 changed files with 381 additions and 484 deletions.
Binary file modified app/release/app-release.apk
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,4 @@ public enum AppNavPhase {
WAITING_USER_INPUT,
REACHING_ORIGIN,
REACHING_DESTINATION
;

// private static AppNavPhase[] vals = values();
// public AppNavPhase next()
// {
// return vals[(this.ordinal()+1) % vals.length];
// }
}
2 changes: 2 additions & 0 deletions app/src/main/java/com/github/gidabotapp/domain/Floor.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ public enum Floor {
public int getFloorCode(){
return this.ordinal();
}

public String getRobotNameShort(){
return this.robot.getShortName();
}

public String getRobotNameLong(){
return this.robot.longName;
}
Expand Down
13 changes: 9 additions & 4 deletions app/src/main/java/com/github/gidabotapp/domain/MapPosition.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.github.gidabotapp.domain;


import android.util.Log;

import com.google.android.gms.maps.model.LatLng;

import java.util.Locale;
Expand Down Expand Up @@ -38,24 +36,31 @@ public double getZ() {
return z;
}

// Beste puntu batekiko distantzia euklidearra (karratua) kalkulatu
// ez da erroa erabiltzen -> distance square
// Returns square distance to given other Position
// Real distance is not meaningful, hence root is not computed
public double dSquare(MapPosition otherPos){
double dx = otherPos.x - this.x;
double dy = otherPos.y - this.y;
return dx * dx + dy * dy;
}

// Converts MapPoint to Latitude and Longitude
// Conversion depends on floor, so floor is given as an argument
public LatLng toLatLng(Floor floor){
// Map's Latitude and Longitude Bounds
final double[] LAT_BOUNDS = new double[]{-65 , +65};
final double[] LNG_BOUNDS = new double[]{-180, +180};

// Convert X coordinate to Longitude
double lng = rangeConversion(floor.getXBounds(), LNG_BOUNDS, x);
// Convert Y coordinate to Latitude
double lat = rangeConversion(floor.getYBounds(), LAT_BOUNDS, y);

return new LatLng(lat,lng);
}


// Converts old value from old_bounds range to new_bounds range
public double rangeConversion(double[] old_bounds, double[] new_bounds, double old_value) {
double old_range = (old_bounds[1] - old_bounds[0]);
double new_range = (new_bounds[1] - new_bounds[0]);
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/github/gidabotapp/domain/Robot.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.github.gidabotapp.R;

public enum Robot{
// StartPoint => 000 - Fakultateko sarrera nagusia
// StartPoint => 000 - Fakultateko Sarrera Nagusia
TARTALO ("Tartalo", R.drawable.tartalo_small,3.5503, -18.4937),

// StartPoint => 122 - Dekanotza
Expand Down
4 changes: 0 additions & 4 deletions app/src/main/java/com/github/gidabotapp/domain/Room.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ public double getZ(){
return position.getZ();
}

public boolean equals(Room room2){
return this.num.compareTo(room2.num) == 0;
}

@NonNull
@Override
public String toString(){
Expand Down
164 changes: 93 additions & 71 deletions app/src/main/java/com/github/gidabotapp/repository/QNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,38 +38,50 @@
import std_srvs.EmptyResponse;

public class QNode extends AbstractNodeMain {
// Singleton pattern instance
private static QNode INSTANCE = null;

// Node publishers
private Publisher<Goal> pubGoal;
private Publisher<CancelRequest> pubCancel;

// Service to clear Global Costmap
private ServiceClient<EmptyRequest, EmptyResponse> clearCostmapClient;

private HashMap<Floor, Subscriber<PoseWithCovarianceStamped>> positionSubs;
private HashMap<Floor, Subscriber<PendingGoals>> pendingReqSubs;
// Node subscribers
private HashMap<Floor, Subscriber<PoseWithCovarianceStamped>> positionSubHM;
private HashMap<Floor, Subscriber<PendingGoals>> pendingReqSubHM;
private Subscriber<std_msgs.Int8> subNavPhase;
private Subscriber<std_msgs.Int8> subDialogMessage;

private final HashMap<Floor, MutableLiveData<MapPosition>> currentPositions;
private final HashMap<Floor, MutableLiveData<List<Goal>>> pendingRequests;
// All MutableLiveData to expose ROS system's current data
private final HashMap<Floor, MutableLiveData<MapPosition>> currentPositionsHM;
private final HashMap<Floor, MutableLiveData<List<Goal>>> pendingRequestsHM;
private final MutableLiveData<PhaseMessage> phaseMessageLD;
private final MutableLiveData<MultiNavPhase> multiNavPhaseLD;

// ConnectedNode will be injected through MainActivity (RosActivity)
private ConnectedNode connectedNode;

// User Id will allow to differentiate possible different users in the system
private final String userId;

private int sequenceNumber;
// Will increment with each goal sent
private int goalSequenceNumber;

// Singleton pattern, private constructor
private QNode() {
// Get random UUID and set its first four characters as current instance's userID
this.userId = UUID.randomUUID().toString().substring(0,4);
this.sequenceNumber = 0;
this.currentPositions = new HashMap<Floor, MutableLiveData<MapPosition>>(){{
this.goalSequenceNumber = 0;
// Initialize current position's LiveData HashMap
this.currentPositionsHM = new HashMap<Floor, MutableLiveData<MapPosition>>(){{
for(Floor floor: Floor.values()){
put(floor, new MutableLiveData<MapPosition>());
}
}};
this.pendingRequests = new HashMap<Floor, MutableLiveData<List<Goal>>>(){{
// Initialize pending requests' LiveData HashMap
this.pendingRequestsHM = new HashMap<Floor, MutableLiveData<List<Goal>>>(){{
for(Floor floor: Floor.values()){
put(floor, new MutableLiveData<List<Goal>>());
}
Expand All @@ -78,18 +90,23 @@ private QNode() {
this.multiNavPhaseLD = new MutableLiveData<>();
}

// Singleton lazy initialization
public static synchronized QNode getInstance(){
if(INSTANCE == null){
INSTANCE = new QNode();
}
return INSTANCE;
}

// Node's name will be base name + current instance's userId
// This will allow to differentiate different users' nodes
public GraphName getDefaultNodeName() {
String GRAPH_NAME_BASE = "GidabotApp/QNode_";
return GraphName.of(GRAPH_NAME_BASE + userId);
}

// onStart event will initialize all publishers and subscribers needed
// ConnectedNode will be the the node received from nodeMainExecutor
public void onStart(final ConnectedNode connectedNode) {
this.connectedNode = connectedNode;

Expand All @@ -99,37 +116,42 @@ public void onStart(final ConnectedNode connectedNode) {
pubCancel = connectedNode.newPublisher("/cancel_request", CancelRequest._TYPE);
pubCancel.setLatchMode(true);

positionSubs = new HashMap<>();
final String amcl_topic_template = "/%s/amcl_pose";
for(final Floor floor: Floor.values()){
String topic = String.format(amcl_topic_template, floor.getRobotNameShort());
Subscriber<PoseWithCovarianceStamped> subscriber = connectedNode.newSubscriber(topic, PoseWithCovarianceStamped._TYPE);
subscriber.addMessageListener(new MessageListener<PoseWithCovarianceStamped>() {
@Override
public void onNewMessage(PoseWithCovarianceStamped message) {
MapPosition position = new MapPosition(message);
currentPositions.get(floor).postValue(position);
}
});
positionSubs.put(floor,subscriber);
}
// Initialize position subscribers' HashMap with a subscriber for each Floor (and hence, each Robot)
positionSubHM = new HashMap<Floor, Subscriber<PoseWithCovarianceStamped>>(){{
final String amcl_topic_template = "/%s/amcl_pose";
for(final Floor floor: Floor.values()) {
String topic = String.format(amcl_topic_template, floor.getRobotNameShort());
Subscriber<PoseWithCovarianceStamped> subscriber = connectedNode.newSubscriber(topic, PoseWithCovarianceStamped._TYPE);
subscriber.addMessageListener(new MessageListener<PoseWithCovarianceStamped>() {
@Override
public void onNewMessage(PoseWithCovarianceStamped message) {
MapPosition position = new MapPosition(message);
currentPositionsHM.get(floor).postValue(position);
}
});
put(floor, subscriber);
}
}};

pendingReqSubs = new HashMap<>();
final String pReq_topic_template = "/%s/pending_requests";
for(final Floor floor: Floor.values()){
String topic = String.format(pReq_topic_template, floor.getRobotNameShort());
Subscriber<PendingGoals> subscriber = connectedNode.newSubscriber(topic, PendingGoals._TYPE);
subscriber.addMessageListener(new MessageListener<PendingGoals>() {
@Override
public void onNewMessage(PendingGoals message) {
List<Goal> pendingGoals = message.getGoals();
pendingRequests.get(floor).postValue(pendingGoals);
}
});
pendingReqSubs.put(floor,subscriber);
}
// Initialize pending requests' subscribers' HashMap with a subscriber for each Floor (and hence, each Robot)
pendingReqSubHM = new HashMap<Floor, Subscriber<PendingGoals>>(){{
final String pReq_topic_template = "/%s/pending_requests";
for(final Floor floor: Floor.values()){
String topic = String.format(pReq_topic_template, floor.getRobotNameShort());
Subscriber<PendingGoals> subscriber = connectedNode.newSubscriber(topic, PendingGoals._TYPE);
subscriber.addMessageListener(new MessageListener<PendingGoals>() {
@Override
public void onNewMessage(PendingGoals message) {
List<Goal> pendingGoals = message.getGoals();
pendingRequestsHM.get(floor).postValue(pendingGoals);
}
});
put(floor,subscriber);
}
}};


// Nav Phase subscriber connection
subNavPhase = connectedNode.newSubscriber("/nav_phase", Int8._TYPE);
subNavPhase.addMessageListener(new MessageListener<Int8>() {
@Override
Expand All @@ -140,6 +162,7 @@ public void onNewMessage(Int8 message) {
}
});

// Dialog QT message subscriber connection
subDialogMessage = connectedNode.newSubscriber("/dialog_qt_message", Int8._TYPE);
subDialogMessage.addMessageListener(new MessageListener<Int8>() {
@Override
Expand All @@ -159,27 +182,27 @@ public void onNewMessage(Int8 message) {

}


// Publishes a goal, posting currentRoom, goal and chosen way as information
// for the robot to make the correct path
public void publishGoal(Room current, Room goal, Way chosenWay){
MessageFactory topicMessageFactory = connectedNode.getTopicMessageFactory();

// Clear Global costmap
// Clear Global costmap. This clears current stored obstacles, to prevent errors, such as the robot getting stuck
clearGlobalCostmap();

Goal message = topicMessageFactory.newFromType(Goal._TYPE);

message.setGoalSeq(sequenceNumber);
message.setGoalSeq(goalSequenceNumber);
message.setInitialFloor((float) current.getFloor());
message.setGoalFloor((float) goal.getFloor());

// Initial pose will be current Room's mapPosition coordinates
Point initial_pose = topicMessageFactory.newFromType(Point._TYPE);

initial_pose.setX(current.getX());
initial_pose.setY(current.getY());
initial_pose.setZ(current.getZ());
message.setInitialPose(initial_pose);


// Goal pose will be current Room's mapPosition coordinates
Point goal_pose = topicMessageFactory.newFromType(Point._TYPE);
goal_pose.setX(goal.getX());
goal_pose.setY(goal.getY());
Expand All @@ -188,6 +211,8 @@ public void publishGoal(Room current, Room goal, Way chosenWay){

message.setIntermediateRobot(false); //TODO
message.setIntermediateFloor((float)0.0); //TODO

// If not null, way will be chosenWay argument
String way = "";
if (chosenWay != null){
way = chosenWay.toString();
Expand All @@ -198,11 +223,12 @@ public void publishGoal(Room current, Room goal, Way chosenWay){
message.setLanguage("EU");
message.setUserName(this.userId);

// Publish built message and increment sequenceNumber
pubGoal.publish(message);
this.sequenceNumber++;
this.goalSequenceNumber++;
}


// Publishes a cancel request message
public void publishCancel(int goal_seq, boolean intermediateRobot, Floor initialFloor, Floor goalFloor, Floor intermediateFloor){
MessageFactory topicMessageFactory = connectedNode.getTopicMessageFactory();

Expand All @@ -211,7 +237,7 @@ public void publishCancel(int goal_seq, boolean intermediateRobot, Floor initial
message.setIntermediateRobot(intermediateRobot);
message.setInitialFloor((float) initialFloor.getFloorCode());
message.setGoalFloor((float) goalFloor.getFloorCode());
message.setRequestFloor((float) initialFloor.getFloorCode()); // IMPORTANTE: hau gabe ez doa
message.setRequestFloor((float) initialFloor.getFloorCode()); // !! Important, if not set correctly, it won't work
if (intermediateRobot){
message.setIntermediateFloor((float) intermediateFloor.getFloorCode());
}
Expand All @@ -220,7 +246,7 @@ public void publishCancel(int goal_seq, boolean intermediateRobot, Floor initial
}



// Clears global costmap, sending an empty request to clear costmap topic
public void clearGlobalCostmap(){
MessageFactory requestMessageFactory = connectedNode.getServiceRequestMessageFactory();

Expand All @@ -244,35 +270,14 @@ public void onFailure(RemoteException e) {
}
}


public MutableLiveData<PhaseMessage> getPhaseMessageLD(){
return this.phaseMessageLD;
}


public MutableLiveData<MultiNavPhase> getMultiNavPhaseLD(){
return this.multiNavPhaseLD;
}


public HashMap<Floor, MutableLiveData<MapPosition>> getCurrentPositions(){
return this.currentPositions;
}

public HashMap<Floor, MutableLiveData<List<Goal>>> getPendingRequests(){
return this.pendingRequests;
}

public String getUserId(){
return this.userId;
}

// Shuts down every powered subscriber and listener
// Finally sets instance to null
public void shutdown() {
try {
for(Subscriber<PoseWithCovarianceStamped> sub: positionSubs.values()){
for(Subscriber<PoseWithCovarianceStamped> sub: positionSubHM.values()){
sub.shutdown();
}
for(Subscriber<PendingGoals> sub: pendingReqSubs.values()){
for(Subscriber<PendingGoals> sub: pendingReqSubHM.values()){
sub.shutdown();
}

Expand All @@ -292,4 +297,21 @@ public void shutdown() {

}

// Getters
public MutableLiveData<PhaseMessage> getPhaseMessageLD(){
return this.phaseMessageLD;
}
public MutableLiveData<MultiNavPhase> getMultiNavPhaseLD(){
return this.multiNavPhaseLD;
}
public HashMap<Floor, MutableLiveData<MapPosition>> getCurrentPositionsHM(){
return this.currentPositionsHM;
}
public HashMap<Floor, MutableLiveData<List<Goal>>> getPendingRequestsHM(){
return this.pendingRequestsHM;
}
public String getUserId(){
return this.userId;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public static RoomDatabase getInstance(final Context context){
if(INSTANCE == null){
INSTANCE = androidx.room.Room.databaseBuilder(context,
RoomDatabase.class, db_name)
// .addCallback(populateDB)
// Populate database with stored information at assets/Rooms.db. This is only executed on app's first launch,
// Which means that if you want to repopulate database you will have to uninstall the app
.createFromAsset("database/"+db_name)
.build();
Log.i("DAO", "Database instantiated");
Expand Down
Loading

0 comments on commit 0fb3d73

Please sign in to comment.