//
you're reading...
How-to's

Arduino UART sensors

2014-06-03 17.48.12

Do you want to create your own UART sensors for the EV3?

Here is how to do do it using an Arduino.

We will implement a Nose sensor for our robot, using an MQ-2 gas sensor that you can buy cheaply from ebay.

The Arduino in the picture is a rather big Arduino Mega 2560. It would be better to use one of the many tiny format Arduinos, and a 3D printed case for it would be good. The sensor can be powrered by the EV3. You could use the Dexter Industries breadboard adapter instead of the cut up NXT/EV3 cable, to make things look neater.

You will need a NoseSensor class:

package mypackage;

import lejos.hardware.port.Port;
import lejos.hardware.sensor.SensorMode;
import lejos.hardware.sensor.UARTSensor;

public class NoseSensor extends UARTSensor implements SensorMode {

	public NoseSensor(Port port) {
		super(port);
	}

	@Override
	public int sampleSize() {
		return 1;
	}

	@Override
	public void fetchSample(float[] sample, int offset) {
		sample[offset] = port.getShort();	
	}

	@Override
	public String getName() {
		return "Smelly";
	}
}

You will need a test program:

package mypackage;

import lejos.hardware.Button;
import lejos.hardware.port.SensorPort;

public class Nose {

	public static void main(String[] args) {
		NoseSensor nose = new NoseSensor(SensorPort.S1);
		float[] sample = new float[nose.sampleSize()];
		
		while(Button.ESCAPE.isUp()) {
			nose.fetchSample(sample,0);
			System.out.println("Smelliness: " + sample[0]);
		}	
		nose.close();
	}
}

And finally, you will need an Arduino sketch that implements the EV3 UART protocol, and reads the data from the MQ-2. This one is very messy and full of diagnostics. I plan to write an Arduino library to make this much easier. This code uses the Arduino USB serial port (Serial) for sending optional diagnostics to your PC, and a second hardware serial link (Serial1) for the UART link to the EV3. You could use Serial for the UART if you remove the diagnostics, or you can use SoftwareSerial.

#include <Serial.h>

#define MY_TYPE 99
#define MY_NAME "NOSE"
#define SPEED 38400

#define   BYTE_ACK                      0x04
#define   BYTE_NACK                     0x02
#define   CMD_TYPE                      0x40
#define   CMD_MODES                     0x49
#define   CMD_SPEED                     0x52
#define   CMD_MASK                      0xC0
#define   CMD_INFO                      0x80
#define   CMD_LLL_MASK                  0x38
#define   CMD_LLL_SHIFT                 3
#define   CMD_MMM_MASK                  0x07
#define   CMD_DATA                      0xc0

unsigned long last_nack = 0;

void setup() {
  Serial.begin(115200);
  reset();
}

unsigned long last_message;

void loop() {
  byte cmd;
  if (millis() - last_nack > 10000) reset();
  if (Serial1.available()) {
      cmd = Serial1.read();
      Serial.print("Received: ");
      Serial.println(cmd, HEX);
      if (cmd == BYTE_NACK) last_nack = millis();
  }
  if (millis() - last_message > 100) {
    byte bb[2];
    int r = analogRead(0);
    bb[0] = r & 0xff;
    bb[1] = r >> 8;
    
    send_cmd(CMD_DATA | (1 << CMD_LLL_SHIFT), bb, 2); // mode 0, length 2
    last_message = millis();
  }
}

void reset() {
  for(;;) {
    Serial.println("Resetting");
    byte bb[4];
    byte speed[4];

    Serial1.begin(2400);
    delay(50);
    send_cmd(CMD_TYPE, MY_TYPE);
    bb[0] = 0; // modes = 1
    bb[1] = 0; // views = 1
    send_cmd(CMD_MODES, bb, 2);
    get_bytes(SPEED, speed);
    send_cmd(CMD_SPEED, speed, 4);
    send_cmd(CMD_INFO | (2 << CMD_LLL_SHIFT), 0, (byte*) MY_NAME, 4);
    bb[0] = 1; // sets
    bb[1] = 1; // format Data16
    bb[2] = 4; // figures
    bb[3] = 0; // decimals
    send_cmd(CMD_INFO | (2 << CMD_LLL_SHIFT), 0x80, bb, 4);
    Serial1.write(BYTE_ACK);
    Serial.println("ACK Sent");
    unsigned long m = millis();
    while(!Serial1.available() && millis() - m < 1000);
    if (Serial1.available()) {
      byte cmd = Serial1.read();
      Serial.print("Received for Ack: ");
      Serial.println(cmd, HEX);
      if (cmd == BYTE_ACK) {
        Serial1.end();
        Serial1.begin(SPEED);
        delay(80);
        last_nack = millis();
        break;
      }
    } else Serial.println("ACK timeout");
  }
}

void get_bytes(unsigned long val, byte* bb) {
  for(int i=0;i<4;i++) {
    bb[i] = (val >> (i *8)) & 0xff;
  }
}

void send_cmd(byte cmd, byte type, byte* data, byte len) {
  byte checksum = 0xff ^ cmd;
  Serial.print("Sent: ");
  Serial.print(cmd, HEX);
  Serial1.write(cmd);
  checksum ^= type;
  Serial1.write(type);
  Serial.print(type, HEX);
  for(int i=0;i<len;i++) {
    checksum ^= data[i];
    Serial1.write(data[i]);
    Serial.print(data[i], HEX);
  }
  Serial1.write(checksum);
  Serial.println(checksum, HEX);
}

void send_cmd(byte cmd, byte data) {
  byte bb[1];
  bb[0] = data;
  send_cmd(cmd,bb,1);
}

void send_cmd(byte cmd) {
  byte checksum = 0xff ^ cmd;
  Serial1.write(cmd);
  Serial.print("Sent: ");
  Serial.print(cmd, HEX);
  Serial1.write(checksum);
  Serial.println(checksum, HEX);
}

void send_cmd(byte cmd, byte* data, byte len) {
  byte checksum = 0xff ^ cmd;
  Serial1.write(cmd);
    Serial.print("Sent: ");
  Serial.print(cmd, HEX);
  for(int i=0;i<len;i++) {
    checksum ^= data[i];
    Serial1.write(data[i]);
    Serial.print(data[i], HEX);
  }
  Serial1.write(checksum);
  Serial.println(checksum, HEX);
}
Advertisements

Discussion

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

About leJOS News

leJOS News keeps you up-to-date with leJOS. It features latest news, explains cool features, shows advanced techniques and highlights amazing projects. Be sure to subscribe to leJOS News and never miss an article again. Best of all, subscription is free!
Follow leJOS News on WordPress.com
%d bloggers like this: