Разработка Под Sailfish Os: Использование Датчиков (Часть 2)

Привет! Данная статья является второй частью более крупной статьи, посвященной использованию датчиков устройств под управлением ОС Sailfish. Первая часть доступна здесь .



Датчик наклона

Датчик наклона, как следует из названия, определяет угол наклона устройства.

Ситуация с компонентами для измерения наклона аналогична датчикам освещенности: есть еще один «умный» компонент — Датчик вращения , и его менее продвинутый товарищ - Датчик ориентации .

ВращениеЧтение предоставляет информацию о точном угле наклона относительно трёх осей координат: свойство x содержит информацию о том, насколько продольная ось смартфона отклонилась от горизонтального положения, свойство y содержит ту же информацию, но для поперечной оси, и z - о повороте относительно центра экрана.

Более наглядно это можно увидеть на изображении:

Разработка под Sailfish OS: использование датчиков (часть 2)

Эти значения вы можете наблюдать в импровизированной таблице на экране устройства:

  
  
  
  
  
  
  
  
   

RotationSensor { id: rotationSensor active: true } Column { Label { text: "x: " + rotationSensor.reading.x } Label { text: "y: " + rotationSensor.reading.y } Label { text: "z: " + rotationSensor.reading.z } }

Определение значений угла z не всегда доступно.

Чтобы определить, доступно ли это значение, необходимо проверить свойство имеетZ компонент ВращениеЧтение .

Датчик ориентации , как менее функциональный компонент, позволяет ответить на важный вопрос: «какая сторона смартфона направлена вверхЭ» Соответственно, оно может принимать шесть значений, каждое из которых соответствует ребру.

Плюс одно дополнительное значение, указывающее, что положение невозможно определить.

Эти значения можно найти в следующем списке:

  • ОриентацияЧтение.

    Не определено - невозможно определить местоположение устройства,

  • ОриентацияЧтение.

    Пополнение - верхний край направлен вверх,

  • ОриентацияЧтение.

    TopDown - нижний край направлен вверх (перевернут),

  • ОриентацияЧтение.

    LeftUp - левая сторона направлена вверх,

  • ОриентацияЧтение.

    RightUp - правая сторона направлена вверх,

  • ОриентацияЧтение.

    FaceUp — устройство расположено экраном вверх,

  • ОриентацияЧтение.

    FaceDown — устройство расположено лицевой стороной вниз.

Применять Датчик ориентации можно, например, чтобы сохранить ориентацию изображения при изменении положения самого устройства:

OrientationSensor { id: orientationSensor active: true } Image { anchors.centerIn: parent source: " http://social.fruct.org/content/img/fruct.png " transform: Rotation { angle: rotationAngle() } } function rotationAngle() { switch (orientationSensor.reading.orientation) { case OrientationReading.TopUp: return 0; case OrientationReading.RightUp: return 90; case OrientationReading.TopDown: return 180; case OrientationReading.LeftUp: return 270; default: return 0; } }

В приведенном выше примере логотип будет обращен к верхнему краю смартфона:

Разработка под Sailfish OS: использование датчиков (часть 2)



Магнитометр

Магнитометр представлен типом QML. Магнитометр , он предоставляет информацию о напряженности магнитного поля вокруг устройства по осям X, Y и Z. Значения указаны в Tesla. Магнитометр может реагировать как на силу любых магнитных полей вокруг прибора, так и на силу только геомагнитного поля.

Такое поведение контролируется свойством returnGeoValues , который может принимать либо истинный , или ЛОЖЬ .

Изначально это имеет смысл ЛОЖЬ и реагирует на любые магнитные поля поблизости.

Разница между этими двумя режимами заключается в том, что при включении returnGeoValues Датчик попытается устранить влияние посторонних магнитных полей, исходящих от источников магнитного поля, таких как проводники, магниты и электронные устройства, и сосредоточится на естественном магнитном поле Земли.

Конечно, полностью исключить влияние посторонних магнитных полей не удастся, поэтому показания датчиков все равно будут меняться при появлении новых источников.

Объект МагнитометрЧтение имеет помимо уже знакомых свойств Икс , й , И я , содержащие напряжения по осям, также обладают свойством уровень калибровки — уровень точности измерения напряженности геомагнитного поля.

Этот параметр принимает значения от 0 до 1 в соответствии с уровнем калибровки датчика и меняет свое значение только при returnGeoValues содержит истинный .

Это свойство отражает, насколько сильно близлежащие магнитные поля влияют на измерение геомагнитного поля.

Если влияние велико, значение упадет до нуля.

Для восстановления точности измерений необходимо откалибровать датчик.

Обычно это делается путем вращения устройства по дуге восьмерки или просто размахивания им в разных направлениях в пространстве.

Если точность низкая, значения датчика будут сильно отличаться от фактических значений.

