#java #android #navigation #arcore #sceneform
Вопрос:
Я разрабатываю приложение AR для Android для навигации в помещении. Я реализовал класс beaconService, чтобы получать значения моих 3 маяков и сохранять их с помощью базы данных SQLite. Приняв эти значения, я оцениваю местоположение пользователя с помощью метода трилатерации. Несмотря на то,что я сталкиваюсь с некоторыми проблемами с местоположением, которое я вычисляю (возможно, из-за неправильного расположения моих 3 маяков), я хочу использовать это местоположение (это массив значений x, y) для реализации AR-части моего приложения. в частности, я хочу, чтобы пользователь перемещался к месту назначения с помощью Sceneform и ARCore sdk. Я опубликую класс BeaconService и часть того, что я пытался реализовать для определения местоположения пользователя и реализации части AR (часть навигации). ПОЭТОМУ мне нужна помощь в части AR моего приложения.
Класс обслуживания маяков
protected ScanCallback mScanCallback = new ScanCallback() {
@RequiresApi(api = Build.VERSION_CODES.P)
@Override
public void onScanResult(int callbackType, final ScanResult result) {
final BluetoothDevice bluetoothDevice = result.getDevice();
ScanRecord scanRecord = result.getScanRecord();
assert scanRecord != null;
List<ADStructure> structures = ADPayloadParser.getInstance().parse(scanRecord.getBytes());
ConstantsVariables.activity_started_bluetooth = true;
String deviceName = scanRecord.getDeviceName();
if (deviceName != null) {
for (ADStructure structure : structures) {
if (structure instanceof IBeacon) {
final IBeacon iBeacon = (IBeacon) structure;
Distance = (float) calculateDistance(applyKalmanFilterToRssi(result.getRssi()));
if (db.getCount() == 0 || !db.checkIfSpecificMinorIsInDB(iBeacon.getMinor())) {
db.addBeacon(new BeaconInfo(iBeacon.getMinor(), Distance, result.getRssi()));
}
else {
BeaconInfo beaconInfo = db.getBeaconInfo(iBeacon.getMinor());
beaconInfo.setMinor(iBeacon.getMinor());
beaconInfo.setDistance(Distance);
beaconInfo.setRssi(result.getRssi());
db.updateBeacon(beaconInfo);
}
}
@NonNull
@Override
public Result doWork() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
System.out.println("Bluetooth not supported");
} else {
System.out.println("Bluetooth initialized");
}
if (mBluetoothAdapter.isEnabled()) {
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
setScanSettings();
mBluetoothLeScanner.startScan(null, mScanSettings, mScanCallback);
}
return Result.success();
}
// Method Apply Filter
private double applyKalmanFilterToRssi(double rssi){
double filterrssi = kalmanFilter.applyFilter(rssi);
return filterrssi;
}
private void setScanSettings() {
ScanSettings.Builder mBuilder = new ScanSettings.Builder();
mBuilder.setReportDelay(0);
mBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER);
mScanSettings = mBuilder.build();
}
public double calculateDistance(double rssi) {
int txPower = -56;
if (rssi == 0) {
return -1.0; // if we cannot determine accuracy, return -1.
}
double ratio = rssi * 1.0 / txPower;
if (ratio < 1.0) {
return Math.pow(ratio, 10);
} else {
return (0.89976) * Math.pow(ratio, 7.7095) 0.111;
}
}
Класс навигации
Чтобы определить местоположение пользователя, я использую этот метод:
private void updateUserLocation {
DatabaseHandler db = new DatabaseHandler(getApplicationContext());
List<BeaconInfo> beaconList = db.getAllBeacons();
for (BeaconInfo beaconInfo : beaconList) {
int MinorType = beaconInfo.getMinor();
if (MinorType == ConstantsVariables.minor_437) {
distance437 = beaconInfo.getDistance();
distanceVector[0] = distance437 / 100000; //km to meters
} else if (MinorType == ConstantsVariables.minor_570) {
distance570 = beaconInfo.getDistance();
distanceVector[1] = distance570 / 100000;
} else if (MinorType == ConstantsVariables.minor_574) {
distance574 = beaconInfo.getDistance();
distanceVector[2] = distance574 / 100000;
}
}
Log.i(TAG, "Distances: " distance437 " / " distance570 " / " distance574);
//Trilateration
NonLinearLeastSquaresSolver solver = new NonLinearLeastSquaresSolver(new TrilaterationFunction(positions, distanceVector), new LevenbergMarquardtOptimizer());
LeastSquaresOptimizer.Optimum optimum = solver.solve();
calculatedPosition = optimum.getPoint().toArray();
}
For the AR part i have impemented these:
private void setARFragment() {
mARFragment = (CloudAnchorFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
// When you build a Renderable, Sceneform loads its resources in the background while returning
// a CompletableFuture. Call thenAccept(), handle(), or check isDone() before calling get().
create3dModel();
mARFragment.getArSceneView().getScene().addOnUpdateListener(this::onSceneUpdate);
}
private void create3dModel() {
ModelRenderable.builder()
.setSource(this, Uri.parse("model.sfb"))
.build()
.thenAccept(renderable -> mObjRenderable = renderable)
.exceptionally(
throwable -> {
Toast toast = Toast.makeText(this, "Unable to load obj renderable", Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
return null;
});
}
private void onSceneUpdate(FrameTime frameTime) {
// Let the fragment update its state first.
mARFragment.onUpdate(frameTime);
// If there is no frame then don't process anything.
if (mARFragment.getArSceneView().getArFrame() == null) {
return;
}
// If ARCore is not tracking yet, then don't process anything.
if (mARFragment.getArSceneView().getArFrame().getCamera().getTrackingState() != TrackingState.TRACKING) {
return;
}
// Place the anchor 1m in front of the camera if anchorNode is null.
if (this.mAnchorNode == null) {
addModelToScene();
}
private void addModelToScene() {
Session session = mARFragment.getArSceneView().getSession();
Pose pos = Objects.requireNonNull(mARFragment.getArSceneView().getArFrame()).getCamera().getPose().compose(Pose.makeTranslation(0, 0, -1));
assert session != null;
Anchor mAnchor;
mAnchor = session.createAnchor(pos);
mAnchorNode = new AnchorNode(mAnchor);
mAnchorNode.setParent(mARFragment.getArSceneView().getScene());
// Create the arrow node and add it to the anchor.
arrow = new Node();
Quaternion rotation1 = Quaternion.axisAngle(new Vector3(1.3f, 0.5f, 0.0f), 90); // rotate X axis 90 degrees
Quaternion rotation2 = Quaternion.axisAngle(new Vector3(0.5f, -1.5f, 1.0f), 90); // rotate Y axis 90 degrees
arrow.setLocalRotation(Quaternion.multiply(rotation1, rotation2));
arrow.setParent(mAnchorNode);
//arrow.setRenderable(mObjRenderable);
}
So i have to create a new method now that based on the calculatedPosition(user position) and the destination point (is saved) to navigate user to their destination with AR. Any help will be appreciated.