AI2 Component  (Version nb184)
NxtUltrasonicSensor.java
Go to the documentation of this file.
1 // -*- mode: java; c-basic-offset: 2; -*-
2 // Copyright 2009-2011 Google, All Rights reserved
3 // Copyright 2011-2012 MIT, All rights reserved
4 // Released under the Apache License, Version 2.0
5 // http://www.apache.org/licenses/LICENSE-2.0
6 
7 package com.google.appinventor.components.runtime;
8 
19 
20 import android.os.Handler;
21 
29 @DesignerComponent(version = YaVersion.NXT_ULTRASONICSENSOR_COMPONENT_VERSION,
30  description = "A component that provides a high-level interface to an ultrasonic sensor on a " +
31  "LEGO MINDSTORMS NXT robot.",
32  category = ComponentCategory.LEGOMINDSTORMS,
33  nonVisible = true,
34  iconName = "images/legoMindstormsNxt.png")
35 @SimpleObject
36 public class NxtUltrasonicSensor extends LegoMindstormsNxtSensor implements Deleteable {
37 
38  private enum State { UNKNOWN, BELOW_RANGE, WITHIN_RANGE, ABOVE_RANGE }
39  private static final String DEFAULT_SENSOR_PORT = "4";
40  private static final int DEFAULT_BOTTOM_OF_RANGE = 30;
41  private static final int DEFAULT_TOP_OF_RANGE = 90;
42 
43  private Handler handler;
44  private final Runnable sensorReader;
45  private State previousState;
46  private int bottomOfRange;
47  private int topOfRange;
48  private boolean belowRangeEventEnabled;
49  private boolean withinRangeEventEnabled;
50  private boolean aboveRangeEventEnabled;
51 
56  super(container, "NxtUltrasonicSensor");
57  handler = new Handler();
58  previousState = State.UNKNOWN;
59  sensorReader = new Runnable() {
60  public void run() {
61  if (bluetooth != null && bluetooth.IsConnected()) {
62  SensorValue<Integer> sensorValue = getDistanceValue("");
63  if (sensorValue.valid) {
64  State currentState;
65  if (sensorValue.value < bottomOfRange) {
66  currentState = State.BELOW_RANGE;
67  } else if (sensorValue.value > topOfRange) {
68  currentState = State.ABOVE_RANGE;
69  } else {
70  currentState = State.WITHIN_RANGE;
71  }
72 
73  if (currentState != previousState) {
74  if (currentState == State.BELOW_RANGE && belowRangeEventEnabled) {
75  BelowRange();
76  }
77  if (currentState == State.WITHIN_RANGE && withinRangeEventEnabled) {
78  WithinRange();
79  }
80  if (currentState == State.ABOVE_RANGE && aboveRangeEventEnabled) {
81  AboveRange();
82  }
83  }
84 
85  previousState = currentState;
86  }
87  }
88  if (isHandlerNeeded()) {
89  handler.post(sensorReader);
90  }
91  }
92  };
93 
94  SensorPort(DEFAULT_SENSOR_PORT);
95  BottomOfRange(DEFAULT_BOTTOM_OF_RANGE);
96  TopOfRange(DEFAULT_TOP_OF_RANGE);
100  }
101 
102  @Override
103  protected void initializeSensor(String functionName) {
104  setInputMode(functionName, port, SENSOR_TYPE_LOWSPEED_9V, SENSOR_MODE_RAWMODE);
105  configureUltrasonicSensor(functionName);
106  }
107 
108  private void configureUltrasonicSensor(String functionName) {
109  // Set to continuous read mode.
110  byte[] data = new byte[3];
111  data[0] = (byte) 0x02;
112  data[1] = (byte) 0x41;
113  data[2] = (byte) 0x02;
114  lsWrite(functionName, port, data, 0);
115  }
116 
121  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_LEGO_NXT_SENSOR_PORT,
122  defaultValue = DEFAULT_SENSOR_PORT)
123  @SimpleProperty(userVisible = false)
124  public void SensorPort(String sensorPortLetter) {
125  setSensorPort(sensorPortLetter);
126  }
127 
128  @SimpleFunction(description = "Returns the current distance in centimeters as a value between " +
129  "0 and 254, or -1 if the distance can not be read.")
130  public int GetDistance() {
131  String functionName = "GetDistance";
132  if (!checkBluetooth(functionName)) {
133  return -1;
134  }
135 
136  SensorValue<Integer> sensorValue = getDistanceValue(functionName);
137  if (sensorValue.valid) {
138  return sensorValue.value;
139  }
140 
141  // invalid response
142  return -1;
143  }
144 
145  private SensorValue<Integer> getDistanceValue(String functionName) {
146  // Send command to initiate read
147  byte[] data = new byte[2];
148  data[0] = (byte) 0x02;
149  data[1] = (byte) 0x42;
150  lsWrite(functionName, port, data, 1);
151 
152  // Wait for read data to be ready, but only try 3 times.
153  for (int i = 0; i < 3; i++) {
154  int countAvailableBytes = lsGetStatus(functionName, port);
155  if (countAvailableBytes > 0) {
156  // Read data.
157  byte[] returnPackage = lsRead(functionName, port);
158  if (returnPackage != null) {
159  int value = getUBYTEValueFromBytes(returnPackage, 4);
160  if (value >= 0 && value <= 254) {
161  return new SensorValue<Integer>(true, value);
162  }
163  }
164  break;
165  }
166  }
167 
168  // invalid response or not ready after 3 tries
169  return new SensorValue<Integer>(false, null);
170  }
171 
176  @SimpleProperty(description = "The bottom of the range used for the BelowRange, WithinRange," +
177  " and AboveRange events.",
178  category = PropertyCategory.BEHAVIOR)
179  public int BottomOfRange() {
180  return bottomOfRange;
181  }
182 
188  defaultValue = "" + DEFAULT_BOTTOM_OF_RANGE)
190  public void BottomOfRange(int bottomOfRange) {
191  this.bottomOfRange = bottomOfRange;
192  previousState = State.UNKNOWN;
193  }
194 
199  @SimpleProperty(description = "The top of the range used for the BelowRange, WithinRange, and" +
200  " AboveRange events.",
201  category = PropertyCategory.BEHAVIOR)
202  public int TopOfRange() {
203  return topOfRange;
204  }
205 
211  defaultValue = "" + DEFAULT_TOP_OF_RANGE)
213  public void TopOfRange(int topOfRange) {
214  this.topOfRange = topOfRange;
215  previousState = State.UNKNOWN;
216  }
217 
222  @SimpleProperty(description = "Whether the BelowRange event should fire when the distance" +
223  " goes below the BottomOfRange.",
224  category = PropertyCategory.BEHAVIOR)
225  public boolean BelowRangeEventEnabled() {
226  return belowRangeEventEnabled;
227  }
228 
233  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "False")
235  public void BelowRangeEventEnabled(boolean enabled) {
236  boolean handlerWasNeeded = isHandlerNeeded();
237 
238  belowRangeEventEnabled = enabled;
239 
240  boolean handlerIsNeeded = isHandlerNeeded();
241  if (handlerWasNeeded && !handlerIsNeeded) {
242  handler.removeCallbacks(sensorReader);
243  }
244  if (!handlerWasNeeded && handlerIsNeeded) {
245  previousState = State.UNKNOWN;
246  handler.post(sensorReader);
247  }
248  }
249 
250  @SimpleEvent(description = "Distance has gone below the range.")
251  public void BelowRange() {
252  EventDispatcher.dispatchEvent(this, "BelowRange");
253  }
254 
259  @SimpleProperty(description = "Whether the WithinRange event should fire when the distance" +
260  " goes between the BottomOfRange and the TopOfRange.",
261  category = PropertyCategory.BEHAVIOR)
262  public boolean WithinRangeEventEnabled() {
263  return withinRangeEventEnabled;
264  }
265 
270  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "False")
272  public void WithinRangeEventEnabled(boolean enabled) {
273  boolean handlerWasNeeded = isHandlerNeeded();
274 
275  withinRangeEventEnabled = enabled;
276 
277  boolean handlerIsNeeded = isHandlerNeeded();
278  if (handlerWasNeeded && !handlerIsNeeded) {
279  handler.removeCallbacks(sensorReader);
280  }
281  if (!handlerWasNeeded && handlerIsNeeded) {
282  previousState = State.UNKNOWN;
283  handler.post(sensorReader);
284  }
285  }
286 
287  @SimpleEvent(description = "Distance has gone within the range.")
288  public void WithinRange() {
289  EventDispatcher.dispatchEvent(this, "WithinRange");
290  }
291 
296  @SimpleProperty(description = "Whether the AboveRange event should fire when the distance" +
297  " goes above the TopOfRange.",
298  category = PropertyCategory.BEHAVIOR)
299  public boolean AboveRangeEventEnabled() {
300  return aboveRangeEventEnabled;
301  }
302 
307  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "False")
309  public void AboveRangeEventEnabled(boolean enabled) {
310  boolean handlerWasNeeded = isHandlerNeeded();
311 
312  aboveRangeEventEnabled = enabled;
313 
314  boolean handlerIsNeeded = isHandlerNeeded();
315  if (handlerWasNeeded && !handlerIsNeeded) {
316  handler.removeCallbacks(sensorReader);
317  }
318  if (!handlerWasNeeded && handlerIsNeeded) {
319  previousState = State.UNKNOWN;
320  handler.post(sensorReader);
321  }
322  }
323 
324  @SimpleEvent(description = "Distance has gone above the range.")
325  public void AboveRange() {
326  EventDispatcher.dispatchEvent(this, "AboveRange");
327  }
328 
329  private boolean isHandlerNeeded() {
330  return belowRangeEventEnabled || withinRangeEventEnabled || aboveRangeEventEnabled;
331  }
332 
333  // Deleteable implementation
334 
335  @Override
336  public void onDelete() {
337  handler.removeCallbacks(sensorReader);
338  super.onDelete();
339  }
340 }
com.google.appinventor.components.runtime.EventDispatcher
Definition: EventDispatcher.java:22
com.google.appinventor.components.runtime.LegoMindstormsNxtBase.lsGetStatus
final int lsGetStatus(String functionName, int port)
Definition: LegoMindstormsNxtBase.java:193
com.google.appinventor.components.annotations.SimpleFunction
Definition: SimpleFunction.java:23
com.google.appinventor.components.runtime.NxtUltrasonicSensor.AboveRange
void AboveRange()
Definition: NxtUltrasonicSensor.java:325
com.google.appinventor.components.common.YaVersion
Definition: YaVersion.java:14
com.google.appinventor.components.runtime.NxtUltrasonicSensor.GetDistance
int GetDistance()
Definition: NxtUltrasonicSensor.java:130
com.google.appinventor.components.annotations.DesignerProperty
Definition: DesignerProperty.java:25
com.google.appinventor.components.runtime.LegoMindstormsNxtBase.bluetooth
BluetoothClient bluetooth
Definition: LegoMindstormsNxtBase.java:77
com.google.appinventor.components
com.google.appinventor.components.common.PropertyTypeConstants.PROPERTY_TYPE_NON_NEGATIVE_INTEGER
static final String PROPERTY_TYPE_NON_NEGATIVE_INTEGER
Definition: PropertyTypeConstants.java:206
com.google.appinventor.components.runtime.NxtUltrasonicSensor.BelowRangeEventEnabled
void BelowRangeEventEnabled(boolean enabled)
Definition: NxtUltrasonicSensor.java:235
com.google.appinventor.components.runtime.NxtUltrasonicSensor.WithinRange
void WithinRange()
Definition: NxtUltrasonicSensor.java:288
com.google.appinventor.components.runtime.NxtUltrasonicSensor.initializeSensor
void initializeSensor(String functionName)
Definition: NxtUltrasonicSensor.java:103
com.google.appinventor.components.runtime.LegoMindstormsNxtSensor.setSensorPort
final void setSensorPort(String sensorPortLetter)
Definition: LegoMindstormsNxtSensor.java:78
com.google.appinventor.components.runtime.BluetoothConnectionBase.IsConnected
final boolean IsConnected()
Definition: BluetoothConnectionBase.java:204
com.google.appinventor.components.runtime.LegoMindstormsNxtBase.lsRead
final byte[] lsRead(String functionName, int port)
Definition: LegoMindstormsNxtBase.java:225
com.google.appinventor.components.common.PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN
static final String PROPERTY_TYPE_BOOLEAN
Definition: PropertyTypeConstants.java:35
com.google.appinventor.components.annotations.DesignerComponent
Definition: DesignerComponent.java:22
com.google.appinventor.components.annotations.SimpleEvent
Definition: SimpleEvent.java:20
com.google.appinventor.components.annotations.PropertyCategory.BEHAVIOR
BEHAVIOR
Definition: PropertyCategory.java:15
com.google.appinventor.components.runtime.NxtUltrasonicSensor.NxtUltrasonicSensor
NxtUltrasonicSensor(ComponentContainer container)
Definition: NxtUltrasonicSensor.java:55
com.google.appinventor.components.runtime.LegoMindstormsNxtBase.lsWrite
final void lsWrite(String functionName, int port, byte[] data, int rxDataLength)
Definition: LegoMindstormsNxtBase.java:210
com.google.appinventor.components.runtime.LegoMindstormsNxtSensor.SensorPort
String SensorPort()
Definition: LegoMindstormsNxtSensor.java:70
com.google.appinventor.components.runtime.NxtUltrasonicSensor.TopOfRange
int TopOfRange()
Definition: NxtUltrasonicSensor.java:202
com.google.appinventor.components.runtime.LegoMindstormsNxtBase.getUBYTEValueFromBytes
final int getUBYTEValueFromBytes(byte[] bytes, int offset)
Definition: LegoMindstormsNxtBase.java:407
com.google.appinventor.components.runtime.NxtUltrasonicSensor.TopOfRange
void TopOfRange(int topOfRange)
Definition: NxtUltrasonicSensor.java:213
com.google.appinventor.components.runtime.EventDispatcher.dispatchEvent
static boolean dispatchEvent(Component component, String eventName, Object...args)
Definition: EventDispatcher.java:188
com.google.appinventor.components.runtime.NxtUltrasonicSensor.onDelete
void onDelete()
Definition: NxtUltrasonicSensor.java:336
com.google.appinventor.components.runtime.LegoMindstormsNxtSensor
Definition: LegoMindstormsNxtSensor.java:21
com.google.appinventor.components.annotations.SimpleProperty
Definition: SimpleProperty.java:23
com.google.appinventor.components.annotations.PropertyCategory
Definition: PropertyCategory.java:13
com.google.appinventor.components.runtime.ComponentContainer
Definition: ComponentContainer.java:16
com.google.appinventor.components.runtime.Deleteable
Definition: Deleteable.java:15
com.google.appinventor.components.common
Definition: ComponentCategory.java:7
com.google.appinventor.components.common.ComponentCategory
Definition: ComponentCategory.java:48
com.google.appinventor.components.runtime.NxtUltrasonicSensor.AboveRangeEventEnabled
void AboveRangeEventEnabled(boolean enabled)
Definition: NxtUltrasonicSensor.java:309
com.google.appinventor.components.runtime.LegoMindstormsNxtBase.checkBluetooth
final boolean checkBluetooth(String functionName)
Definition: LegoMindstormsNxtBase.java:250
com.google.appinventor.components.annotations.SimpleObject
Definition: SimpleObject.java:23
com.google.appinventor.components.runtime.NxtUltrasonicSensor.BottomOfRange
int BottomOfRange()
Definition: NxtUltrasonicSensor.java:179
com.google.appinventor.components.runtime.LegoMindstormsNxtSensor.port
int port
Definition: LegoMindstormsNxtSensor.java:56
com.google
com
com.google.appinventor.components.runtime.NxtUltrasonicSensor.AboveRangeEventEnabled
boolean AboveRangeEventEnabled()
Definition: NxtUltrasonicSensor.java:299
com.google.appinventor.components.runtime.NxtUltrasonicSensor.BelowRange
void BelowRange()
Definition: NxtUltrasonicSensor.java:251
com.google.appinventor.components.runtime.NxtUltrasonicSensor.BottomOfRange
void BottomOfRange(int bottomOfRange)
Definition: NxtUltrasonicSensor.java:190
com.google.appinventor.components.runtime.NxtUltrasonicSensor
Definition: NxtUltrasonicSensor.java:36
com.google.appinventor.components.runtime.NxtUltrasonicSensor.WithinRangeEventEnabled
boolean WithinRangeEventEnabled()
Definition: NxtUltrasonicSensor.java:262
com.google.appinventor.components.runtime.LegoMindstormsNxtBase.setInputMode
final void setInputMode(String functionName, int port, int sensorType, int sensorMode)
Definition: LegoMindstormsNxtBase.java:158
com.google.appinventor.components.runtime.NxtUltrasonicSensor.BelowRangeEventEnabled
boolean BelowRangeEventEnabled()
Definition: NxtUltrasonicSensor.java:225
com.google.appinventor.components.common.PropertyTypeConstants
Definition: PropertyTypeConstants.java:14
com.google.appinventor.components.annotations
com.google.appinventor.components.runtime.NxtUltrasonicSensor.WithinRangeEventEnabled
void WithinRangeEventEnabled(boolean enabled)
Definition: NxtUltrasonicSensor.java:272
com.google.appinventor