Monday, October 23, 2017

Arduino Motorcycle Safety Device

Arduino Motorcycle Safety Device

Project #1 - Monitor Freezing Temperature



As winter approaching, keeping track of ambient temperature to aware of possible ice formation becomes one of the road survival must-do for motorcyclists.

With a very simple program, I am making use of the temperature sensor build in the Lightblue Bean to monitor ambient temperature.

The program is super simple (showing below), it turns on the the Bean's red LED once it detects temperature at/below 3C. 















/*
 * Temperature monitor for freeze warning when ambient temperature drops to/below 3C
 * Single Green LED on when temperature is above 3C
 * Single Red LED on when current temperature is at/below 3C
 */

#define FREEZING_TEMP 3

void setup() {
  // Light Green LED on startup
  Bean.setLed(0,255,0);
}

void loop() {
  int temp = Bean.getTemperature();
  if(temp <= FREEZING_TEMP){
    Bean.setLed(255,0,0);
  } else {
    Bean.setLed(0,255,0);
  };
  Bean.sleep(60000);    // Sleep for 60 seconds
}


Sunday, October 15, 2017

Android reading LightBlue Bean digital and analog pins

Reading LightBlue Bean digital and analog pins


I got several requests on how to read the Bean pins value, so here it comes ...

The Bean SDK API has callable methods to retrieve sensors value but not the digital and analog pins, my example here is to re-use the DemoSketch from PunchThrough and read the pins value through serial message.

Install and run the DemoSketch on your bean.

First come first is to install the Sketch, please refer to ....

a). Refer to the source and introduction of the demo sketch.
https://punchthrough.com/bean/docs/guides/everything-else/lb-demo-sketch/

b). Load the sketch into your bean.
I am using MacOSX (link below), you can find the loader based on your platform.
https://www.punchthrough.com/bean/docs/guides/getting-started/os-x/

Handshake details from the DemoSketch

With reference to the source ...



#define BUFFER_SIZE 64

void setup() {
  // Set a timeout so that Bean won't stall indefinitely if something goes wrong
  Serial.setTimeout(25);

  // Configure digital pins as inputs
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
}

void loop() {
  // Grab up to 64 bytes from Bean's Virtual Serial port
  char buffer[BUFFER_SIZE];
  uint8_t bytes_rcvd = Serial.readBytes(buffer, BUFFER_SIZE);

  if (bytes_rcvd == 1 && buffer[0] == 0x02) {
    // We got a request for data from LightBlue!

    // Read analog pins A0 and A1
    int analog1 = analogRead(A0);
    int analog2 = analogRead(A1);

    // Read digital pins D0 through D5 and join their bits into a single byte
    uint8_t digitalAll = 0;
    digitalAll |= digitalRead(0);
    digitalAll |= digitalRead(1) << 1;
    digitalAll |= digitalRead(1) << 2;
    digitalAll |= digitalRead(1) << 3;
    digitalAll |= digitalRead(1) << 4;
    digitalAll |= digitalRead(1) << 5;

    // Package the data into a 6-byte buffer
    buffer[0] = 0x82;
    buffer[1] = digitalAll;
    buffer[2] = analog1 & 0xFF;
    buffer[3] = analog1 >> 8;
    buffer[4] = analog2 & 0xFF;
    buffer[5] = analog2 >> 8;

    // Send back 6 bytes of data to LightBlue
    Serial.write((uint8_t *)buffer, 6);
  }

  // Sleep until another serial request wakes us up
  Bean.sleep(0xFFFFFFFF);
}

Based on the source, the interface spec is as the following.

  1. When bean receives a serial message with first byte equals to 0x02, it responses back with a 6 bytes serial message.
  2. The 6 bytes response message is formatted as ..
    byte 1 - Response header code equals 0x82
    byte 2 - Binary value of pins D0 through D5
    byte 3 and 4 - Analog value of A0
    byte 5 and 6 - Analog value of A1


Android Program

Based on the DemoSketch, Bean won't read and send its pins value unless it receives a request message through its Serial transport,  our Android program need to send a request message to the bean to get things started.

A). Sending the request message

