├── AndroidManifest.xml ├── README ├── build.gradle ├── build.xml ├── buildAll.sh ├── local.properties ├── mainpage.dox ├── manifest.xml ├── proguard-project.txt ├── project.properties ├── res ├── layout │ └── main.xml └── values │ └── strings.xml └── src └── org └── ros └── android └── android_sensors_driver ├── ImuPublisher.java ├── MainActivity.java └── NavSatFixPublisher.java /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Authors: 2 | chadrockey@gmail.com (Chad Rockey) 3 | axelfurlan@gmail.com (Axel Furlan) 4 | 5 | This is an extension to the first version of the Ros Android Sensors Driver. 6 | It extends the driver to camera readings and updates the previous version to the post-gradle shift of the rosjava libs. 7 | Two compression methods are currently supported, PNG and JPEG (with selectable compression quality). 8 | The topic names are: 9 | 10 | /android/imu 11 | /android/fix (GPS) 12 | /camera/camera_info 13 | /camera/image/compressed 14 | 15 | 16 | 17 | 18 | Compiling: 19 | 20 | To compile it on you machine, please follow the detailed instructions at: 21 | 22 | Rosjava: 23 | http://www.dobots.nl/blog/-/blogs/android-and-rosjava 24 | 25 | Once your environment is set, do the following steps: 26 | 1) git clone the repo in the android_core folder (the same folder where tutorials are). 27 | 2) Edit the settings.gradle file in the android_core folder, adding 'android_sensors_driver' at the end of the include list. 28 | 3) cd android_sensors_driver; ../gradlew clean debug 29 | 30 | For the whole process of building, packing, installing into the phone and running the app in debug mode, use the buildAll.sh script. -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | dependencies { 18 | compile 'ros.rosjava_core:rosjava_tutorial_pubsub:0.0.0-SNAPSHOT' 19 | } 20 | 21 | 22 | debug.dependsOn project(':android_gingerbread_mr1').tasks.debug 23 | 24 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 29 | 30 | 31 | 40 | 41 | 42 | 43 | 47 | 48 | 60 | 61 | 62 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /buildAll.sh: -------------------------------------------------------------------------------- 1 | # Bash 2 | 3 | ../gradlew clean debug 4 | if [ $? -eq 0 ] 5 | then 6 | adb uninstall org.ros.android.android_sensors_driver 7 | adb install bin/MainActivity-debug.apk 8 | adb shell am start -n org.ros.android.android_sensors_driver/org.ros.android.android_sensors_driver.MainActivity 9 | adb logcat -c 10 | adb logcat 11 | fi 12 | -------------------------------------------------------------------------------- /local.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must *NOT* be checked into Version Control Systems, 5 | # as it contains information specific to your local configuration. 6 | 7 | # location of the SDK. This is only used by Ant 8 | # For customization when using a Version Control System, please read the 9 | # header note. 10 | sdk.dir=/home/willow/NVPACK/android-sdk-linux 11 | -------------------------------------------------------------------------------- /mainpage.dox: -------------------------------------------------------------------------------- 1 | /** 2 | \mainpage 3 | \htmlinclude manifest.html 4 | 5 | \b android_sensors_driver is ... 6 | 7 | 10 | 11 | 12 | \section codeapi Code API 13 | 14 | 24 | 25 | 26 | */ 27 | -------------------------------------------------------------------------------- /manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | android_sensors_driver 4 | 5 | Chad Rockey (chadrockey@gmail.com) 6 | Apache 2.0 7 | 8 | http://ros.org/wiki/android_sensors_driver 9 | 10 | -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system use, 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | 10 | # Project target. 11 | target=android-13 12 | #android.library=true 13 | android.library.reference.1=../android_gingerbread_mr1 14 | android.library.reference.2=../../OpenCV-2.4.2-android-sdk/sdk/java 15 | -------------------------------------------------------------------------------- /res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 17 | 18 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ROS Android Sensors Driver 4 | 5 | -------------------------------------------------------------------------------- /src/org/ros/android/android_sensors_driver/ImuPublisher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Chad Rockey 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of the Android Sensors Driver nor the names of its 14 | * contributors may be used to endorse or promote products derived from 15 | * this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | package org.ros.android.android_sensors_driver; 31 | 32 | 33 | import java.util.List; 34 | 35 | import android.hardware.Sensor; 36 | import android.hardware.SensorEvent; 37 | import android.hardware.SensorEventListener; 38 | import android.hardware.SensorManager; 39 | import android.os.Looper; 40 | import android.os.SystemClock; 41 | 42 | import org.ros.node.ConnectedNode; 43 | import org.ros.message.Time; 44 | import org.ros.namespace.GraphName; 45 | import sensor_msgs.Imu; 46 | import org.ros.node.Node; 47 | import org.ros.node.NodeMain; 48 | import org.ros.node.topic.Publisher; 49 | 50 | /** 51 | * @author chadrockey@gmail.com (Chad Rockey) 52 | * @author axelfurlan@gmail.com (Axel Furlan) 53 | */ 54 | public class ImuPublisher implements NodeMain 55 | { 56 | 57 | private ImuThread imuThread; 58 | private SensorListener sensorListener; 59 | private SensorManager sensorManager; 60 | private Publisher publisher; 61 | 62 | private class ImuThread extends Thread 63 | { 64 | private final SensorManager sensorManager; 65 | private SensorListener sensorListener; 66 | private Looper threadLooper; 67 | 68 | private final Sensor accelSensor; 69 | private final Sensor gyroSensor; 70 | private final Sensor quatSensor; 71 | 72 | private ImuThread(SensorManager sensorManager, SensorListener sensorListener) 73 | { 74 | this.sensorManager = sensorManager; 75 | this.sensorListener = sensorListener; 76 | this.accelSensor = this.sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 77 | this.gyroSensor = this.sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); 78 | this.quatSensor = this.sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); 79 | } 80 | 81 | 82 | public void run() 83 | { 84 | Looper.prepare(); 85 | this.threadLooper = Looper.myLooper(); 86 | this.sensorManager.registerListener(this.sensorListener, this.accelSensor, SensorManager.SENSOR_DELAY_FASTEST); 87 | this.sensorManager.registerListener(this.sensorListener, this.gyroSensor, SensorManager.SENSOR_DELAY_FASTEST); 88 | this.sensorManager.registerListener(this.sensorListener, this.quatSensor, SensorManager.SENSOR_DELAY_FASTEST); 89 | Looper.loop(); 90 | } 91 | 92 | 93 | public void shutdown() 94 | { 95 | this.sensorManager.unregisterListener(this.sensorListener); 96 | if(this.threadLooper != null) 97 | { 98 | this.threadLooper.quit(); 99 | } 100 | } 101 | } 102 | 103 | private class SensorListener implements SensorEventListener 104 | { 105 | 106 | private Publisher publisher; 107 | 108 | private boolean hasAccel; 109 | private boolean hasGyro; 110 | private boolean hasQuat; 111 | 112 | private long accelTime; 113 | private long gyroTime; 114 | private long quatTime; 115 | 116 | private Imu imu; 117 | 118 | private SensorListener(Publisher publisher, boolean hasAccel, boolean hasGyro, boolean hasQuat) 119 | { 120 | this.publisher = publisher; 121 | this.hasAccel = hasAccel; 122 | this.hasGyro = hasGyro; 123 | this.hasQuat = hasQuat; 124 | this.accelTime = 0; 125 | this.gyroTime = 0; 126 | this.quatTime = 0; 127 | this.imu = this.publisher.newMessage(); 128 | } 129 | 130 | // @Override 131 | public void onAccuracyChanged(Sensor sensor, int accuracy) 132 | { 133 | } 134 | 135 | // @Override 136 | public void onSensorChanged(SensorEvent event) 137 | { 138 | if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) 139 | { 140 | this.imu.getLinearAcceleration().setX(event.values[0]); 141 | this.imu.getLinearAcceleration().setY(event.values[1]); 142 | this.imu.getLinearAcceleration().setZ(event.values[2]); 143 | 144 | double[] tmpCov = {0.01,0,0, 0,0.01,0, 0,0,0.01};// TODO Make Parameter 145 | this.imu.setLinearAccelerationCovariance(tmpCov); 146 | this.accelTime = event.timestamp; 147 | } 148 | else if(event.sensor.getType() == Sensor.TYPE_GYROSCOPE) 149 | { 150 | this.imu.getAngularVelocity().setX(event.values[0]); 151 | this.imu.getAngularVelocity().setY(event.values[1]); 152 | this.imu.getAngularVelocity().setZ(event.values[2]); 153 | double[] tmpCov = {0.0025,0,0, 0,0.0025,0, 0,0,0.0025};// TODO Make Parameter 154 | this.imu.setAngularVelocityCovariance(tmpCov); 155 | this.gyroTime = event.timestamp; 156 | } 157 | else if(event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) 158 | { 159 | float[] quaternion = new float[4]; 160 | SensorManager.getQuaternionFromVector(quaternion, event.values); 161 | this.imu.getOrientation().setW(quaternion[0]); 162 | this.imu.getOrientation().setX(quaternion[1]); 163 | this.imu.getOrientation().setY(quaternion[2]); 164 | this.imu.getOrientation().setZ(quaternion[3]); 165 | double[] tmpCov = {0.001,0,0, 0,0.001,0, 0,0,0.001};// TODO Make Parameter 166 | this.imu.setOrientationCovariance(tmpCov); 167 | this.quatTime = event.timestamp; 168 | } 169 | 170 | // Currently storing event times in case I filter them in the future. Otherwise they are used to determine if all sensors have reported. 171 | if((this.accelTime != 0 || !this.hasAccel) && (this.gyroTime != 0 || !this.hasGyro) && (this.quatTime != 0 || !this.hasQuat)) 172 | { 173 | // Convert event.timestamp (nanoseconds uptime) into system time, use that as the header stamp 174 | long time_delta_millis = System.currentTimeMillis() - SystemClock.uptimeMillis(); 175 | this.imu.getHeader().setStamp(Time.fromMillis(time_delta_millis + event.timestamp/1000000)); 176 | this.imu.getHeader().setFrameId("/imu");// TODO Make parameter 177 | 178 | publisher.publish(this.imu); 179 | 180 | // Create a new message 181 | this.imu = this.publisher.newMessage(); 182 | 183 | // Reset times 184 | this.accelTime = 0; 185 | this.gyroTime = 0; 186 | this.quatTime = 0; 187 | } 188 | } 189 | } 190 | 191 | 192 | public ImuPublisher(SensorManager manager) 193 | { 194 | this.sensorManager = manager; 195 | } 196 | 197 | public GraphName getDefaultNodeName() 198 | { 199 | return GraphName.of("android_sensors_driver/imuPublisher"); 200 | } 201 | 202 | public void onError(Node node, Throwable throwable) 203 | { 204 | } 205 | 206 | public void onStart(ConnectedNode node) 207 | { 208 | try 209 | { 210 | this.publisher = node.newPublisher("android/imu", "sensor_msgs/Imu"); 211 | // Determine if we have the various needed sensors 212 | boolean hasAccel = false; 213 | boolean hasGyro = false; 214 | boolean hasQuat = false; 215 | 216 | List accelList = this.sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER); 217 | 218 | if(accelList.size() > 0) 219 | { 220 | hasAccel = true; 221 | } 222 | 223 | List gyroList = this.sensorManager.getSensorList(Sensor.TYPE_GYROSCOPE); 224 | if(gyroList.size() > 0) 225 | { 226 | hasGyro = true; 227 | } 228 | 229 | List quatList = this.sensorManager.getSensorList(Sensor.TYPE_ROTATION_VECTOR); 230 | if(quatList.size() > 0) 231 | { 232 | hasQuat = true; 233 | } 234 | 235 | this.sensorListener = new SensorListener(publisher, hasAccel, hasGyro, hasQuat); 236 | this.imuThread = new ImuThread(this.sensorManager, sensorListener); 237 | this.imuThread.start(); 238 | } 239 | catch (Exception e) 240 | { 241 | if (node != null) 242 | { 243 | node.getLog().fatal(e); 244 | } 245 | else 246 | { 247 | e.printStackTrace(); 248 | } 249 | } 250 | } 251 | 252 | //@Override 253 | public void onShutdown(Node arg0) 254 | { 255 | this.imuThread.shutdown(); 256 | 257 | try 258 | { 259 | this.imuThread.join(); 260 | } 261 | catch (InterruptedException e) 262 | { 263 | e.printStackTrace(); 264 | } 265 | } 266 | 267 | //@Override 268 | public void onShutdownComplete(Node arg0) 269 | { 270 | } 271 | 272 | } 273 | 274 | -------------------------------------------------------------------------------- /src/org/ros/android/android_sensors_driver/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.ros.android.android_sensors_driver; 18 | 19 | import android.content.Context; 20 | import android.hardware.SensorManager; 21 | import android.location.LocationManager; 22 | import android.os.Bundle; 23 | import android.util.Log; 24 | import android.view.Menu; 25 | import android.view.MenuItem; 26 | import android.view.SubMenu; 27 | import android.view.Window; 28 | import android.view.WindowManager; 29 | import org.ros.address.InetAddressFactory; 30 | import org.ros.android.RosActivity; 31 | import org.ros.node.NodeConfiguration; 32 | import org.ros.node.NodeMainExecutor; 33 | 34 | /** 35 | * @author chadrockey@gmail.com (Chad Rockey) 36 | * @author axelfurlan@gmail.com (Axel Furlan) 37 | */ 38 | 39 | 40 | public class MainActivity extends RosActivity 41 | { 42 | 43 | 44 | private NavSatFixPublisher fix_pub; 45 | private ImuPublisher imu_pub; 46 | 47 | private LocationManager mLocationManager; 48 | private SensorManager mSensorManager; 49 | 50 | 51 | public MainActivity() 52 | { 53 | super("Ros Android Sensors Driver", "Ros Android Sensors Driver"); 54 | } 55 | 56 | @Override 57 | protected void onPause() 58 | { 59 | super.onPause(); 60 | } 61 | 62 | @Override 63 | protected void onCreate(Bundle savedInstanceState) 64 | { 65 | super.onCreate(savedInstanceState); 66 | //requestWindowFeature(Window.FEATURE_NO_TITLE); 67 | //getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 68 | setContentView(R.layout.main); 69 | 70 | mLocationManager = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE); 71 | mSensorManager = (SensorManager)this.getSystemService(SENSOR_SERVICE); 72 | } 73 | 74 | @Override 75 | protected void onResume() 76 | { 77 | super.onResume(); 78 | } 79 | 80 | @Override 81 | public boolean onCreateOptionsMenu(Menu menu) { 82 | 83 | /*SubMenu subPreview = menu.addSubMenu("Color settings"); 84 | subPreview.add(1,VIEW_MODE_RGBA,0,"RGB Color").setChecked(true); 85 | subPreview.add(1,VIEW_MODE_GRAY,0,"Grayscale"); 86 | subPreview.add(1,VIEW_MODE_CANNY,0,"Canny edges"); 87 | subPreview.setGroupCheckable(1, true, true); 88 | 89 | SubMenu subCompression = menu.addSubMenu("Compression"); 90 | // subCompression.add(2,IMAGE_TRANSPORT_COMPRESSION_NONE,0,"None"); 91 | subCompression.add(2,IMAGE_TRANSPORT_COMPRESSION_PNG,0,"Png"); 92 | 93 | SubMenu subCompressionRate = subCompression.addSubMenu(2,IMAGE_TRANSPORT_COMPRESSION_JPEG,0,"Jpeg"); 94 | subCompression.setGroupCheckable(2, true, true); 95 | subCompressionRate.setHeaderTitle("Compression quality"); 96 | subCompressionRate.getItem().setChecked(true); 97 | subCompressionRate.add(3,50,0,"50"); 98 | subCompressionRate.add(3,60,0,"60"); 99 | subCompressionRate.add(3,70,0,"70"); 100 | subCompressionRate.add(3,80,0,"80").setChecked(true); 101 | subCompressionRate.add(3,90,0,"90"); 102 | subCompressionRate.add(3,100,0,"100"); 103 | subCompressionRate.setGroupCheckable(3, true, true);*/ 104 | 105 | return true; 106 | } 107 | 108 | @Override 109 | public boolean onOptionsItemSelected(MenuItem item) 110 | { 111 | /*if(item.getGroupId() == 1) 112 | { 113 | viewMode = item.getItemId(); 114 | item.setChecked(true); 115 | } 116 | 117 | if(item.getGroupId() == 2) 118 | { 119 | imageCompression = item.getItemId(); 120 | item.setChecked(true); 121 | } 122 | 123 | if(item.getGroupId() == 3) 124 | { 125 | imageCompressionQuality = item.getItemId(); 126 | item.setChecked(true); 127 | }*/ 128 | return true; 129 | } 130 | 131 | @Override 132 | protected void init(NodeMainExecutor nodeMainExecutor) 133 | { 134 | NodeConfiguration nodeConfiguration2 = NodeConfiguration.newPublic(InetAddressFactory.newNonLoopback().getHostAddress()); 135 | nodeConfiguration2.setMasterUri(getMasterUri()); 136 | nodeConfiguration2.setNodeName("android_sensors_driver_nav_sat_fix"); 137 | this.fix_pub = new NavSatFixPublisher(mLocationManager); 138 | nodeMainExecutor.execute(this.fix_pub, nodeConfiguration2); 139 | 140 | NodeConfiguration nodeConfiguration3 = NodeConfiguration.newPublic(InetAddressFactory.newNonLoopback().getHostAddress()); 141 | nodeConfiguration3.setMasterUri(getMasterUri()); 142 | nodeConfiguration3.setNodeName("android_sensors_driver_imu"); 143 | this.imu_pub = new ImuPublisher(mSensorManager); 144 | nodeMainExecutor.execute(this.imu_pub, nodeConfiguration3); 145 | 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/org/ros/android/android_sensors_driver/NavSatFixPublisher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Chad Rockey 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of the Android Sensors Driver nor the names of its 14 | * contributors may be used to endorse or promote products derived from 15 | * this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | package org.ros.android.android_sensors_driver; 31 | 32 | import android.location.Location; 33 | import android.location.LocationListener; 34 | import android.location.LocationManager; 35 | import android.location.LocationProvider; 36 | import android.os.Bundle; 37 | import android.os.Looper; 38 | 39 | import org.ros.namespace.GraphName; 40 | import org.ros.node.ConnectedNode; 41 | import org.ros.message.Time; 42 | import sensor_msgs.NavSatFix; 43 | import sensor_msgs.NavSatStatus; 44 | import org.ros.node.Node; 45 | import org.ros.node.NodeMain; 46 | import org.ros.node.topic.Publisher; 47 | 48 | /** 49 | * @author chadrockey@gmail.com (Chad Rockey) 50 | * @author axelfurlan@gmail.com (Axel Furlan) 51 | */ 52 | public class NavSatFixPublisher implements NodeMain { 53 | 54 | private NavSatThread navSatThread; 55 | private LocationManager locationManager; 56 | private NavSatListener navSatFixListener; 57 | private Publisher publisher; 58 | 59 | private class NavSatThread extends Thread { 60 | LocationManager locationManager; 61 | NavSatListener navSatListener; 62 | private Looper threadLooper; 63 | 64 | private NavSatThread(LocationManager locationManager, NavSatListener navSatListener){ 65 | this.locationManager = locationManager; 66 | this.navSatListener = navSatListener; 67 | } 68 | 69 | public void run() { 70 | Looper.prepare(); 71 | threadLooper = Looper.myLooper(); 72 | this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this.navSatListener); 73 | Looper.loop(); 74 | } 75 | 76 | public void shutdown(){ 77 | this.locationManager.removeUpdates(this.navSatListener); 78 | if(threadLooper != null){ 79 | threadLooper.quit(); 80 | } 81 | } 82 | } 83 | 84 | private class NavSatListener implements LocationListener { 85 | 86 | private Publisher publisher; 87 | 88 | private volatile byte currentStatus; 89 | 90 | private NavSatListener(Publisher publisher) { 91 | this.publisher = publisher; 92 | this.currentStatus = NavSatStatus.STATUS_FIX; // Default to fix until we are told otherwise. 93 | } 94 | 95 | // @Override 96 | public void onLocationChanged(Location location) 97 | { 98 | NavSatFix fix = this.publisher.newMessage(); 99 | fix.getHeader().setStamp(Time.fromMillis(System.currentTimeMillis())); 100 | fix.getHeader().setFrameId("/gps"); 101 | 102 | fix.getStatus().setStatus(currentStatus); 103 | fix.getStatus().setService(NavSatStatus.SERVICE_GPS); 104 | 105 | fix.setLatitude(location.getLatitude()); 106 | fix.setLongitude(location.getLongitude()); 107 | fix.setAltitude(location.getAltitude()); 108 | fix.setPositionCovarianceType(NavSatFix.COVARIANCE_TYPE_APPROXIMATED); 109 | double deviation = location.getAccuracy(); 110 | double covariance = deviation*deviation; 111 | double[] tmpCov = {covariance,0,0, 0,covariance,0, 0,0,covariance}; 112 | fix.setPositionCovariance(tmpCov); 113 | publisher.publish(fix); 114 | } 115 | 116 | // @Override 117 | public void onProviderDisabled(String provider) { 118 | } 119 | 120 | // @Override 121 | public void onProviderEnabled(String provider) { 122 | } 123 | 124 | // @Override 125 | public void onStatusChanged(String provider, int status, Bundle extras) { 126 | switch (status) { 127 | case LocationProvider.OUT_OF_SERVICE: 128 | currentStatus = NavSatStatus.STATUS_NO_FIX; 129 | break; 130 | case LocationProvider.TEMPORARILY_UNAVAILABLE: 131 | currentStatus = NavSatStatus.STATUS_NO_FIX; 132 | break; 133 | case LocationProvider.AVAILABLE: 134 | currentStatus = NavSatStatus.STATUS_FIX; 135 | break; 136 | } 137 | } 138 | } 139 | 140 | public NavSatFixPublisher(LocationManager manager) { 141 | this.locationManager = manager; 142 | } 143 | 144 | //@Override 145 | public void onStart(ConnectedNode node) 146 | { 147 | try 148 | { 149 | this.publisher = node.newPublisher("android/fix", "sensor_msgs/NavSatFix"); 150 | this.navSatFixListener = new NavSatListener(publisher); 151 | this.navSatThread = new NavSatThread(this.locationManager, this.navSatFixListener); 152 | this.navSatThread.start(); 153 | } 154 | catch (Exception e) 155 | { 156 | if (node != null) 157 | { 158 | node.getLog().fatal(e); 159 | } 160 | else 161 | { 162 | e.printStackTrace(); 163 | } 164 | } 165 | } 166 | 167 | //@Override 168 | public void onShutdown(Node arg0) { 169 | this.navSatThread.shutdown(); 170 | try { 171 | this.navSatThread.join(); 172 | } catch (InterruptedException e) { 173 | e.printStackTrace(); 174 | } 175 | } 176 | 177 | //@Override 178 | public void onShutdownComplete(Node arg0) { 179 | } 180 | 181 | public GraphName getDefaultNodeName() 182 | { 183 | return GraphName.of("android_sensors_driver/imuPublisher"); 184 | } 185 | 186 | public void onError(Node node, Throwable throwable) 187 | { 188 | } 189 | 190 | } 191 | --------------------------------------------------------------------------------