I'm making my first Android application. As a toy problem to learn the system I want to make a simple app that display as text which direction the phone is pointing using the built in compass.
How do I access the compass from my code, and have my code be aware of direction changes?
I believe I'll need the SensorManager class but I'm confused how to use it. How do I tell it I want the compass sensor? How do I tell it to do an action (update text) on a direction change?
// First, get an instance of the SensorManager
SensorManager sMan = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
// Second, get the sensor you're interested in
Sensor magnetField = sMan.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
// Third, implement a SensorEventListener class
SensorEventListener magnetListener = new SensorEventListener() {
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// do things if you're interested in accuracy changes
}
public void onSensorChanged(SensorEvent event) {
// implement what you want to do here
}
};
// Finally, register your listener
sMan.registerListener(magnetListener, magnetField, SensorManager.SENSOR_DELAY_NORMAL);
However, please note that this is actually a magnetic sensor; therefore if you have magnetic interference around you, it may be pointing to the wrong direction. Also, you need to know the difference between True North and Magnetic North. Since this code uses magnetic sensor, you obtain the Magnetic North, but if you need to calculate the True North, you would need to do some adjustments with GeomagneticField.getDeclination().
Have a look at the API demos. There is an application that has already been written which access the compass and accelerometer. Maybe that will give you a better idea on how you can go about your task.
you shall find it in:
/android-sdk-linux_86/samples/android-8/ApiDemos/src/com/example/android/apis/os/sensor.java
hope it helps.
First you should check if a compass sensor is present on the system
PackageManager m = getPackageManager();
if(!m.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)) {
Log.d("COMPASS_SENSOR", "Device has no compass");
}
Related
Most smartphones feature a 3-axis Gyroscope, a 3-axis magnetometer and a 3-axis accelerometer. Combining these sensors' measurements in a clever way (Kalman filter) should yield a fast, accurate, noise free and absolute device orientation. This could be stored as a quaternion or yaw/pitch/roll values.
What is the simplest way to achieve this in Android? Does the operating system already do those calculations for you? Are there open source implementations that one could use?
Most examples/tutorials I could find only focus on one type of sensor. But for my use case only the fusion of all three sensors via proper filtering would be of interest...
You need to implements SensorEventListener interface.
and in your class you must declare these :
Sensor sensor;
SensorManager sensorManager;
and override these methods:
public void onAccuracyChanged(Sensor sensor,int accuracy)
{
}
public void onSensorChanged(SensorEvent event)
{
}
and in constructor of your class(Activity or...)
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
sensorManager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_GAME);
i want to get and move needle on co-ordinates as per user rotates or move device as compass does also as this app is doing already.you can see what i want to say on this link https://play.google.com/store/apps/details?id=com.plaincode.clinometer&hl=en but now at this time i am not able to understand on this context. i am unable to find hint for how to start..is their is any api to get and make it work or need to implement accelerometer on a very extensive level to get it done. please guide me if u have any code or link regarding this..thank in advance
I was looking for this solution more than a year ago and for that somehow i managed to do this similar this way. and source for that which i managed to do is -- link to source
You should start creating an activity that implements SensorEventListener, including the two following methods:
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// add your code
// event.values[] contains the 3 accelerometer values
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
// add your code
}
As second step, start with the implementation of accelerometers into the Activity:
private SensorManager mSensorManager;
private Sensor mRotationSensor;
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Then register a sensor listener on it (you could do in onResume):
mSensorManager.registerListener(this, mRotationSensor, 16000);
// 16000 microseconds
and unregister it (in onPause):
mSensorManager.unregisterListener(this);
Please note that, if you want a very accurate measurement of angles and slopes in the 3 dimensions, you should implement a calibration routine of the onboard accelerometers, that usually need a small compensation in gain, offset and angle.
You can read a simple but complete usage of Accelerometers on the free and opensource BasicAirData Clinometer: https://github.com/BasicAirData/Clinometer
The app includes also a calibration routine.
I am developing a application which needs a new acceleration datum every 10 millisecond. And i need to save the data into a files. Can anyone give me some android accelerometer example codes as reference? Thanks very much.
Read up on the SensorManager to learn how to get accelerometer data:
http://developer.android.com/reference/android/hardware/SensorManager.html
You can access the SensorManager straight from your application context.
SensorManager manager = (SensorManager) context.getSystemService(Context.SensorManager);
Then you register a SensorEventListener, the sensor you want to listen to, and the rate. The SensorManager class provides constants for the refresh rate. For your purposes, SENSOR_DELAY_GAME might be fast enough, but I feel like SENSOR_DELAY_FASTEST is a safer bet. To my knowledge, there's no hard numbers on the rates of the defaults, so just see what works best.
Sensor accel = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
manager.registerListener(new MySensorEventListener(), accel, SensorManager.SENSOR_DELAY_GAME);
Then, every time a new event is polled from the accelerometer, it will call the listener's onSensorChanged method:
public class MySensorEventListener implements SensorEventListener {
#Override
public void onSensorChanged(SensorEvent event) {
// do what you need to do with the data from event
}
}
my android application shows the direction of a particular place in the world and therefore in needs to get the compass degree.
This is the code I've been using to calculate the degrees:
public void getDirection() {
mySensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
List<Sensor> mySensors = mySensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
if(mySensors.size() > 0){
mySensorManager.registerListener(mySensorEventListener, mySensors.get(0), SensorManager.SENSOR_DELAY_UI);
}
else{
TextView alert = (TextView)findViewById(R.id.instruct);
alert.setText(getString(R.string.direction_not_found));
myCompassView.setVisibility(myCompassView.INVISIBLE);
}
}
private SensorEventListener mySensorEventListener = new SensorEventListener(){
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
compassBearing = (float)event.values[0];
float bearing;
bearing = compassBearing - templeBearing;
if (bearing < 0)
bearing = 360 + bearing;
myCompassView.updateDirection(bearing);
}
};
This method usually works but sometimes it just gets the wrong north, what do I have to do to get a more accurate location?
I have a couple suggestions for you:
1) Your device may not be calibrated. In order to do it, move it around in a form of 8 (see this). If you don't if your device is calibrated or not make some tests by pointing the device at some known cardinal point direction and compare the values. Typically, if a device is not calibrated, you will see great variations in the azimuth value for small rotations. That is what I would be worried about.
Now, don't forget that the sensor gives you the bearing to Magnetic North, and not True North! This difference is known as declination of the magnetic field and its value changes from place to place and from time to time due to changes in Earth's magnetic field. This app can compute some of the values for you with relative accuracy. I wouldn't be too much worried about this as the declination is typically small, but you might be looking for good precision (where I live the declination is 3º, currently).
2) Stay away from metal objects or stuff that generate a strong magnetic field. For example, don't do tests if you have your phone near the computer or any physical keyboards! This is pure poison for testing compass-geolocation. Some apps can measure the intensity of the magnetic field (if the device supports it). When you get closer to metal stuff you will experience higher values and strong changes in directions. For fun, there are also some "metal detectors": this app recognises changes in the magnetic field and vibrates when you are close "metal object" or stuff that magnetically interfere with the device.
3) Remember to update the bearing when you tilt your device to landscape mode. (article is a must read!) This is because azimuth value is based on the rotation of the perpendicular axis to the plane of the phone. When you rotate the device to landscape, this value is changed by +/-90º! This is not resolved by disabling the application landscape mode! You will have to determine it programmatically by analysing rotations around the other two axis (pitch and roll). This is not trivial, but there are some examples somewhere in the net.
edit: If you are interested in some code, check out Mixare, it is an open source augmented reality framework under the GPL3 for Android. Take a look at their code regarding orientation, compass geolocation and bearing.
PS: I don't have any sort of connection with the creators of the mentioned applications.
I am developing an android app for my project, I need to find room temperature as part of it. I am using Droid 2 A955 model for testing.
My Questions are:
What sensors need to be available in my Android phone to perform
this temperature sensing task?
Can Ambient Light Sensor (available in Droid 2) help in doing this
task?
Is there any Android api to find/sense room temperature
programmatically in my android code?
Thanks in advance for your help.
To answer all three of your questions in one fell swoop, no, I don't believe so. There can be a temperature sensor in android devices, but it senses the temperature of the battery, not the outside temperature. It would not provide an accurate gauge for that purpose.
I'm not sure how an ambient light sensor would help with temperature, it can be very bright out but it could be in an air conditioned room.
Lastly: there are lots of examples of temperature apps, but again, most are related to the battery.
Edit: Official documentation says:
Device implementations MAY but SHOULD NOT include a thermometer (i.e. temperature sensor.) If a device implementation does include a
thermometer, it MUST measure the temperature of the device CPU. It MUST NOT measure any other temperature. (Note that this sensor type is
deprecated in the Android 2.3 APIs.)
Update:
API level 14 (i.e. Android 4.0) onwards, support for measuring ambient temperature has been added (via TYPE_AMBIENT_TEMPERATURE). [Android doc reference]
This, however, will work only on devices with ambient temperature sensor.
It seems that there is a new sensor in the API.
This one is for the ambient temperature, but probably there are just a few devices with this implemented.
UPDATE: it seems that the Galaxy S4 is the first phone integrating ambient temperature sensor
You'll want to check out the Sensor reference docs. Offhand, I don't think there are accessible temperature sensors on-board most handhelds though.
Take a look at the Sensor class in the documentation.
You need to do something along the lines of this:
public class SensorActivity extends Activity, implements SensorEventListener {
private final SensorManager mSensorManager;
private final Sensor mTemp;
public SensorActivity() {
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mtemp = mSensorManager.getDefaultSensor(Sensor.TYPE_TEMPERATURE);
}
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, mTemp, SensorManager.SENSOR_DELAY_NORMAL);
}
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void onSensorChanged(SensorEvent event) {
}
}
This should give you access to the temperature sensors in it's own activity.
Play with this and see what you can find. The documentation has great examples for other types of sensors, the temp sensor should be even simpler than most of the provided ones.
Hope this helps!
You can use the iCelsius Wireless from Kickstarter. It has an API. It is impossible to measure accurately temperature using an internal sensor from a SmartPhone. It will always be few degree to high.
i have same your question long time ago. And what my found is :
check this offical site for Environment sensor
this tuts for environment sensor : Ambient Temperature (room temp) Ambient Light ... Tutsplus. on my phone only Ambient Light work
now as i know only samsung galaxy S4 have Ambient Temperature. if you have S4 search Holo Ambient Temperature on gg playstore .
this sounds interesting:
http://developer.android.com/reference/android/hardware/Sensor.html#TYPE_AMBIENT_TEMPERATURE
from API >= 13
There is the age old method of letting the phone and a "good" thermometer stabilize at room temperature (a few hours) and read both.
Then put it outside in a nice wintry garage at about 35F let it stabilize. Then pray for linearity.
Empirical is always nice. I am very interested in measuring a constant temperature in an empty house, and watch for the temperature dropping (or rising!!)
Bradshaw at Buzzards Bay
Try this one:
private float temperature = 0;
In onCreate put wìthis code:
SensorManager mySensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor AmbientTemperatureSensor
= mySensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE);
if (AmbientTemperatureSensor != null) {
mySensorManager.registerListener(
AmbientTemperatureSensorListener,
AmbientTemperatureSensor,
SensorManager.SENSOR_DELAY_NORMAL);
}
And the method below:
private final SensorEventListener AmbientTemperatureSensorListener
= new SensorEventListener() {
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_AMBIENT_TEMPERATURE) {
temperature = event.values[0];
}
}
};