byte requestCode=0x02;
byte[] requestMsg= {requestCode};
bean.sendSerialMessage(requestMsg);


B). Bean's callback and response parsing

Your BeanListener interface will receive a call back on onSerialMessageReceived
and the 6 bytes serial message is passed through the byte array.  The following example
code is validate the proper responser header byte (0x82) and parses the byte array
to retrieve the digital and analog pins value.



public void onSerialMessageReceived(byte[] data) {
    Log.d(TAG, "onSerialMessageReceived >> "+BeanInfo);
    char[] chars= Hex.encodeHex(data);
    Log.d(TAG,"data: "+ String.valueOf(chars));
    int size=data.length;
    Log.d(TAG,"number of bytes: "+ size);
    Log.d(TAG,"byte 1 (should be 82):"+ Integer.toHexString(data[0] & 0xFF));
    byte digitalPins=data[1];
    String s1 = String.format("%8s", Integer.toBinaryString(digitalPins & 0xFF)).replace(' ', '0');
    Log.d(TAG,"byte 2  Pins[xx543210]:"+ s1);
    byte a1L = data[2];
    byte a1H = data[3];
    byte a2L = data[4];
    byte a2H = data[5];
    int a1=a1H*256+a1L;
    int a2=a2H*256+a2L;
    Log.d(TAG,"A1 values:"+ a1);
    Log.d(TAG,"A2 values:"+ a2);
}


Herewith is the complete read pins function whereas a discovered bean is passed and connect with
the example BeanListener.

public static void readPins(Context context, Bean bean){
    final String TAG="BEAN";
    final String BeanInfo=bean.describe();
    byte requestCode=0x02;
    byte[] requestMsg= {requestCode};
    bean.sendSerialMessage(requestMsg);
    bean.connect(context, new BeanListener() {
        @Override        public void onConnected() {
            Log.d(TAG, "onConnected >> "+BeanInfo);
        }

        @Override        public void onConnectionFailed() {
            Log.d(TAG, "onConnectionFailed >> "+BeanInfo);
        }

        @Override        public void onDisconnected() {
            Log.d(TAG, "onDisconnected >> "+BeanInfo);
        }

        @Override        public void onSerialMessageReceived(byte[] data) {
            Log.d(TAG, "onSerialMessageReceived >> "+BeanInfo);
            char[] chars= Hex.encodeHex(data);
            Log.d(TAG,"data: "+ String.valueOf(chars));
            int size=data.length;
            Log.d(TAG,"number of bytes: "+ size);
            Log.d(TAG,"byte 1 (should be 82):"+ Integer.toHexString(data[0] & 0xFF));
            byte digitalPins=data[1];
            String s1 = String.format("%8s", Integer.toBinaryString(digitalPins & 0xFF)).replace(' ', '0');
            Log.d(TAG,"byte 2  Pins[xx543210]:"+ s1);
            byte a1L = data[2];
            byte a1H = data[3];
            byte a2L = data[4];
            byte a2H = data[5];
            int a1=a1H*256+a1L;
            int a2=a2H*256+a2L;
            Log.d(TAG,"A1 values:"+ a1);
            Log.d(TAG,"A2 values:"+ a2);
        }

        @Override        public void onScratchValueChanged(ScratchBank bank, byte[] value) {
            Log.d(TAG, "onScratchValueChanged >> "+bank);
        }

        @Override        public void onError(BeanError error) {
            Log.d(TAG, "onConnectionFailed >> "+error);
        }

        @Override        public void onReadRemoteRssi(int rssi) {
            Log.d(TAG, "onReadRemoteRssi >> "+rssi);
        }
    });
}

Sunday, February 14, 2016

Android reading LightBlue Bean sensor values

The previous blog shows example of using the LightBlue Bean Android SDK to read the bean's temperature sensor value.  In this blog, I am going to examine reading all other sensor values.  The programming model is simple and consistent, you call the bean.readXXX function with a callback handler, the SDK then invoke the callback with the measured sensor value.

Full source code available in Github

1. Read Battery Level

