Перейти к содержанию
Fire Monkey от А до Я
  • 0

Delphi 10.4. Андроид. Проблемы с компасом.


Саша

Вопрос

Опубликовано

Вчера попросил нейросеть написать программу для вывода азимута в Label по нажатию кнопки. Все примеры, которые показывалв нейросеть были с ошибками. После пятичасового общения с нейросетью получил работающий пример.
Но значения азимута не то что хаотично менялись, они были непредсказуемыми.

Вот "работающий" пример от нейросети:

 

Спойлер

unit unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Sensors,
  System.Math, FMX.Types, FMX.Controls, FMX.Forms, FMX.StdCtrls,
  FMX.Controls.Presentation;

type
  TForm1 = class(TForm)
    LabelAzimuth: TLabel;
    Button1: TButton;
    Timer1: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    FSensorManager: TSensorManager;
    FCompass: TCustomOrientationSensor;
    FLastValidAzimuth: Double;
    FReadingCount: Integer;
    function GetNormalizedAzimuth: Double;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  FSensorManager := TSensorManager.Current;
  FSensorManager.Active := True;

  // Поиск датчика компаса
  for i := 0 to FSensorManager.Count - 1 do
    if (FSensorManager.Sensors[i].Category = TSensorCategory.Orientation) and
       (FSensorManager.Sensors[i] is TCustomOrientationSensor) then
    begin
      FCompass := TCustomOrientationSensor(FSensorManager.Sensors[i]);
      Break;
    end;

  Timer1.Interval := 300; // Оптимальный интервал обновления
  FLastValidAzimuth := 0;
  FReadingCount := 0;
end;

function TForm1.GetNormalizedAzimuth: Double;
const
  MAX_READINGS = 10; // Количество показаний для усреднения
var
  RawValue: Double;
begin
  Result := FLastValidAzimuth; // Возвращаем последнее валидное значение по умолчанию

  if Assigned(FCompass) and FCompass.Started then
  begin
    try
      // Получаем сырое значение
      RawValue := FCompass.HeadingX * (180/Pi);

      // Фильтрация аномальных значений
      if (RawValue > 3600) or (RawValue < -3600) then
        Exit; // Игнорируем явно ошибочные значения

      // Нормализация в диапазон 0-360
      Result := RawValue;
      while Result < 0 do Result := Result + 360;
      while Result >= 360 do Result := Result - 360;

      // Простое усреднение
      if FReadingCount < MAX_READINGS then
      begin
        FLastValidAzimuth := (FLastValidAzimuth * FReadingCount + Result) / (FReadingCount + 1);
        Inc(FReadingCount);
      end
      else
      begin
        FLastValidAzimuth := Result; // После набора статистики используем текущее значение
      end;

    except
      on E: Exception do
        LabelAzimuth.Text := 'Ошибка датчика: ' + E.Message;
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Assigned(FCompass) then
  begin
    if not FCompass.Started then
    begin
      FCompass.Start;
      FReadingCount := 0; // Сброс счетчика при ручном запуске
    end;
    Timer1.Enabled := not Timer1.Enabled;
    if Timer1.Enabled then Button1.Text :=  'Старт'
    else Button1.Text :=  'Стоп';
  end
  else
    LabelAzimuth.Text := 'Компас не доступен';
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  FLastValidAzimuth := GetNormalizedAzimuth;
  LabelAzimuth.Text := Format('Азимут: %.1f°', [FLastValidAzimuth]);
end;

end.


Выходит, что Embarcadero не может работать корретно с сенсорами. А приложения с компасом, написанные на JAVA работают четко.

Известно, что как-то можно соединить в одном приложении Delphi и Java. Подскажите, пожалуйста, в каком направлении копать.

спасибо!

Рекомендуемые сообщения

  • 0
Опубликовано

И еще прошу помочь разобраться вот в чем.

Нейросеть пишет: "Создаем Java-класс для точных показаний (CompassSensor.java):"
 

Правильно ли я понимаю, что этот класс (приведенный ниже) надо поместить в файл с именем CompassSensor.java?

Далее она пишет: "Добавьте Java-файл в: Project -> Deployment -> Add File -> platforms\android\src\com\embarcadero\compass\CompassSensor.java"
 

По какому пути должен быть размещён этот файл? Подскажите, пожалуйста.

 

А вот Java - класс:

 

Спойлер

package com.embarcadero.compass;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

public class CompassSensor implements SensorEventListener {
    private SensorManager sensorManager;
    private Sensor accelerometer;
    private Sensor magnetometer;
    private float[] lastAccelerometer = new float[3];
    private float[] lastMagnetometer = new float[3];
    private float[] rotationMatrix = new float[9];
    private float[] orientation = new float[3];
    private boolean lastAccelerometerSet = false;
    private boolean lastMagnetometerSet = false;

    public CompassSensor(SensorManager manager) {
        sensorManager = manager;
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        magnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
    }

    public void start() {
        sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME);
        sensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_GAME);
    }

    public void stop() {
        sensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor == accelerometer) {
            System.arraycopy(event.values, 0, lastAccelerometer, 0, event.values.length);
            lastAccelerometerSet = true;
        } else if (event.sensor == magnetometer) {
            System.arraycopy(event.values, 0, lastMagnetometer, 0, event.values.length);
            lastMagnetometerSet = true;
        }

        if (lastAccelerometerSet && lastMagnetometerSet) {
            SensorManager.getRotationMatrix(rotationMatrix, null, lastAccelerometer, lastMagnetometer);
            SensorManager.getOrientation(rotationMatrix, orientation);
            float azimuthInRadians = orientation[0];
            float azimuthInDegrees = (float)(Math.toDegrees(azimuthInRadians) + 360) % 360;
            // Здесь можно передать данные в Delphi
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}

 

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...