Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 package com.github.turtlebot.turtlebot_android.turtlebot_core;
00036
00037 import java.util.HashMap;
00038 import java.util.List;
00039
00040 import com.github.rosjava.android_apps.application_management.Dashboard.DashboardInterface;
00041 import com.github.rosjava.android_extras.gingerbread.view.BatteryLevelView;
00042 import org.ros.exception.RemoteException;
00043 import org.ros.exception.RosException;
00044 import org.ros.message.MessageListener;
00045 import org.ros.namespace.GraphName;
00046 import org.ros.namespace.NameResolver;
00047 import org.ros.node.ConnectedNode;
00048 import org.ros.node.Node;
00049 import org.ros.node.service.ServiceClient;
00050 import org.ros.node.service.ServiceResponseListener;
00051 import org.ros.node.topic.Subscriber;
00052
00053 import create_node.SetDigitalOutputsRequest;
00054 import create_node.SetDigitalOutputsResponse;
00055 import create_node.SetTurtlebotModeRequest;
00056 import create_node.SetTurtlebotModeResponse;
00057 import create_node.TurtlebotSensorState;
00058
00059 import diagnostic_msgs.DiagnosticArray;
00060 import diagnostic_msgs.DiagnosticStatus;
00061 import diagnostic_msgs.KeyValue;
00062
00063 import android.content.Context;
00064 import android.graphics.Color;
00065 import android.util.AttributeSet;
00066 import android.util.Log;
00067 import android.view.LayoutInflater;
00068 import android.view.View;
00069 import android.widget.ImageButton;
00070 import android.widget.LinearLayout;
00071 import android.widget.ProgressBar;
00072 import android.widget.Toast;
00073
00074
00075 public class TurtlebotDashboard extends LinearLayout implements DashboardInterface {
00076 private ImageButton modeButton;
00077 private ProgressBar modeWaitingSpinner;
00078 private BatteryLevelView robotBattery;
00079 private BatteryLevelView laptopBattery;
00080 private ConnectedNode connectedNode;
00081 private Subscriber<diagnostic_msgs.DiagnosticArray> diagnosticSubscriber;
00082 private boolean powerOn = false;
00083 private int numModeResponses;
00084 private int numModeErrors;
00085
00086 public TurtlebotDashboard(Context context) {
00087 super(context);
00088 inflateSelf(context);
00089 }
00090 public TurtlebotDashboard(Context context, AttributeSet attrs) {
00091 super(context, attrs);
00092 inflateSelf(context);
00093 }
00094 private void inflateSelf(Context context) {
00095 LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
00096 inflater.inflate(R.layout.turtlebot_dashboard, this);
00097 modeButton = (ImageButton) findViewById(R.id.mode_button);
00098 modeButton.setOnClickListener(new OnClickListener() {
00099 @Override
00100 public void onClick(View v) {
00101 onModeButtonClicked();
00102 }
00103 });
00104 modeWaitingSpinner = (ProgressBar) findViewById(R.id.mode_waiting_spinner);
00105 modeWaitingSpinner.setIndeterminate(true);
00106 modeWaitingSpinner.setVisibility(View.GONE);
00107 robotBattery = (BatteryLevelView) findViewById(R.id.robot_battery);
00108 laptopBattery = (BatteryLevelView) findViewById(R.id.laptop_battery);
00109 }
00120 private void handleDiagnosticArray(DiagnosticArray msg) {
00121 String mode = null;
00122 for(DiagnosticStatus status : msg.getStatus()) {
00123 if(status.getName().equals("/Power System/Battery")) {
00124 populateBatteryFromStatus(robotBattery, status);
00125 }
00126 if(status.getName().equals("/Power System/Laptop Battery")) {
00127 populateBatteryFromStatus(laptopBattery, status);
00128 }
00129 if(status.getName().equals("/Mode/Operating Mode")) {
00130 mode = status.getMessage();
00131 }
00132 }
00133 showMode(mode);
00134 }
00135
00136
00137 private void onModeButtonClicked() {
00138 powerOn = !powerOn;
00139 SetTurtlebotModeRequest modeRequest = connectedNode.getTopicMessageFactory().newFromType(SetTurtlebotModeRequest._TYPE);
00140 SetDigitalOutputsRequest setDigOutRequest = connectedNode.getTopicMessageFactory().newFromType(SetDigitalOutputsRequest._TYPE);
00141 setDigOutRequest.setDigitalOut1((byte) 0);
00142 setDigOutRequest.setDigitalOut2((byte) 0);
00143 if(powerOn) {
00144 modeRequest.setMode(TurtlebotSensorState.OI_MODE_FULL);
00145 setDigOutRequest.setDigitalOut0((byte) 1);
00146 } else {
00147 modeRequest.setMode(TurtlebotSensorState.OI_MODE_PASSIVE);
00148 setDigOutRequest.setDigitalOut0((byte) 0);
00149 }
00150 setModeWaiting(true);
00151 numModeResponses = 0;
00152 numModeErrors = 0;
00153
00154 try {
00155 ServiceClient<SetTurtlebotModeRequest, SetTurtlebotModeResponse> modeServiceClient = connectedNode.newServiceClient("turtlebot_node/set_operation_mode", "turtlebot_node/SetTurtlebotMode");
00156 modeServiceClient.call(modeRequest, new ServiceResponseListener<SetTurtlebotModeResponse>() {
00157 @Override
00158 public void onSuccess(SetTurtlebotModeResponse message) {
00159 numModeResponses++;
00160 updateModeWaiting();
00161 }
00162 @Override
00163 public void onFailure(RemoteException e) {
00164 numModeResponses++;
00165 numModeErrors++;
00166 updateModeWaiting();
00167 }
00168 });
00169 } catch(Exception ex) {
00170 Toast.makeText(getContext(), "Exception in service call for set_operation_mode: " + ex.getMessage(), Toast.LENGTH_LONG).show();
00171 Log.i("TurtlebotDashboard", "making toast.");
00172 }
00173 try {
00174 ServiceClient<SetDigitalOutputsRequest, SetDigitalOutputsResponse> setDigOutServiceClient = connectedNode.newServiceClient("turtlebot_node/set_digital_outputs", "turtlebot_node/SetDigitalOutputs");
00175 setDigOutServiceClient.call(setDigOutRequest, new ServiceResponseListener<SetDigitalOutputsResponse>() {
00176 @Override
00177 public void onSuccess(final SetDigitalOutputsResponse msg) {
00178 numModeResponses++;
00179 updateModeWaiting();
00180 }
00181 @Override
00182 public void onFailure(RemoteException e) {
00183 numModeResponses++;
00184 numModeErrors++;
00185 updateModeWaiting();
00186 }
00187 });
00188 } catch(Exception ex) {
00189 Toast.makeText(getContext(), "Exception in service call for set_digital_outputs: " + ex.getMessage(), Toast.LENGTH_LONG).show();
00190 Log.i("TurtlebotDashboard", "making toast.");
00191 }
00192 }
00193
00194 private void updateModeWaiting() {
00195 if(numModeResponses >= 2) {
00196 setModeWaiting(false);
00197 }
00198 }
00199 private void setModeWaiting(final boolean waiting) {
00200 post(new Runnable() {
00201 @Override
00202 public void run() {
00203 modeWaitingSpinner.setVisibility(waiting ? View.VISIBLE : View.GONE);
00204 }
00205 });
00206 }
00207 private void showMode(String mode) {
00208 if(mode == null) {
00209 modeButton.setColorFilter(Color.GRAY);
00210 } else if(mode.equals("Full")) {
00211 modeButton.setColorFilter(Color.GREEN);
00212 powerOn = true;
00213 } else if(mode.equals("Safe")) {
00214 modeButton.setColorFilter(Color.YELLOW);
00215 powerOn = true;
00216 } else if(mode.equals("Passive")) {
00217 modeButton.setColorFilter(Color.RED);
00218 powerOn = false;
00219 } else {
00220 modeButton.setColorFilter(Color.GRAY);
00221 Log.w("TurtlebotDashboard", "Unknown mode string: '" + mode + "'");
00222 }
00223 setModeWaiting(false);
00224 }
00225 private void populateBatteryFromStatus(BatteryLevelView view, DiagnosticStatus status) {
00226 HashMap<String, String> values = keyValueArrayToMap(status.getValues());
00227 try {
00228 float percent = 100 * Float.parseFloat(values.get("Charge (Ah)")) / Float.parseFloat(values.get("Capacity (Ah)"));
00229 view.setBatteryPercent((int) percent);
00230
00231
00232
00233 } catch(NumberFormatException ex) {
00234
00235 } catch(ArithmeticException ex) {
00236
00237 } catch(NullPointerException ex) {
00238
00239 }
00240 try {
00241 view.setPluggedIn(Float.parseFloat(values.get("Current (A)")) > 0);
00242 } catch(NumberFormatException ex) {
00243 } catch(ArithmeticException ex) {
00244 } catch(NullPointerException ex) {
00245 }
00246 }
00247 private HashMap<String, String> keyValueArrayToMap(List<KeyValue> list) {
00248 HashMap<String, String> map = new HashMap<String, String>();
00249 for(KeyValue kv : list) {
00250 map.put(kv.getKey(), kv.getValue());
00251 }
00252 return map;
00253 }
00254
00255 @Override
00256 public void onShutdown(Node node) {
00257 if(diagnosticSubscriber != null) {
00258 diagnosticSubscriber.shutdown();
00259 }
00260 diagnosticSubscriber = null;
00261 connectedNode = null;
00262
00263 }
00264
00265 @Override
00266 public void onStart(ConnectedNode connectedNode) {
00267
00268 this.connectedNode = connectedNode;
00269 try {
00270 diagnosticSubscriber = connectedNode.newSubscriber("diagnostics_agg", "diagnostic_msgs/DiagnosticArray");
00271 diagnosticSubscriber.addMessageListener(new MessageListener<diagnostic_msgs.DiagnosticArray>() {
00272 @Override
00273 public void onNewMessage(final diagnostic_msgs.DiagnosticArray message) {
00274 TurtlebotDashboard.this.post(new Runnable() {
00275 @Override
00276 public void run() {
00277 TurtlebotDashboard.this.handleDiagnosticArray(message);
00278 }
00279 });
00280 }
00281 });
00282 NameResolver resolver = connectedNode.getResolver().newChild(GraphName.of("/turtlebot_node"));
00283 } catch(Exception ex) {
00284 this.connectedNode = null;
00285 try {
00286 throw (new RosException(ex));
00287 } catch (RosException e) {
00288
00289 e.printStackTrace();
00290 }
00291 }
00292 }
00293 }