Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compass fluctuation and unstable values. #3

Open
amol251 opened this issue Nov 27, 2019 · 6 comments
Open

Compass fluctuation and unstable values. #3

amol251 opened this issue Nov 27, 2019 · 6 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@amol251
Copy link

amol251 commented Nov 27, 2019

Thank you for the compass I was looking for the same. But on the real device, it is getting fluctuated and the values also are unstable. Please help me out. Also tried Low Pass Filter as per the stack solution https://stackoverflow.com/questions/57308560/smooth-orientation-compass-using-react-native-sensorss-magnetometer.

The following added screen is of stable device.

ezgif com-video-to-gif

@rahulhaque
Copy link
Owner

Please, check the latest commit and test it out to see if the issue still exists. It's been a while I got the chance to look into this project. Also I've posted an answer on Stackoverflow. Please check and accept the answer if it helps.

@kenwoolf
Copy link

The problem is with LPF in the _angle method. When magnetometer's "y" goes from positive values to negative rapidly, the LPF.next() recieves greatly different values. Some close to 0 degrees, some close to 360. So the input to LPF might look somthing like this: 0, 357, 2, 350 etc. It can't keep up. And that's why the image starts to oscillate.

@huzaima1298
Copy link

Any solution for this? how to solve?

@kenwoolf
Copy link

kenwoolf commented May 7, 2020

I have introduced hysteresis like behavior into the response. Added the _hysteresis method for that. But I have also changed a few other things, like inside the _angle method I simply return the atan with an angle between -180 to 180. I don't rotate it to be between 0-360. And the subscription is expo based. I have also edited the compass image, so that North is pointing to the right side on it, this way I don't have to rotate it with another 90 degrees inside the code. So don't just copy that one method, cause it won't work like that with original code. :D

import React, { Component } from "react";
import { View, StyleSheet, Dimensions, Image } from "react-native";
import { Magnetometer } from "expo-sensors";
import LPF from "lpf";

let ScreenHeight = Dimensions.get("window").height;

class CompassPointer extends Component\<{}, { degree: number }\> {

    _magnetometerSubscription;

    constructor(props) {
        super(props);
        this.state = {
            degree: 0
        };
        LPF.init([]);
        LPF.smoothing = 0.2;
    };

    componentDidMount() {
        this._subscribe();
    }

    componentWillUnmount() {
        this._unsubscribe();
    };


    _subscribe = async () => {
        if (Magnetometer.isAvailableAsync()) {
            Magnetometer.setUpdateInterval(16);
            this._magnetometerSubscription = Magnetometer.addListener(sensorData => {
                this.setState({ degree: this._angle(sensorData) });
            });
        } else {
            console.log("Magnetometer not available!");
        }
    };

    _unsubscribe = () => {
        this._magnetometerSubscription.remove();
        this._magnetometerSubscription = null;
    };

    _angle = magnetometer => {
        let angle = 0;
        if (magnetometer) {
            let { x, y } = magnetometer;
            angle = Math.atan2(y, x) * (180 / Math.PI);
        }
        return Math.round(LPF.next(this._hysteresis(angle)));
    };

    _hysteresis = angle => {
        if (Math.abs(this.state.degree - angle) >= 180) {
            if (angle >= 0) {
                return angle - 360;
            }
            if (angle < 0) {
                return 360 + angle;
            }
        } else {
            return angle;
        }
    }

    render() {
        return (
            <View>
                <Image style={[this.styles.compassImage,
                { transform: [{ rotate: 360 - this.state.degree + "deg" }] }]}
                    source={require("../../../assets/compass.jpg")} />
            </View>
        )
    }

    styles = StyleSheet.create({
        compassImage: {
            width: ScreenHeight / 4,
            height: ScreenHeight / 4,
            borderRadius: ScreenHeight / 8
        }
    });
}
export default CompassPointer;

This can still become unstable for a second if you turn it around too much.

@huzaima1298
Copy link

Please, check the latest commit and test it out to see if the issue still exists. It's been a while I got the chance to look into this project. Also I've posted an answer on Stackoverflow. Please check and accept the answer if it helps.

it is still the same. even my App hangs after i nevigate to compass

@rahulhaque rahulhaque added enhancement New feature or request help wanted Extra attention is needed labels Jun 27, 2020
@hani-q
Copy link

hani-q commented Aug 14, 2021

The problem is with LPF in the _angle method. When magnetometer's "y" goes from positive values to negative rapidly, the LPF.next() recieves greatly different values. Some close to 0 degrees, some close to 360. So the input to LPF might look somthing like this: 0, 357, 2, 350 etc. It can't keep up. And that's why the image starts to oscillate.

Is there any method to flush the LPF and start a new when it approaches 0 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

5 participants