The following code snippet call to read the Bean's battery level, the callback's onResult is invoked with a BatteryLevel object represents the measured battery level, you can get the battery voltage and percentage of battery level.

       bean.readBatteryLevel(new Callback<BatteryLevel>() {
            @Override
            public void onResult(BatteryLevel result) {
                Log.d(TAG, "result: "+result.getPercentage());
                Log.d(TAG, "Battery percentage: "+result.getPercentage());
                Log.d(TAG, "Battery volt: "+result.getVoltage());
            }
        }
        );

2. Read Arduino's Power State.

The callback is invoked with a Boolean, True indicating the Bean's Arduino is ON and OFF if False.

   bean.readArduinoPowerState(new Callback<Boolean>() {
            @Override
            public void onResult(Boolean result) {
                Log.d(TAG, "result: "+result);
            }
        });

3. Read Acceleration in X, Y and Z - axis

For read acceleration, the parameter passed to the callback handler is an Acceleration object which contains acceleration on X, Y and Z axis, you can retrieve those values by the x(), y() and z() getter of the Acceleration object.

      bean.readAcceleration(new Callback<Acceleration>() {
            @Override
            public void onResult(Acceleration result) {
                Log.d(TAG, "result: "+result);
                Log.d(TAG, "Acceleration on X-axis: "+result.x());
                Log.d(TAG, "Acceleration on y-axis: "+result.y());
                Log.d(TAG, "Acceleration on z-axis: "+result.z());
            }
        });


4. Read AccelerometerRange

As per the Beans' Android SDK, the SDK shall invoke the callback function passing an AccelerometerRange object.  However, I found that the SDK is passing an Integer instead.  As a result, I am always getting Class Cast exception.  

       bean.readAccelerometerRange(new Callback<AccelerometerRange>() {
            @Override
            public void onResult(AccelerometerRange result) {
                Log.d(TAG, "result: "+result);
            }
        });

5. Read the RGB LED

You can also read the LED colour with the Bean's readLed function call, you will then get a LedColor object with contains 3 integers representing the R, G, B intensity of the LED.

      bean.readLed(new Callback<LedColor>() {
            @Override
            public void onResult(LedColor result) {
                Log.d(TAG, "result: "+result);
            }
        });

6. Reading Pins value

The SDK doesn't provide function to read the Pins value, but it shall be very easy to have a Bean's Sketch to put the Pins value to Scratch Data or Virtual Serial Port that an Android App can read.  Let me know if you are interested to see some example code on this.




Sunday, February 7, 2016

Mobile Arduino with LightBlue Bean and Android

Punch Through LightBlue Bean - A Bluetooth Low Energy (BLE) Arduino

I accidentally come to Punch Through website and attracted by it tiny BLE Arduino, ordered it and start hacking on it.

LightBlue Bean is a tiny wearable Arduino powered by a watch battery, it comes with a accelerometer, temperature sensor and RGB LED, the best part is that you can program and interface with it wirelessly through BLE.  More about the LightBlue Bean is available here.  It also has with an Android SDK, my hacking exercise this weekend is to write an Android program to interface with my new tiny toy.

Herewith is the step of creating an Android program to connect to the Bean and read the ambient temperature.   The exercise is based on Android Studio and Gradle,


HelloBean - Android program to wirelessly interface to LightBlue Bean


1. Create a simple blank Android application using Android Studio.
2. Add LightBean Android SDK but adding to  HelloBean/app/build.gradle

dependencies {
...
    compile 'com.punchthrough.bean.sdk:sdk:1.0.2'
...
}

3. To keep things simple, HelloBean app just has one single Activity (MainActivity) and a single screen.  We made this single Activity the listener of the Bean discovery and connection action.  The MainActivity class has a list of discovered bean (i.e. beans) and a target bean (i.e. bean).  We start Bean discovery when the App start (i.e. onCreate of the MainActivity) by calling the startDiscovery() of BeanManager.

public class MainActivity extends ...  implements BeanDiscoveryListener, BeanListener {
   final String TAG = "BlueBean";
    final List<Bean> beans = new ArrayList<>();
    Bean bean = null;
    TextView textView =null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 ...
        textView = (TextView)findViewById(R.id.main_text);
        textView.setText("Start Bluebean discovery ...");
        Log.d(TAG,"Start Bluebean discovery ...");
        BeanManager.getInstance().startDiscovery(this);
    }