Это особенно актуально при использовании магнитометра в качестве компаса.



Компас

Компонент Компас действует как электронный компас.

Его свойство чтения содержит объект КомпасЧтение , который предоставляет информацию об азимуте устройства — угле между северным магнитным полюсом и осью X устройства по часовой стрелке.

Эта информация, как и показания магнитометра, основана на данных геомагнитного поля.

Из-за этого компас также подвержен различным помехам и также требует калибровки.

КомпасЧтение имеет два свойства:

  • азимут : qreal — горизонтальный угол между северным магнитным полюсом Земли и направлением, в котором указывает верхний край смартфона,
  • уровень калибровки : qreal — точность показаний датчика, полностью аналогичная свойству уровень калибровки тип МагнитометрЧтение .



Фильтрация показаний датчиков

Показания некоторых датчиков могут меняться много раз в секунду.

Использование стандартного механизма уведомлений Qt с использованием сигналов и слотов существенно замедлит процесс получения значений и снизит точность измерений в целом.

Альтернативой использованию сигналов для получения значения датчика является класс QSensorFilter .

Этот класс представляет собой интерфейс, реализующий функцию обратного вызова, которая вызывается при получении новых показаний классом подписанного датчика.

Отличительной особенностью этой функции является возможность изменять поступающие в нее измерения датчика, преобразуя тем самым конечное значение свойства чтение .

А в сочетании с возможностью присоединения к одному датчику нескольких фильтров все преобразования значений можно осуществлять с помощью фильтров, получая на выходе желаемые результаты.

Подобно другим родительским классам из API Qt Sensors, QSensorFilter имеет только универсальный набор методов:

  • общедоступный фильтр bool (QSensorReading *чтение) — та же функция обратного вызова, которая вызывается при получении измерений от датчика.

    Это позволяет предварительно обрабатывать значения.

    Если эта функция возвращает истинный , то показания передаются либо в следующий фильтр, если он есть, либо выдается сигнал об изменении значения свойства чтение .

    По возвращении ЛОЖЬ обработка текущих показаний датчика прекращается.

  • protected void setSensor(QSensor *sensor) — позволяет указать класс датчика, к которому привязан фильтр, из самого фильтра.

Методы, специфичные для конкретного типа датчика, уже реализованы в классах-потомках.

То же, что и с объектами типа Чтение , каждый датчик имеет свой фильтр.

Например, акселерометр, с которым связан класс QАкселерометр , есть фильтр QАкселерометрФильтр и его метод фильтр принимает следующую форму:

bool filter(QAccelerometerReading *reading)

В отличие от родительского метода, он получает в качестве параметра объект с измерениями акселерометра.

То же самое касается и других типов фильтров.

Управление фильтрами осуществляется с помощью методов класса сенсора.

Для этой цели QSensors Реализован ряд функций, позволяющих управлять набором обработчиков:

  • void addFilter (QSensorFilter *filter) — добавляет указанный фильтр в конец списка.

    При этом один фильтр может быть включен в список несколько раз.

  • void RemoveFilter (QSensorFilter *filter) — удаляет из списка первое найденное вхождение указанного фильтра.

  • QList фильтры() константа — список указателей на все фильтры, на которые подписан датчик.

    Функции-обработчики вызываются в порядке возрастания их позиции в списке.

В отличие от других классов API Qt Sensors, фильтры изначально не имеют интерфейса для работы с ними из QML-кода.

Кроме того, методы управления набором фильтров конкретного датчика нельзя использовать непосредственно из QML. В качестве примера использования фильтра можно рассмотреть реализацию режимов акселерометра.

QАкселерометр::Пользователь И QАкселерометр::Гравитация .

Этот фильтр может быть полезен на устройствах, которые не поддерживают другие режимы работы акселерометра, кроме Комбинированный .

Для этого вам также понадобится использовать датчик вращения – Датчик вращения .

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

А затем эта информация используется для расчета ускорения, вызванного пользователем.

Именно такой подход мы будем использовать для реализации режимов Сила тяжести И Пользователь Первым шагом является создание класса, выполняющего фильтрацию, который будет унаследован от QАкселерометрФильтр .

В нем мы сразу задаем значение величины G – ускорение свободного падения.



#define G 9.80665 #include <QtSensors> #include <math.h> class AccelerationModeFilter : public QAccelerometerFilter { public: AccelerationModeFilter(); bool filter(QAccelerometerReading *reading); void setAccelerationMode(QAccelerometer::AccelerationMode accelerationMode); QAccelerometer::AccelerationMode getAccelerationMode(); private: QRotationSensor rotationSensor; QAccelerometer::AccelerationMode accelerationMode; };

В классе необходимо иметь два типа свойств: QRotationSensor — датчик вращения, с его помощью мы будем определять положение устройства в пространстве; QAccelerometer::AccelerationMode — режим измерения значений акселерометра; в соответствии с этим значением будет выбран необходимый метод расчета значения.

