Implemented smart beaconing algorithm

pull/30/head
sh123 2022-07-04 13:56:27 +03:00
rodzic 1a346248ff
commit 8ff1d472ee
4 zmienionych plików z 94 dodań i 30 usunięć

Wyświetl plik

@ -3,7 +3,7 @@ package com.radio.codec2talkie.protocol.position;
import android.location.Location;
public class Position {
public String timestamp;
public long timestampEpochMs;
public String srcCallsign;
public String dstCallsign;
public double latitude;
@ -19,6 +19,9 @@ public class Position {
public int extDigipathSsid;
public boolean isSpeedBearingEnabled;
public boolean isAltitudeEnabled;
public boolean hasBearing;
public boolean hasAltitude;
public boolean hasSpeed;
public static Position fromLocation(Location location) {
Position position = new Position();
@ -27,6 +30,28 @@ public class Position {
position.bearingDegrees = location.getBearing();
position.altitudeMeters = location.getAltitude();
position.speedMetersPerSecond = location.getSpeed();
position.timestampEpochMs = location.getTime();
position.hasBearing = location.hasBearing();
position.hasAltitude = location.hasAltitude();
position.hasSpeed = location.hasSpeed();
return position;
}
public double distanceTo(Position position) {
final int R = 6371; // Radius of the earth
double latDistance = Math.toRadians(position.latitude - latitude);
double lonDistance = Math.toRadians(position.longitude - longitude);
double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
+ Math.cos(Math.toRadians(latitude)) * Math.cos(Math.toRadians(position.latitude))
* Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = R * c * 1000; // convert to meters
double height = altitudeMeters - position.longitude;
distance = Math.pow(distance, 2) + Math.pow(height, 2);
return Math.sqrt(distance);
}
}

Wyświetl plik

@ -33,7 +33,17 @@ public class UnitTools {
return (long)(metersPerSecond / 0.514444);
}
public static double metersPerSecondToMilesPerHour(float metersPerSecond) {
return metersPerSecond * 2.23693629;
}
public static double kilometersPerSecondToMetersPerSecond(double kilometersPerHour) {
return kilometersPerHour * 0.2777777778;
}
public static long minutesToMillis(long minutes ) {
return minutes * 60L * 1000L;
}
public static long millisToSeconds(long milliseconds) { return milliseconds / 1000L; }
}

Wyświetl plik

@ -81,13 +81,7 @@ public class Periodic implements Tracker {
}
private void sendLocation(Location location) {
Position position = new Position();
position.latitude = location.getLatitude();
position.longitude = location.getLongitude();
position.bearingDegrees = location.getBearing();
position.speedMetersPerSecond = location.getSpeed();
position.altitudeMeters = location.getAltitude();
_trackerCallback.onSendLocation(position);
_trackerCallback.onSendLocation(Position.fromLocation(location));
}
private final LocationListener _locationListener = new LocationListener() {

Wyświetl plik

@ -16,6 +16,7 @@ import androidx.preference.PreferenceManager;
import com.radio.codec2talkie.protocol.position.Position;
import com.radio.codec2talkie.settings.PreferenceKeys;
import com.radio.codec2talkie.tools.UnitTools;
public class Smart implements Tracker {
private static final String TAG = Periodic.class.getSimpleName();
@ -25,26 +26,28 @@ public class Smart implements Tracker {
private Context _context;
private LocationManager _locationManager;
private int _fastSpeed;
private int _fastRate;
private int _slowSpeed;
private int _slowRate;
private int _minTurnTime;
private int _minTurnAngle;
private int _fastSpeedKmph;
private int _fastRateSeconds;
private int _slowSpeedKmph;
private int _slowRateSeconds;
private int _minTurnTimeSeconds;
private int _minTurnAngleDegrees;
private int _turnSlope;
private Position _oldPosition;
@Override
public void initialize(Context context, TrackerCallback trackerCallback) {
_context = context;
_trackerCallback = trackerCallback;
_locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
_fastSpeed = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_FAST_SPEED, "90"));
_fastRate = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_FAST_RATE, "60"));
_slowSpeed = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_SLOW_SPEED, "5"));
_slowRate = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_SLOW_RATE, "1200"));
_minTurnTime = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_MIN_TURN_TIME, "15"));
_minTurnAngle = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_MIN_TURN_ANGLE, "10"));
_fastSpeedKmph = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_FAST_SPEED, "90"));
_fastRateSeconds = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_FAST_RATE, "60"));
_slowSpeedKmph = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_SLOW_SPEED, "5"));
_slowRateSeconds = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_SLOW_RATE, "1200"));
_minTurnTimeSeconds = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_MIN_TURN_TIME, "15"));
_minTurnAngleDegrees = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_MIN_TURN_ANGLE, "10"));
_turnSlope = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.APRS_LOCATION_SOURCE_SMART_TURN_SLOPE, "240"));
}
@ -71,8 +74,8 @@ public class Smart implements Tracker {
}
_locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
5000L,
5,
0,
0,
_locationListener
);
_isTracking = true;
@ -90,17 +93,49 @@ public class Smart implements Tracker {
}
private void sendLocation(Location location) {
Position position = new Position();
position.latitude = location.getLatitude();
position.longitude = location.getLongitude();
position.bearingDegrees = location.getBearing();
position.speedMetersPerSecond = location.getSpeed();
position.altitudeMeters = location.getAltitude();
_trackerCallback.onSendLocation(position);
_trackerCallback.onSendLocation(Position.fromLocation(location));
}
private boolean isCornerPeggingTriggered(Position newPosition, Position oldPosition) {
long timeDifferenceSeconds = UnitTools.millisToSeconds(newPosition.timestampEpochMs - oldPosition.timestampEpochMs);
float turnAngleDegrees = Math.abs(newPosition.bearingDegrees - oldPosition.bearingDegrees) % 360;
turnAngleDegrees = turnAngleDegrees <= 180 ? turnAngleDegrees : 360 - turnAngleDegrees;
if (!newPosition.hasBearing || newPosition.speedMetersPerSecond == 0)
return false;
if (!oldPosition.hasBearing)
return timeDifferenceSeconds >= _minTurnTimeSeconds;
double thresholdDegrees = _minTurnAngleDegrees + _turnSlope / UnitTools.metersPerSecondToMilesPerHour(newPosition.speedMetersPerSecond);
return timeDifferenceSeconds >= _minTurnTimeSeconds && turnAngleDegrees > thresholdDegrees;
}
private boolean shouldSendPosition(Position newPosition, Position oldPosition) {
if (oldPosition == null) return true;
if (isCornerPeggingTriggered(newPosition, oldPosition)) return true;
double distanceMeters = oldPosition.distanceTo(newPosition);
long timeDifferenceSeconds = UnitTools.millisToSeconds(newPosition.timestampEpochMs - oldPosition.timestampEpochMs);
double maxSpeedMetersPerSecond = Math.max(Math.max(distanceMeters/timeDifferenceSeconds, newPosition.speedMetersPerSecond), oldPosition.speedMetersPerSecond);
double maxSpeedKilometersPerSecond = UnitTools.kilometersPerSecondToMetersPerSecond(maxSpeedMetersPerSecond);
double speedRateSeconds;
if (maxSpeedKilometersPerSecond <= _slowSpeedKmph)
speedRateSeconds = _slowRateSeconds;
else if (maxSpeedKilometersPerSecond >= _fastSpeedKmph)
speedRateSeconds = _fastRateSeconds;
else
speedRateSeconds = (_fastRateSeconds + (_slowRateSeconds - _fastRateSeconds) * (_fastSpeedKmph - maxSpeedKilometersPerSecond) / (_fastSpeedKmph - _slowSpeedKmph));
return timeDifferenceSeconds >= (long)speedRateSeconds;
}
private void processNewLocation(Location location) {
// TODO, add Smartbeaconing logic
Position newPosition = Position.fromLocation(location);
if (shouldSendPosition(newPosition, _oldPosition)) {
_trackerCallback.onSendLocation(newPosition);
_oldPosition = newPosition;
}
}
private final LocationListener _locationListener = new LocationListener() {