4.  Add the following methods to implement BeanDiscoveryListener interface.  We connect to the first bean found of the discovery as our target bean by calling bean.connect().

  @Override
    public void onBeanDiscovered(Bean bean, int rssi) {
        Log.d(TAG,"A bean is found: "+bean);
        StringBuffer aBuf= new StringBuffer(textView.getText());
        aBuf.append("\n");
        aBuf.append(""+bean.getDevice().getName()+" address: "+bean.getDevice().getAddress());
        textView.setText(aBuf.toString());
        beans.add(bean);
    }

    @Override
    public void onDiscoveryComplete() {
        StringBuffer aBuf= new StringBuffer(textView.getText());
        aBuf.append("\n");
        aBuf.append("not more Bluebean found");
        textView.setText(aBuf.toString());
        for (Bean bean : beans) {
            Log.d(TAG, "Bean name: "+bean.getDevice().getName());
            Log.d(TAG, "Bean address: "+bean.getDevice().getAddress());
         }
        if(beans.size()>0){
            bean=beans.get(0);
            bean.connect(this,this);
        }
    }

5. Add the following methods to implement BeanListener.  Once the bean is connected, we query the bean's hardware information and it's measured temperature.

  // BeanListener Methods
    @Override
    public void onConnected() {
        Log.d(TAG,"connected to Bean!");
        bean.readDeviceInfo(new Callback<DeviceInfo>() {
            @Override
            public void onResult(DeviceInfo deviceInfo) {
                Log.d(TAG,deviceInfo.hardwareVersion());
                Log.d(TAG,deviceInfo.firmwareVersion());
                Log.d(TAG,deviceInfo.softwareVersion());
            }
        });

         bean.readTemperature(new Callback<Integer>() {
            @Override
            public void onResult(Integer data){
                Log.d(TAG, "Temperature: "+data);
              }
        });
    }

    @Override
    public void onConnectionFailed() {
        Log.d(TAG,"onConnectionFailed");
    }

    @Override
    public void onDisconnected() {
        Log.d(TAG,"onDisconnected");
    }

    @Override
    public void onSerialMessageReceived(byte[] data) {
        Log.d(TAG,"onSerialMessageReceived");
        Log.d(TAG,"data: "+data);
    }

    @Override
    public void onScratchValueChanged(ScratchBank bank, byte[] value) {
        Log.d(TAG,"onScratchValueChanged");
        Log.d(TAG,"bank: "+bank+"\tvalue: "+value);
    }

    @Override
    public void onError(BeanError error) {
        Log.d(TAG,"onError");
        Log.d(TAG,"error: "+error);
    }


As this exercise shows, interfacing to LightBlue Bean using Android through BLE is extremely easy, it's SDK also provide a very simple programming model.  Hacking this tiny wearable Arduino is fun and easy, we are going to have more projects on it.  Stay tune.



Saturday, January 23, 2016

Arduino Car Battery Monitor

In this circuit, a resistor divider circuit with an effective divider ratio of 3.78.

(100K+56K)/56K = 3.78

This has a measurable voltage range of 0-18.9 volts, this take care of the potential voltage spike when the battery is on charge or at ignition.

The 22uF capacitor is to reduce the spike measured by Arduino.



#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const int sensorPin = A0;
const float DivderRatio = 3.78;


void setup(){
  Serial.begin(9600);
  lcd.begin(16,2);
  lcd.print("KTM 690 ENDURO");   
  lcd.setCursor(0,1);
  lcd.print("Volt =");
}

void loop() {
  
  int sensorValue = analogRead(sensorPin);
  float sensorVoltage = (sensorValue/1024.0) * 5.0;
  float vcc = sensorVoltage * DivderRatio;
  Serial.print("Sensor Value=");
  Serial.print(sensorValue);
  Serial.print("\t volt=");
  Serial.print(sensorVoltage);
  Serial.println("\t Vcc=");
  Serial.println(vcc);
  lcd.setCursor(11,1);
  lcd.print(vcc);
  delay(150);
}