При расчете проекций ускорений на оси координат часто придется прибегать к тригонометрическим операциям, например взятию синуса и косинуса.

Для этого будет использоваться стандартная библиотека C. math.h и ее методы грех() И потому что() .

Эти методы принимают значения угла в радианах, тогда как датчик выдает значения в градусах.

Поэтому создадим небольшой метод, который будет конвертировать значения углов из градусов в радианы:

qreal toRadian(qreal degree) { return degree * M_PI / 180; }

Режим расчета ускорения будет установлен в конструкторе класса, где мы инициализируем и активируем датчик наклона:

AccelerationModeFilter::AccelerationModeFilter() : rotationSensor() { rotationSensor.setActive(true); }

Самая важная часть — переопределение метода фильтр (QAccelerometerReading *чтение) , в котором будут произведены расчеты:

bool AccelerationModeFilter::filter(QAccelerometerReading* reading) { switch (accelerationMode) { case QAccelerometer::Gravity: reading->setX(G * sin(toRadian(rotationSensor.reading()->y()))); reading->setY(- G * sin(toRadian(rotationSensor.reading()->x()))); reading->setZ(- zAxisAcceleration(rotationSensor.reading()->x(), rotationSensor.reading()->y())); break; case QAccelerometer::User: reading->setX(reading->x() - G * sin(toRadian(rotationSensor.reading()->y()))); reading->setY(reading->y() + G * sin(toRadian(rotationSensor.reading()->x()))); reading->setZ(reading->z() + zAxisAcceleration(rotationSensor.reading()->x(), rotationSensor.reading()->y())); break; } return true; } void AccelerationModeFilter::setAccelerationMode(QAccelerometer::AccelerationMode accelerationMode) { this->accelerationMode = accelerationMode; } QAccelerometer::AccelerationMode AccelerationModeFilter::getAccelerationMode() { return accelerationMode; }

В операторе выключатель выбираем блоки, каждый из которых будет отвечать за свой режим измерения ускорения, таких режимов два: Сила тяжести И Пользователь ; Комбинированный можно пропустить, так как значения изначально находятся в этом режиме.

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

Чтобы рассчитать ускорение по осям X и Y, просто умножьте ускорение свободного падения на синус угла между смартфоном и соответствующей осью координатной плоскости, а для расчета ускорения по оси Z потребуется применить матрица преобразования.

Давайте реализуем это в отдельном методе:

qreal zAxisAcceleration(qreal xDegree, qreal yDegree) { qreal xRadian = toRadian(xDegree); qreal yRadian = toRadian(yDegree); double zCoordinates[3] = {0, 0, G}; double rotationValues[9] = { -cos(xRadian), 0, sin(xRadian), sin(yRadian) * sin(xRadian), cos(yRadian), -sin(yRadian) * cos(yRadian), -cos(yRadian) * sin(xRadian), sin(yRadian), cos(yRadian) * cos(xRadian) }; QGenericMatrix<1, 3, double> zVector(zCoordinates); QGenericMatrix<3, 3, double> rotationMatrix(rotationValues); return (rotationMatrix * zVector)(2, 0); }

Поскольку у нас не урок геометрии, думаю, нет необходимости объяснять, почему матрица выглядит именно так, но интересующиеся всегда могут обратиться к Википедия .

Для режима Сила тяжести рассчитанные значения ускорения по осям просто записываются в соответствующие свойства объекта чтение , так как в этом случае значения ускорения зависят только от положения устройства.

Для определения значений в режиме Пользователь Абсолютные значения полученных расчетов необходимо вычесть из показаний акселерометра — так мы исключим влияние силы тяжести на измерения датчика.

На этом реализация фильтра завершена, подключаем его к нужному акселерометру и используем два новых режима:

#include <QtSensors> #include "accelerometerfilterexample.h" class AccelerometerWithFilter : public QAccelerometer { Q_OBJECT public: AccelerometerWithFilter() : filter() { setActive(true); addFilter(&filter); connect(this, &AccelerometerWithFilter::accelerationModeChanged, [=](AccelerationMode accelerationMode) {this->filter.setAccelerationMode(accelerationMode);}); } private: AccelerationModeFilter filter; };



Заключение

? это и предыдущий В статьях рассматриваются основные датчики, доступные в операционной системе Sailfish OS. Хотя приведенные примеры очень просты, они должны познакомить читателя с возможностями Qt Sensors API и показать потенциал использования плагина при разработке приложений.

Технические вопросы также можно обсудить по адресу канал русскоязычного сообщества Sailfish OS в Telegram или группа вконтакте .

Автор: Максим Костерин Теги: #sailfish os #qml #Qt #sensors #sensors #Разработка мобильных приложений #Qt #Разработка для Sailfish OS

Вместе с данным постом часто просматривают: