kopia lustrzana https://github.com/sh123/codec2_talkie
Implemented smart beaconing algorithm
rodzic
1a346248ff
commit
8ff1d472ee
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
Ładowanie…
Reference in New Issue