Thursday, April 25, 2013

Reading RC Channels with Arduino Due

Update 27/04/2013

The following code was originally presented as a test sketch to demonstrate a glitch in the Arduino Due micros function which is being resolved. See the following post for details of the glitch and resolution.

http://arduino.cc/forum/index.php/topic,162787.0/topicseen.html

With this resolution in place the code presented below can be used to read 8 RC Channels and output them to a combination of upto 8 RC Servos or ESCs.

The code can be operated in two configurations -

1) Loop Back Test - Here 8 servo outputs are created and given fixed values from 1100 to 1800, these pulse values are output on pins 10 to 17 and can be read back in through the interrupts attached to pins 2 to 9. This is intended to give the user confidence that the code is able to read multiple RC Channels before moving to configuration 2 - Pass Through

2) Pass Through -  This is similar to 1) above however the input is now connected to the output such that a change in an incoming signal will cause a corresponding change in the servo output signal. To implement pass  through on any channel, simply remove the comment form the start of the servo.writeMicrosecond command for that channel for example

Change this -

  if(bUpdateFlags & CHANNEL1_FLAG)
  {
      // remove the // from the line below to implement pass through updates to the servo on this channel -
      //servoChannel1.writeMicroseconds(unChannel1In);
      Serial.print(unChannel1In);
      Serial.print(",");
  }
to this -

  if(bUpdateFlags & CHANNEL1_FLAG)
  {
      // remove the // from the line below to implement pass through updates to the servo on this channel -
      servoChannel1.writeMicroseconds(unChannel1In);
      Serial.print(unChannel1In);
      Serial.print(",");
  }




The code has been ported from an original project based on the Arduino UNO, follow the links in the comments for the background and detailed explanation.

// MultiChannels
//
// rcarduino.blogspot.com
//
// A simple approach for reading and writing eight RC Channels using Arduino Due interrupts
//
// See related posts -
// http://rcarduino.blogspot.co.uk/2012/01/how-to-read-rc-receiver-with.html
// http://rcarduino.blogspot.co.uk/2012/03/need-more-interrupts-to-read-more.html
// http://rcarduino.blogspot.co.uk/2012/01/can-i-control-more-than-x-servos-with.html
//
// rcarduino.blogspot.com
//

#include "Servo.h"

// Assign your channel in pins
#define CHANNEL1_IN_PIN 2
#define CHANNEL2_IN_PIN 3
#define CHANNEL3_IN_PIN 4
#define CHANNEL4_IN_PIN 5
#define CHANNEL5_IN_PIN 6
#define CHANNEL6_IN_PIN 7
#define CHANNEL7_IN_PIN 8
#define CHANNEL8_IN_PIN 9

// Assign your channel out pins
#define CHANNEL1_OUT_PIN 10
#define CHANNEL2_OUT_PIN 11
#define CHANNEL3_OUT_PIN 12
#define CHANNEL4_OUT_PIN 13
#define CHANNEL5_OUT_PIN 14
#define CHANNEL6_OUT_PIN 15
#define CHANNEL7_OUT_PIN 16
#define CHANNEL8_OUT_PIN 17

// Servo objects generate the signals expected by Electronic Speed Controllers and Servos
// We will use the objects to output the signals we read in
// this example code provides a straight pass through of the signal with no custom processing
Servo servoChannel1;
Servo servoChannel2;
Servo servoChannel3;
Servo servoChannel4;
Servo servoChannel5;
Servo servoChannel6;
Servo servoChannel7;
Servo servoChannel8;

// These bit flags are set in bUpdateFlagsShared to indicate which
// channels have new signals
#define CHANNEL1_FLAG 1
#define CHANNEL2_FLAG 2
#define CHANNEL3_FLAG 4
#define CHANNEL4_FLAG 8
#define CHANNEL5_FLAG 16
#define CHANNEL6_FLAG 32
#define CHANNEL7_FLAG 64
#define CHANNEL8_FLAG 128

// holds the update flags defined above
volatile uint32_t bUpdateFlagsShared;

// shared variables are updated by the ISR and read by loop.
// In loop we immediatley take local copies so that the ISR can keep ownership of the
// shared ones. To access these in loop
// we first turn interrupts off with noInterrupts
// we take a copy to use in loop and the turn interrupts back on
// as quickly as possible, this ensures that we are always able to receive new signals
volatile uint32_t unChannel1InShared;
volatile uint32_t unChannel2InShared;
volatile uint32_t unChannel3InShared;
volatile uint32_t unChannel4InShared;
volatile uint32_t unChannel5InShared;
volatile uint32_t unChannel6InShared;
volatile uint32_t unChannel7InShared;
volatile uint32_t unChannel8InShared;

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

  Serial.println("multiChannels");

  // attach servo objects, these will generate the correct
  // pulses for driving Electronic speed controllers, servos or other devices
  // designed to interface directly with RC Receivers
  servoChannel1.attach(CHANNEL1_OUT_PIN);
  servoChannel2.attach(CHANNEL2_OUT_PIN);
  servoChannel3.attach(CHANNEL3_OUT_PIN);
  servoChannel4.attach(CHANNEL4_OUT_PIN);
  servoChannel5.attach(CHANNEL5_OUT_PIN);
  servoChannel6.attach(CHANNEL6_OUT_PIN);
  servoChannel7.attach(CHANNEL7_OUT_PIN);
  servoChannel8.attach(CHANNEL8_OUT_PIN);

  // attach the interrupts used to read the channels
  attachInterrupt(CHANNEL1_IN_PIN, calcChannel1,CHANGE);
  attachInterrupt(CHANNEL2_IN_PIN, calcChannel2,CHANGE);
  attachInterrupt(CHANNEL3_IN_PIN, calcChannel3,CHANGE);
  attachInterrupt(CHANNEL4_IN_PIN, calcChannel4,CHANGE);
  attachInterrupt(CHANNEL5_IN_PIN, calcChannel5,CHANGE);
  attachInterrupt(CHANNEL6_IN_PIN, calcChannel6,CHANGE);
  attachInterrupt(CHANNEL7_IN_PIN, calcChannel7,CHANGE);
  attachInterrupt(CHANNEL8_IN_PIN, calcChannel8,CHANGE);

  // for loop back test only, lets set each channel to a known value
  servoChannel1.writeMicroseconds(1100);
  servoChannel2.writeMicroseconds(1200);
  servoChannel3.writeMicroseconds(1300);
  servoChannel4.writeMicroseconds(1400);
  servoChannel5.writeMicroseconds(1500);
  servoChannel6.writeMicroseconds(1600);
  servoChannel7.writeMicroseconds(1700);
  servoChannel8.writeMicroseconds(1800);
}

void loop()
{
  // create local variables to hold a local copies of the channel inputs
  // these are declared static so that thier values will be retained
  // between calls to loop.
  static uint32_t unChannel1In;
  static uint32_t unChannel2In;
  static uint32_t unChannel3In;
  static uint32_t unChannel4In;
  static uint32_t unChannel5In;
  static uint32_t unChannel6In;
  static uint32_t unChannel7In;
  static uint32_t unChannel8In;
 
  // local copy of update flags
  static uint32_t bUpdateFlags;

  // check shared update flags to see if any channels have a new signal
  if(bUpdateFlagsShared)
  {
    noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables

    // take a local copy of which channels were updated in case we need to use this in the rest of loop
    bUpdateFlags = bUpdateFlagsShared;
  
    // in the current code, the shared values are always populated
    // so we could copy them without testing the flags
    // however in the future this could change, so lets
    // only copy when the flags tell us we can.
  
    if(bUpdateFlags & CHANNEL1_FLAG)
    {
      unChannel1In = unChannel1InShared;
    }
  
    if(bUpdateFlags & CHANNEL2_FLAG)
    {
      unChannel2In = unChannel2InShared;
    }
  
    if(bUpdateFlags & CHANNEL3_FLAG)
    {
      unChannel3In = unChannel3InShared;
    }
   
    if(bUpdateFlags & CHANNEL4_FLAG)
    {
      unChannel4In = unChannel4InShared;
    }
  
    if(bUpdateFlags & CHANNEL5_FLAG)
    {
      unChannel5In = unChannel5InShared;
    }
  
    if(bUpdateFlags & CHANNEL6_FLAG)
    {
      unChannel6In = unChannel6InShared;
    }
   
    if(bUpdateFlags & CHANNEL7_FLAG)
    {
      unChannel7In = unChannel7InShared;
    }
  
    if(bUpdateFlags & CHANNEL8_FLAG)
    {
      unChannel8In = unChannel8InShared;
    }
    // clear shared copy of updated flags as we have already taken the updates
    // we still have a local copy if we need to use it in bUpdateFlags
    bUpdateFlagsShared = 0;
  
    interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on
    // as soon as interrupts are back on, we can no longer use the shared copies, the interrupt
    // service routines own these and could update them at any time. During the update, the
    // shared copies may contain junk. Luckily we have our local copies to work with :-)
  }
 
  // do any processing from here onwards
  // only use the local values unChannel1, unChannel2, unChannel3, unChannel4, unChannel5, unChannel6, unChannel7, unChannel8
  // variables unChannel1InShared, unChannel2InShared, etc are always owned by the
  // the interrupt routines and should not be used in loop
 
  if(bUpdateFlags & CHANNEL1_FLAG)
  {
      // remove the // from the line below to implement pass through updates to the servo on this channel -
      //servoChannel1.writeMicroseconds(unChannel1In);
      Serial.println();
      Serial.print(unChannel1In);
      Serial.print(",");
  }

  if(bUpdateFlags & CHANNEL2_FLAG)
  {
      // remove the // from the line below to implement pass through updates to the servo on this channel -
      //servoChannel2.writeMicroseconds(unChannel2In);
      Serial.print(unChannel2In);
      Serial.print(",");
  }

  if(bUpdateFlags & CHANNEL3_FLAG)
  {
      // remove the // from the line below to implement pass through updates to the servo on this channel -
      //servoChannel3.writeMicroseconds(unChannel3In);
      Serial.print(unChannel3In);
      Serial.print(",");
  }

  if(bUpdateFlags & CHANNEL4_FLAG)
  {
    // remove the // from the line below to implement pass through updates to the servo on this channel -
    // servoChannel4.writeMicroseconds(unChannel4In);
    Serial.print(unChannel4In);
    Serial.print(",");
  }
 
  if(bUpdateFlags & CHANNEL5_FLAG)
  {
    // remove the // from the line below to implement pass through updates to the servo on this channel -
    // servoChannel5.writeMicroseconds(unChannel5In);
    Serial.print(unChannel5In);
    Serial.print(",");
  }
 
  if(bUpdateFlags & CHANNEL6_FLAG)
  {
    // remove the // from the line below to implement pass through updates to the servo on this channel -
    // servoChannel6.writeMicroseconds(unChannel6In);
    Serial.print(unChannel6In);
  }
 
  if(bUpdateFlags & CHANNEL7_FLAG)
  {
    // remove the // from the line below to implement pass through updates to the servo on this channel -
    // servoChannel7.writeMicroseconds(unChannel7In);
    Serial.print(unChannel7In);
    Serial.print(",");
  }
 
  if(bUpdateFlags & CHANNEL8_FLAG)
  {
    // remove the // from the line below to implement pass through updates to the servo on this channel -
    // servoChannel8.writeMicroseconds(unChannel8In);
    Serial.print(unChannel8In);
  }
 
  bUpdateFlags = 0;
}

void calcChannel1()
{
  static uint32_t ulStart;
 
  if(digitalRead(CHANNEL1_IN_PIN))
  {
    ulStart = micros();
  }
  else
  {
    unChannel1InShared = (uint32_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL1_FLAG;
  }
}

void calcChannel2()
{
  static uint32_t ulStart;
 
  if(digitalRead(CHANNEL2_IN_PIN))
  {
    ulStart = micros();
  }
  else
  {
    unChannel2InShared = (uint32_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL2_FLAG;
  }
}

void calcChannel3()
{
  static uint32_t ulStart;
 
  if(digitalRead(CHANNEL3_IN_PIN))
  {
    ulStart = micros();
  }
  else
  {
    unChannel3InShared = (uint32_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL3_FLAG;
  }
}

void calcChannel4()
{
  static uint32_t ulStart;
 
  if(digitalRead(CHANNEL4_IN_PIN))
  {
    ulStart = micros();
  }
  else
  {
    unChannel4InShared = (uint32_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL4_FLAG;
  }
}

void calcChannel5()
{
  static uint32_t ulStart;
 
  if(digitalRead(CHANNEL5_IN_PIN))
  {
    ulStart = micros();
  }
  else
  {
    unChannel5InShared = (uint32_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL5_FLAG;
  }
}

void calcChannel6()
{
  static uint32_t ulStart;
 
  if(digitalRead(CHANNEL6_IN_PIN))
  {
    ulStart = micros();
  }
  else
  {
    unChannel6InShared = (uint32_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL6_FLAG;
  }
}

void calcChannel7()
{
  static uint32_t ulStart;
 
  if(digitalRead(CHANNEL7_IN_PIN))
  {
    ulStart = micros();
  }
  else
  {
    unChannel7InShared = (uint32_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL7_FLAG;
  }
}

void calcChannel8()
{
  static uint32_t ulStart;
 
  if(digitalRead(CHANNEL8_IN_PIN))
  {
    ulStart = micros();
  }
  else
  {
    unChannel8InShared = (uint32_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL8_FLAG;
  }
}


Wednesday, April 24, 2013

Problem reading RC Channels - The RCArduino Loop Back Test

Many people experience problems adding additional channels to the RCArduino test sketches or porting them to new devices, its usually down to mistakes in the way the additional channels are coded

This post presents an example of managing 8 input/output channels, its a very simple sketch which outputs 8 RC Channels and reads them right back in again.

The sketch can be used in three steps -

1) Initially the sketch outputs fixed values for the servos and reads them back in as a loop back test.

2) Once you are comfortable with the code, you can replace one or more of the loop back connections to start reading RC Channels. 

3) Once you are confident that the sketch is reading your channels correctly you can connect your servos and ESCs to the outputs and your done, 8 channels in, 8 channels out in three easy steps.


Step 1 - Loop back testing
To use the loop back test in step 1, connect pins 2 to 9 (the channel inputs) to pins 10 to 13 and A0 to A3 (the channel outputs).

Each channel is set to a fixed output from 1100 to 1800, if the code works on your board, your should see these values being output in the serial monitor.

Step 2 - RC Channel reading

Once you have this up and running, you can start swapping the connections to an RC receiver one by one. You should now see the channel values for the receiver channels updating in your serial monitor. If the values are within a range of around 1000 to 2000, your ready to move to step 3.

Step 3 - Full Control
To start outputting the values that you have read in, remove the comments from the servoName.writeMicroseconds functions to have full control of upto 8 servos/escs using 8 RC Receiver channels.

If it does not work, let me know which board you have, the code is easily adapted to work on any of the 8-bit Arduino boards. If you have a 32 bit Arduino Due, there is a dedicated post here -

http://rcarduino.blogspot.ae/2013/04/reading-rc-channels-with-arduino-due.html

For more performance and smoother output on the 8-bit Arduinos an RCArduinoFastLib versions will be added in separate in the coming days.

// RCArduino MultiChannel Loop back and servo ESC control for upto 8 RC channels
//
// rcarduino.blogspot.com
//
// A simple approach for reading three RC Channels using pin change interrupts
//
// See related posts -
// http://rcarduino.blogspot.co.uk/2012/01/how-to-read-rc-receiver-with.html
// http://rcarduino.blogspot.co.uk/2012/03/need-more-interrupts-to-read-more.html
// http://rcarduino.blogspot.co.uk/2012/01/can-i-control-more-than-x-servos-with.html
//
// rcarduino.blogspot.com
//

// include the pinchangeint library - see the links in the related topics section above for details
#include <PinChangeInt.h>

#include <Servo.h>

// Assign your channel in pins
#define CHANNEL1_IN_PIN 2
#define CHANNEL2_IN_PIN 3
#define CHANNEL3_IN_PIN 4
#define CHANNEL4_IN_PIN 5
#define CHANNEL5_IN_PIN 6
#define CHANNEL6_IN_PIN 7
#define CHANNEL7_IN_PIN 8
#define CHANNEL8_IN_PIN 9

// Assign your channel out pins
#define CHANNEL1_OUT_PIN 10
#define CHANNEL2_OUT_PIN 11
#define CHANNEL3_OUT_PIN 12
#define CHANNEL4_OUT_PIN 13
#define CHANNEL5_OUT_PIN A0
#define CHANNEL6_OUT_PIN A1
#define CHANNEL7_OUT_PIN A2
#define CHANNEL8_OUT_PIN A3

// Servo objects generate the signals expected by Electronic Speed Controllers and Servos
// We will use the objects to output the signals we read in
// this example code provides a straight pass through of the signal with no custom processing
Servo servoChannel1;
Servo servoChannel2;
Servo servoChannel3;
Servo servoChannel4;
Servo servoChannel5;
Servo servoChannel6;
Servo servoChannel7;
Servo servoChannel8;

// These bit flags are set in bUpdateFlagsShared to indicate which
// channels have new signals
#define CHANNEL1_FLAG 1
#define CHANNEL2_FLAG 2
#define CHANNEL3_FLAG 4
#define CHANNEL4_FLAG 8
#define CHANNEL5_FLAG 16
#define CHANNEL6_FLAG 32
#define CHANNEL7_FLAG 64
#define CHANNEL8_FLAG 128

// holds the update flags defined above
volatile uint8_t bUpdateFlagsShared;

// shared variables are updated by the ISR and read by loop.
// In loop we immediatley take local copies so that the ISR can keep ownership of the
// shared ones. To access these in loop
// we first turn interrupts off with noInterrupts
// we take a copy to use in loop and the turn interrupts back on
// as quickly as possible, this ensures that we are always able to receive new signals
volatile uint16_t unChannel1InShared;
volatile uint16_t unChannel2InShared;
volatile uint16_t unChannel3InShared;
volatile uint16_t unChannel4InShared;
volatile uint16_t unChannel5InShared;
volatile uint16_t unChannel6InShared;
volatile uint16_t unChannel7InShared;
volatile uint16_t unChannel8InShared;

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

  Serial.println("multiChannels");

  // attach servo objects, these will generate the correct
  // pulses for driving Electronic speed controllers, servos or other devices
  // designed to interface directly with RC Receivers
  servoChannel1.attach(CHANNEL1_OUT_PIN);
  servoChannel2.attach(CHANNEL2_OUT_PIN);
  servoChannel3.attach(CHANNEL3_OUT_PIN);
  servoChannel4.attach(CHANNEL4_OUT_PIN);
  servoChannel5.attach(CHANNEL5_OUT_PIN);
  servoChannel6.attach(CHANNEL6_OUT_PIN);
  servoChannel7.attach(CHANNEL7_OUT_PIN);
  servoChannel8.attach(CHANNEL8_OUT_PIN);

  // using the PinChangeInt library, attach the interrupts
  // used to read the channels
  PCintPort::attachInterrupt(CHANNEL1_IN_PIN, calcChannel1,CHANGE);
  PCintPort::attachInterrupt(CHANNEL2_IN_PIN, calcChannel2,CHANGE);
  PCintPort::attachInterrupt(CHANNEL3_IN_PIN, calcChannel3,CHANGE);
  PCintPort::attachInterrupt(CHANNEL4_IN_PIN, calcChannel4,CHANGE);
  PCintPort::attachInterrupt(CHANNEL5_IN_PIN, calcChannel5,CHANGE);
  PCintPort::attachInterrupt(CHANNEL6_IN_PIN, calcChannel6,CHANGE);
  PCintPort::attachInterrupt(CHANNEL7_IN_PIN, calcChannel7,CHANGE);
  PCintPort::attachInterrupt(CHANNEL8_IN_PIN, calcChannel8,CHANGE);

  // for loop back test only, lets set each channel to a known value
  servoChannel1.writeMicroseconds(1100);
  servoChannel2.writeMicroseconds(1200);
  servoChannel3.writeMicroseconds(1300);
  servoChannel4.writeMicroseconds(1400);
  servoChannel5.writeMicroseconds(1500);
  servoChannel6.writeMicroseconds(1600);
  servoChannel7.writeMicroseconds(1700);
  servoChannel8.writeMicroseconds(1800);
}

void loop()
{
  // create local variables to hold a local copies of the channel inputs
  // these are declared static so that thier values will be retained
  // between calls to loop.
  static uint16_t unChannel1In;
  static uint16_t unChannel2In;
  static uint16_t unChannel3In;
  static uint16_t unChannel4In;
  static uint16_t unChannel5In;
  static uint16_t unChannel6In;
  static uint16_t unChannel7In;
  static uint16_t unChannel8In;

  uint8_t bUpdateFlags = 0;
  // check shared update flags to see if any channels have a new signal
  // for nicely formatted serial output use this
  if(bUpdateFlagsShared == 0xFF)
  // for more responsive projects update any channels whenever a new signal is available using this
  // if(bUpdateFlagsShared)
  {
    noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables

    // take a local copy of which channels were updated in case we need to use this in the rest of loop
    bUpdateFlags = bUpdateFlagsShared;
  
    // in the current code, the shared values are always populated
    // so we could copy them without testing the flags
    // however in the future this could change, so lets
    // only copy when the flags tell us we can.
  

    if(bUpdateFlags & CHANNEL1_FLAG)
    {
      unChannel1In = unChannel1InShared;
    }
  
    if(bUpdateFlags & CHANNEL2_FLAG)
    {
      unChannel2In = unChannel2InShared;
    }
  
    if(bUpdateFlags & CHANNEL3_FLAG)
    {
      unChannel3In = unChannel3InShared;
    }

    if(bUpdateFlags & CHANNEL4_FLAG)
    {
      unChannel4In = unChannel4InShared;
    }
  
    if(bUpdateFlags & CHANNEL5_FLAG)
    {
      unChannel5In = unChannel5InShared;
    }
  
    if(bUpdateFlags & CHANNEL6_FLAG)
    {
      unChannel6In = unChannel6InShared;
    }
   
    if(bUpdateFlags & CHANNEL7_FLAG)
    {
      unChannel7In = unChannel7InShared;
    }
  
    if(bUpdateFlags & CHANNEL8_FLAG)
    {
      unChannel8In = unChannel8InShared;
    }
  
    // clear shared copy of updated flags as we have already taken the updates
    // we still have a local copy if we need to use it in bUpdateFlags
    bUpdateFlagsShared = 0;
  
    interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on
    // as soon as interrupts are back on, we can no longer use the shared copies, the interrupt
    // service routines own these and could update them at any time. During the update, the
    // shared copies may contain junk. Luckily we have our local copies to work with :-)
  }
 
  // do any processing from here onwards
  // only use the local values unAuxIn, unThrottleIn and unSteeringIn, the shared
  // variables unAuxInShared, unThrottleInShared, unSteeringInShared are always owned by
  // the interrupt routines and should not be used in loop
  if(bUpdateFlags & CHANNEL1_FLAG)
  {
      // when you are ready to add a servo or esc, remove the // from the following line to use the channel input to control it
      // servoChannel1.writeMicroseconds(unChannel1In);
      Serial.println("");
      Serial.print(bUpdateFlags);
      Serial.print(",");
      Serial.print(unChannel1In);
      Serial.print(",");
  }
 
  if(bUpdateFlags & CHANNEL2_FLAG)
  {
      // when you are ready to add a servo or esc, remove the // from the following line to use the channel input to control it
      // servoChannel2.writeMicroseconds(unChannel2In);
      Serial.print(unChannel2In);
      Serial.print(",");
  }
 
  if(bUpdateFlags & CHANNEL3_FLAG)
  {
      // when you are ready to add a servo or esc, remove the // from the following line to use the channel input to control it
      // servoChannel3.writeMicroseconds(unChannel3In);
      Serial.print(unChannel3In);
      Serial.print(",");
  }
 
  if(bUpdateFlags & CHANNEL4_FLAG)
  {
      // when you are ready to add a servo or esc, remove the // from the following line to use the channel input to control it
      // servoChannel4.writeMicroseconds(unChannel4In);
      Serial.print(unChannel4In);
      Serial.print(",");
  }
 
  if(bUpdateFlags & CHANNEL5_FLAG)
  {
      // when you are ready to add a servo or esc, remove the // from the following line to use the channel input to control it
      // servoChannel5.writeMicroseconds(unChannel5In);
      Serial.print(unChannel5In);
      Serial.print(",");
  }
 
  if(bUpdateFlags & CHANNEL6_FLAG)
  {
      // when you are ready to add a servo or esc, remove the // from the following line to use the channel input to control it
      // servoChannel6.writeMicroseconds(unChannel6In);
      Serial.print(unChannel6In);
      Serial.print(",");
  }
 
  if(bUpdateFlags & CHANNEL7_FLAG)
  {
      // when you are ready to add a servo or esc, remove the // from the following line to use the channel input to control it
      // servoChannel7.writeMicroseconds(unChannel7In);
      Serial.print(unChannel7In);
      Serial.print(",");
  }
 
  if(bUpdateFlags & CHANNEL8_FLAG)
  {
      // when you are ready to add a servo or esc, remove the // from the following line to use the channel input to control it
      // servoChannel8.writeMicroseconds(unChannel8In);
      Serial.print(unChannel8In);
      Serial.print(",");
  }
}


void calcChannel1()
{
  static uint32_t ulStart;
 
  if(PCintPort::pinState) // this is equivalent to digitalRead(CHANNEL1_IN_PIN) but about 10 times faster
  {
    ulStart = micros();
  }
  else
  {
    unChannel1InShared = (uint16_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL1_FLAG;
  }
}

void calcChannel2()
{
  static uint32_t ulStart;
 
  if(PCintPort::pinState)
  {
    ulStart = micros();
  }
  else
  {
    unChannel2InShared = (uint16_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL2_FLAG;
  }
}

void calcChannel3()
{
  static uint32_t ulStart;
 
  if(PCintPort::pinState)
  {
    ulStart = micros();
  }
  else
  {
    unChannel3InShared = (uint16_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL3_FLAG;
  }
}

void calcChannel4()
{
  static uint32_t ulStart;
 
  if(PCintPort::pinState)
  {
    ulStart = micros();
  }
  else
  {
    unChannel4InShared = (uint16_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL4_FLAG;
  }
}

void calcChannel5()
{
  static uint32_t ulStart;
 
  if(PCintPort::pinState)
  {
    ulStart = micros();
  }
  else
  {
    unChannel5InShared = (uint16_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL5_FLAG;
  }
}

void calcChannel6()
{
  static uint32_t ulStart;
 
  if(PCintPort::pinState)
  {
    ulStart = micros();
  }
  else
  {
    unChannel6InShared = (uint16_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL6_FLAG;
  }
}

void calcChannel7()
{
  static uint32_t ulStart;
 
  if(PCintPort::pinState)
  {
    ulStart = micros();
  }
  else
  {
    unChannel7InShared = (uint16_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL7_FLAG;
  }
}

void calcChannel8()
{
  static uint32_t ulStart;
 
  if(PCintPort::pinState)
  {
    ulStart = micros();
  }
  else
  {
    unChannel8InShared = (uint16_t)(micros() - ulStart);
    bUpdateFlagsShared |= CHANNEL8_FLAG;
  }
}
Duane B


Monday, April 22, 2013

Added TinyDebugSerial to attiny85

One of the challenges of 8-pins attiny85 is that we do not have Serial Monitor debugging after flashing the hex into the IC. As per my previous blog, without debugging output, we cannot be sure what is happening when the attiny is up and running.

While browsing the arduino forum, I came across this site that wrote about several methods to have serial communications to the attiny. Since I only have CSN & CE pins free when the nRF24L01 is not transmitting, I decide to go with the TinyDebugSerial method of serial output. This method will use the attiny85 PB3 pin and transmit to the Serial-TTL receiver or an Arduino.

You can use a USB-Serial TTL module or an Arduino to receive the serial transmitted by the attiny and only use one pin on the attiny. Since I have an extra USB FTDI to Serial TTL breakout board, I will use this board and also power up the attiny and nRF24L01 using the on-board selectable 5V/3.3V regulator. Choose 3.3V jumper as the nRF24L01 can only take up to 3.8V only.

attiny/nRF24L01 with FTDI BoB
The above image is my prototype with 6-pin ICSP header on top of the attiny85 with connections to the nRF24L01 and TX to the RX of the FTDI. When I am programming the attiny85, I had to remove the nRF24L01 transceiver and Vcc jumper cable from the FTDI as my USBtinyISP is providing power to the attiny85 and prevent the nRF24L01 transceiver from interfering the attiny85 during flashing/programming the chip. Once the USBtinyISP programming is done, I can immediately "see" the output from the USB-FTDI on my console/serial monitor. 

attiny to USB-Serial TTL


The first step is to install the new tiny cores from https://code.google.com/p/arduino-tiny/ and compile the codes with the new cores to make it everything is working without the extra codes. Once everything is working fine, I added the following lines to my codes :-


#include <TinyDebugSerial.h>
TinyDebugSerial mySerial = TinyDebugSerial();

// Put this in setup()
  mySerial.begin( 9600 );

// Put this in loop()

  mySerial.print("Sent :");
  mySerial.println(buffer);


The rest of the code is at the github repo under libraries/mirf85/examples at the link below.

When I tried to compiled it, I got the following compilation errors due to using an older version of WinAVR on Windows or older avr-gcc on Mac OSX software on the Arduino IDE 1.0.1.

"R_AVR_13_PCREL against symbol `exit' defined in .fini9 section in" 

Here are the links to the fixes and I will not rewrite it here... it have to do with an updated ld file for the avr.

Windows fixes :- Arduino Forum
Max OSX fixes :-  Arduino Forum

Once the above fixes is applied, I was able to see serial output on my USB-Serial on the serial monitor or any terminal program.

Summary Links :-
- Updated github repo
Serial Comms with attiny
Atmel AVR TinyISP
- Attiny cores https://code.google.com/p/arduino-tiny/ with TinyDebugSerial
Window fixes for R_AVR_13_PCREL
Mac OSX fixes for R_AVR_13_PCREL

Friday, April 12, 2013

Process of getting attiny85 to work with nRF24L01 on RF24 libraries

While getting Arduino or Raspberry Pi to talk to nRF24L01 was fun and challenging, trying to make it work for a 8-pin attiny85 is a whole different experience... without serial monitor or printf debugging to the display, after the firmware was flash into the attiny85, you could only guess what is happenning or not happening when nothing was received on the nRF24L01 receiver side...

Initially, I just assume that since the Atmel attiny85 does not have hardware SPI, getting nRF24L01 talking to the attiny was not so possible... but after a few searches and reading up some blogs and forums, things seems to look brighter...

attiny85 pinout

The second challenge was the usable pins on the attiny85, with 8 pins and two used by power and ground, only six pins are available... and the nRF24L01 radios uses the usual SPI - MOSI, MISO, CLK plus another two pins for SS/CSN and CE leaving only the reset pin unused.

The third challenge was size of the firmware, unlike Arduino UNO using atmega328 with 32Kb of flash, the attiny85 only have 8Kb of flash, so optimizing the code was really important, and this is the largest flash size of the attiny x5 series. See this link for the attiny comparison chart.

With the help of Alex from Insidegadgets.com, I start from a scaled down mirf codes ( mirf was the initial libraries for nRF24L01 written in C for the AVR ) using notepad, WinAVR and avrdude to compile and flash the firmware into the attiny85. Then I was using a ported version to Arduino IDE that makes things much more easier as Arduino IDE can still support USBtinyISP, the programmer I was using to flash firmware into the attiny85.

After a few unsuccessful retries, I decide to use a different approach and found on Arduino forum that someone had modified the Arduino SPI and mirf into ther attiny85 version called SPI85 and mirf85. After matching all the channels, data rate and CRC, I manage to get some packets on Serial Monitor with a mirf library on the Arduino UNO.

Since all my libraries are using RF24 for both the Arduino & Raspberry Pi, having a mirf library isn't too much useful for me. I went through all the codes and default settings and managed to configure the mirf to be compatible with RF24 library.

attiny85 nRF24L01 USBtinyISP


Here are a summary of differences between both the mirf and RF24 library :-

Data rate :
mirf : 2Mbps as it uses the default registry setting of the nRF24L01
RF24 : configurable via setDataRate()

CRC length :
mirf : 8bit CRC length
To make it work for the RF24, change the following header files directly :-
mirf85.h
#define mirf_CONFIG ((1<<EN_CRC) | (1<<CRCO) )

RF24 : configurable via setCRCLength()

Node addressing :
mirf : serv1 or clie1 ( 5 bytes in ascii format )
To talk to RF24 receiver, use the following format,  :-

    byte RADDR[] = {0xe2, 0xf0, 0xf0, 0xf0, 0xf0};
    byte TADDR[] = {0xe3, 0xf0, 0xf0, 0xf0, 0xf0};


RF24: f0f0f0f0e2 format ( 5 bytes in hex format )

Optional settings :-

Enable Dynamic Payload :
I had my RF24 receiver with dynamic payload enabled so that I only need to set the payload size on transmitter only and can use different payload length instead of the max length.. set the below to mirf codes to enable dynamic payload.

mirf :
Mirf.configRegister( FEATURE, 1<<EN_DPL );
Mirf.configRegister( DYNPD, 1<<DPL_P0 | 1<<DPL_P1 | 1<<DPL_P2 | 1<<DPL_P3 | 1<<DPL_P4 | 1<<DPL_P5 );

I've compiled all the SPI85 and mirf85 files at github repo at the summary links below.

Summary Links :-

https://github.com/stanleyseow/arduino-nrf24l01
Insidegadgets.com
- Arduino forum




Thursday, April 11, 2013

The Problem ( and Solutions ) With Arduino Interrupts

If you have ever tried to port an Arduino project that uses interrupts from one board type to another, you have probably experienced frustration, this includes the sample code throughout RCArduino.


The following post examines the differences in interrupts between the popular boards, the Arduino UNO, Micro, Mega, Mini and Leonardo. Based on this information we can modify sketches to run on the full range of 8-bit Arduinos.

The 8-bitArduino boards are based on one of three related chips -

ATMega328 - UNO and Mini
ATMega32u4 - Leonardo and Micro
ATMega2560 - Mega

Each of these chips supports two types of interrupts -

1) External Interrupts
These are flexible easy to use interrupts which can be triggered by rising, falling or changing signals. The disadvantage is that there are a limited number available on each chip type.

If we want to access more interrupts we need to look at the next type -

2) Pin Change Interrupts
The underlying chip in your Arduino supports a second type of interrupt however these interrupts are not directly supported by Arduino and need to be accessed through an additional library.

Differences In External Interrupts

The external interrupts are associated with specific digital pins on each chip type, the following table taken from the attachInterrupt reference page lists the available external interrupts and the associated Arduino pin on each chip -


Boardint.0int.1int.2int.3int.4int.5
Uno, Ethernet,
Mini
23
Mega25602321201918
Leonardo, Micro3201


The Arduino team have hidden some of the differences between the ATMega328 and ATM2560 so that attaching INT0 using the attachInterrupt function will attach an interrupt to digital pin 2 on both chips even though on the Mega digital pin2 is actually INT4.

The same logic has not been carried across to the ATMega32u4 Based leonardo. Notice how int0 and int1 are actually reversed on the Leonardo, this will be a major trap for people who are porting code from the UNO.


Does the Leonardo have four external interrupts ?
While the Leonardo appears to have 4 external interrupts, int2 and int3 are attached to digital pins 0 and 1 which are almost always reserved for serial input/output. So yes there are four interrupts, but two of them are only available by disabling serial functionality.

Differences In Pin Change Interrupts
On the Arduino UNO, pin change interrupts can be used to enable interrupts on any of the Arduino PINs to give access to a total of 19 interrupts (13 digital pins and 6 Analog pins).

I initially assumed that this was also possible on the Mega, Micro and Leonardo as well. It isn't.

Pin change interrupts are supported on the following Leonardo/Micro pins - 8,9,10 and 11.

Pin change interrupts are supported on Arduino Mega pins 10,11,12,13,14,15 and analog pins 6 to 15

Interrupts and RCArduino
These differences between the Arduino platforms will have been responsible for some of the difficulty that users have had in porting RCArduino code to Minis, Micros, Leonardos and Megas.

The good news is that now we have a full understanding of the inconsistencies between the different devices there should be no problem in modifying the sample sketches to run on them.

If your having trouble with a sample sketch, get in touch, in the meantime I will be updating some of the sketches to work across multiple boards.

Stay tuned

Duane B

Sunday, April 7, 2013

Serial Communication Tutorial (Part 3)





In the previous two parts of the this tutorial, we went through a number of simple sketches to get you acquainted with the way that the Arduino handles various data types when passed through the Serial COM port. Here are the main themes from part ONE:
  • Stage One:  Echoing data with the Arduino
  • Stage Two: Using Delimiters to split data.
  • Stage Three:Arduino Maths, simple addition
  • Stage Four:Sending a double to an Arduino, and then doubling it.
  • Stage Five:Sending Sensor data from the Arduino to the Serial Monitor

Here are the main themes from Part TWO:

  • Stage Six:......A simple Processing Sketch
  • Stage Seven: Arduino and Processing join forces for more fun
  • Stage Eight: A simple project that shows Serial communication from Arduino to Processing

In Part Three - we will reverse the direction of communication and get Processing to send data to the Arduino via a USB cable,

  • Stage Nine: A simple processing sketch that switches an LED on the Arduino
  • Stage Ten:  A processing sketch that reads from a text file
  • Stage Eleven: A processing sketch that reads data from a text file and sends to the Arduino
  • Stage Twelve: A processing sketch that trasmits data from a file to another Arduino via an XBee module.



Stage Nine - Using your computer to switch an LED

In this stage we create a simple Arduino sketch which will receive a simple command from the Processing Sketch to switch an LED. The Processing sketch will allow you to turn an LED on/off by clicking on the Processing Application window. It will detect the press of the mouse, and will send a command to the Arduino via the USB Serial COM port.

Parts Required:
  • Arduino UNO or compatible board
  • USB cable
  • Arduino and Processing IDE (on computer)
Arduino Logo The Arduino Sketch
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
style="color: rgb(0, 128, 0);">/* ===================================================
style="color: rgb(0, 128, 0);">Simple number reader: Written by ScottC - 07 Apr 2013
style="color: rgb(0, 128, 0);"> Arduino Version: 1.04
style="color: rgb(0, 128, 0);">======================================================*/

style="color: rgb(0, 128, 0);">// The onboard LED is on pin # 13
style="color: rgb(43, 145, 175);">int onboardLED = 13;


style="color: rgb(43, 145, 175);">void setup() {
style="color: rgb(0, 128, 0);">// Begin Serial communication
Serial.begin(9600);

style="color: rgb(0, 128, 0);">//Set the onboard LED to OUTPUT
pinMode(onboardLED, OUTPUT);
}

style="color: rgb(43, 145, 175);">void loop(){
style="color: rgb(0, 128, 0);">/* Read serial port, if the number is 0, then turn off LED
style="color: rgb(0, 128, 0);"> if the number is 1 or greater, turn the LED on. */
style="color: rgb(0, 0, 255);">while (Serial.available() > 0) {
style="color: rgb(43, 145, 175);">int num=Serial.read()-style="color: rgb(163, 21, 21);">'0';
style="color: rgb(0, 0, 255);">if(num<1){
digitalWrite(onboardLED, LOW); style="color: rgb(0, 128, 0);">//Turn Off LED
} style="color: rgb(0, 0, 255);">else{
digitalWrite(onboardLED, HIGH); style="color: rgb(0, 128, 0);">//Turn On LED
}
}
}


Processing icon The Processing Sketch
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
style="color: rgb(0, 128, 0);">/*===========================================================
style="color: rgb(0, 128, 0);"> Toggle Switch: Send Number to Arduino
style="color: rgb(0, 128, 0);"> Written by Scott C on 07 Apr 2013
style="color: rgb(0, 128, 0);"> Processing Version: 2.0b8
style="color: rgb(0, 128, 0);">=============================================================*/

import processing.serial.*;

Serial comPort;
boolean ledState=style="color: rgb(0, 0, 255);">false; style="color: rgb(0, 128, 0);">//LED is off

style="color: rgb(43, 145, 175);">void setup(){
style="color: rgb(0, 128, 0);">//Open COM Port for Communication
comPort = style="color: rgb(0, 0, 255);">new Serial(style="color: rgb(0, 0, 255);">this, Serial.list()[0], 9600);
background(255,0,0); style="color: rgb(0, 128, 0);">//Start with a Red background
}

style="color: rgb(43, 145, 175);">void draw(){
}


style="color: rgb(43, 145, 175);">void mousePressed() {
style="color: rgb(0, 128, 0);">//Toggle led ON and OFF
ledState=!ledState;

style="color: rgb(0, 128, 0);">//If ledState is True - then send a value=1 (ON) to Arduino
style="color: rgb(0, 0, 255);">if(ledState){
background(0,255,0); style="color: rgb(0, 128, 0);">//Change the background to green

style="color: rgb(0, 128, 0);">/*When the background is green, transmit
style="color: rgb(0, 128, 0);"> a value=1 to the Arduino to turn ON LED */
comPort.write(style="color: rgb(163, 21, 21);">'1');
}style="color: rgb(0, 0, 255);">else{
background(255,0,0); style="color: rgb(0, 128, 0);">//Change background to red
comPort.write(style="color: rgb(163, 21, 21);">'0'); style="color: rgb(0, 128, 0);">//Send "0" to turn OFF LED.
}
}




The Video


Stage Ten: Reading from a Text File

We are now going to give the Arduino a rest (for a moment) and concentrate on a Processing Sketch that will read from a text file. Once we learn this skill, we can then build this Processing functionality into our Arduino Projects. Reading from a text file in Processing is actually quite easy if you use the loadStrings()method. However, it is best if you make things easy for yourself by using delimiters. The most common delimitter is a "comma". The comma allows the computer to group information according to your needs.
  • 11,22,33,44,55,66
  • 1,1,2,2,3,3,4,4,5,5,6,6
  • 112,223,334,455,566
The examples above contain the same numbers but are delimitted in different ways.
We are going to import a few different numbers/letters and store them in an array. We will then iterate through the array to display the values within.
So let us now create the text file. Copy and paste the following text into notepad and save the file, but remember where you save it, because we will need to know location and the name of the file in order to read from in.

NotepadIconCopy and Paste into Notepad:
100,200,A,B,C,10.2,0.1,wx,yz,arduinobasics





Save the file
I am going to call my file data.txt, and will be saving it to my D drive, so the file will be located here:
  • D:/data.txt

We will now create the processing sketch to read the text file and display the data on the screen.
We will use the comma delimiters to separate the data so that it displays in the following way:




Processing icon The Processing Sketch
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
style="color: rgb(0, 128, 0);">/* =============================================================
style="color: rgb(0, 128, 0);"> ReadTextFile and Display on Screen:
style="color: rgb(0, 128, 0);"> Written by ScottC on 15th April 2013 using
style="color: rgb(0, 128, 0);"> Processing version 2.0b8
style="color: rgb(0, 128, 0);">
style="color: rgb(0, 128, 0);"> Website: http://arduinobasics.blogspot.com/
style="color: rgb(0, 128, 0);"> Projects: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html
style="color: rgb(0, 128, 0);">
style="color: rgb(0, 128, 0);"> References:
style="color: rgb(0, 128, 0);"> Displaying Text: http://processing.org/reference/text_.html
style="color: rgb(0, 128, 0);"> Reading Text File: http://processing.org/reference/loadStrings_.html
style="color: rgb(0, 128, 0);">=================================================================*/

style="color: rgb(43, 145, 175);">void setup(){
size(180,250);
background(255);

style="color: rgb(0, 128, 0);">/* Read the text file */
String[] lines = loadStrings(style="color: rgb(163, 21, 21);">"D:/data.txt");
style="color: rgb(43, 145, 175);">int numOfLines=lines.length;
style="color: rgb(0, 0, 255);">for(style="color: rgb(43, 145, 175);">int i=0;i<numOfLines;i++){

style="color: rgb(0, 128, 0);">/* Split the data based on a "," delimiter. */
String[] data = splitTokens(lines[i], style="color: rgb(163, 21, 21);">",");
style="color: rgb(43, 145, 175);">int dataCount = data.length;

style="color: rgb(0, 0, 255);">for(style="color: rgb(43, 145, 175);">int j=0; j<dataCount; j++){
style="color: rgb(0, 128, 0);">/* Set the size and colour of the text */
textSize(16);
fill(100,100,255,50+(j*20));

style="color: rgb(0, 128, 0);">/* Display the text on the screen */
text(data[j],10,16+(16*j));
}
}
}


style="color: rgb(43, 145, 175);">void draw(){
}

The code above has the ability to display data from multiple lines within the text file, however for simplicity, I have chosen to use a single line. If I wanted to display more than one line, I would have to change the "for-loops".



Stage Eleven: Read Text File and send to Arduino

In stage 10 we used the Processing  programming language to import a line of data from a text file, break-up the line into pieces (based on comma delimiters) and then displayed the data on the Computer Screen. We will now use this knowledge and take it one step further. We will create a text file, import the data using processing, but this time we will send the data to the Arduino. Meanwhile the Arduino will be waiting patiently for this data, and once it receives the data, it will react according to our needs. We are going to keep this simple. The goal is to send two different letters from the Computer to the Arduino. One letter will turn an LED on, and the other letter will turn the LED off. We will also send an integer to tell the Arduino how long to keep the LED on or off.

GOAL:  Turn an LED on and off by reading a text file.
Our first step in this process is to create a text file that will store our important data. We will store two variables in this file. The first variable will be used to tell the Arduino whether we want to turn the LED on or whether we want to turn the LED off. We will use the letter "O" to turn the LED on, and use the letter "X" to turn the LED off.
The second variable will be a time based variable. It will be used to tell the Arduino "how long" to keep the LED on or off. We will store this variable as an integer and will represent time in "milliseconds".
  • 1000 milliseconds = 1 second
It makes sense to keep these two variables as a pair, however we will separate them using a comma delimitter. We will separate each command by putting the variables on a new line. Copy and paste the following data into notepad (or equivalent text editor), and save the file to your harddrive. I have saved this file as

  • D:/LEDdata.txt

NotepadIconText File Data:Here is the data to put into your text file (notepad):
X,50
O,45
X,40
O,35
X,30
O,25
X,20
O,15
X,10
O,5
X,10
O,15
X,20
O,25
X,30
O,35
X,40
O,45
X,50
O,55
X,60
O,65
X,70
O,75
X,80
O,85
X,90
O,95
X,100
O,200
X,200
O,200
X,500
O,500
X,500
O,500
X,20
O,20
X,20
O,20
X,20
O,20
X,20
O,20
X,20
O,20
X,200
O,20
X,20
O,20
X,20
O,20
X,20
O,20
X,20
O,20
X,20
O,20
X,200
O,20
X,20
O,20
X,20
O,20
X,20
O,20
X,20
O,20
X,200
O,20
X,20
O,20
X,20
O,20
X,20
O,20
X,20
O,20
X,20
O,20
X,20
O,20
X,20



We will now set up the Arduino to accept data from the Computer and react to the Letters
  • "O" to turn the LED on
  • "X" to turn the LED off
  • "E" will be used to test for a successful Serial connection.
We will also get the Arduino to interpret the second variable which will be used to set the amount of time to keep the LED on or off.


Arduino LogoArduino Code:
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
style="color: rgb(0, 128, 0);">/* Read TextFile Data: Written by ScottC on 24 April 2013
style="color: rgb(0, 128, 0);"> Arduino IDE version: 1.0.4
style="color: rgb(0, 128, 0);"> http://arduinobasics.blogspot.com.au/2013/04/serial-communication-tutorial-part-3.html
style="color: rgb(0, 128, 0);">*/

style="color: rgb(0, 128, 0);">/* Global Variables */
byte byteRead; style="color: rgb(0, 128, 0);">//Used to receive data from computer.
style="color: rgb(43, 145, 175);">int timeDelay; style="color: rgb(0, 128, 0);">//time that the LED is On or Off
style="color: rgb(43, 145, 175);">int maxtimeDelay=10000; style="color: rgb(0, 128, 0);">//Maximum time delay = 10 seconds
style="color: rgb(43, 145, 175);">int ledPin=13; style="color: rgb(0, 128, 0);">//LED connected to pin 13 on Arduino UNO.

style="color: rgb(43, 145, 175);">void setup() {
style="color: rgb(0, 128, 0);">//Set pin 13 (ledPin) as an output
pinMode(ledPin, OUTPUT);
style="color: rgb(0, 128, 0);">// Turn the Serial Protocol ON
Serial.begin(9600);
}

style="color: rgb(43, 145, 175);">void loop() {
style="color: rgb(0, 128, 0);">/* check if data has been sent from the computer: */
style="color: rgb(0, 0, 255);">if (Serial.available()) {
style="color: rgb(0, 128, 0);">/* read the most recent byte */
byteRead = Serial.read();

style="color: rgb(0, 0, 255);">switch (byteRead) {
style="color: rgb(0, 0, 255);">case 69: style="color: rgb(0, 128, 0);">//This is an enquiry, send an acknowledgement
Serial.println(style="color: rgb(163, 21, 21);">"A");
style="color: rgb(0, 0, 255);">break;
style="color: rgb(0, 0, 255);">case 79: style="color: rgb(0, 128, 0);">//This is an "O" to turn the LED on
digitalWrite(ledPin, HIGH);
style="color: rgb(0, 0, 255);">break;
style="color: rgb(0, 0, 255);">case 88: style="color: rgb(0, 128, 0);">//This is an "X" to turn the LED off
digitalWrite(ledPin, LOW);
style="color: rgb(0, 0, 255);">break;
style="color: rgb(0, 0, 255);">case 46: style="color: rgb(0, 128, 0);">//End of line
style="color: rgb(0, 128, 0);">//Make sure time delay does not exceed maximum.
style="color: rgb(0, 0, 255);">if(timeDelay > maxtimeDelay){
timeDelay=maxtimeDelay;
}
style="color: rgb(0, 128, 0);">//Set the time for LED to be ON or OFF
delay(timeDelay);
Serial.println(style="color: rgb(163, 21, 21);">"S");
timeDelay=0; style="color: rgb(0, 128, 0);">//Reset timeDelay;
style="color: rgb(0, 0, 255);">break;
style="color: rgb(0, 0, 255);">default:
style="color: rgb(0, 128, 0);">//listen for numbers between 0-9
style="color: rgb(0, 0, 255);">if(byteRead>47 && byteRead<58){
style="color: rgb(0, 128, 0);">//number found, use this to construct the time delay.
timeDelay=(timeDelay*10)+(byteRead-48);
}
}
}
}

Our next step is to import the data in the text file into Processing and then send the data to the Arduino. You may want to review Stage 10 of this tutorial for another example of importing text file data into Processing. You may also want to review stage 7 which shows how to receive data from an Arduino.
We will import all of the data from the file when we push a button on the Processing Window, and send this data to the Arduino via the USB cable that is connected to the computer. We are going to use the same COM port that the Computer uses to upload Arduino Sketches, therefore it is important that you close the Arduino Serial Monitor before you run the processing sketch, otherwise you will get an error which states that the COM port is not available.


Processing iconProcessing Code:
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
style="color: rgb(0, 128, 0);">/* TextFile Data sender (Stage 11) 
style="color: rgb(0, 128, 0);"> Written by ScottC on 24th April 2013
style="color: rgb(0, 128, 0);"> using Processing Version 2.0b8
style="color: rgb(0, 128, 0);">
style="color: rgb(0, 128, 0);"> The full tutorial can be found here:
style="color: rgb(0, 128, 0);"> http://arduinobasics.blogspot.com/2013/04/serial-communication-tutorial-part-3.html
style="color: rgb(0, 128, 0);">*/

import processing.serial.*;

Serial comPort; style="color: rgb(0, 128, 0);">//The com port used between the computer and Arduino
style="color: rgb(43, 145, 175);">int counter=0; style="color: rgb(0, 128, 0);">// Helps to keep track of values sent.
style="color: rgb(43, 145, 175);">int numItems=0; style="color: rgb(0, 128, 0);">//Keep track of the number of values in text file
String comPortString; style="color: rgb(0, 128, 0);">//String received From Arduino
String textFileLines[]; style="color: rgb(0, 128, 0);">//Array of text file lines
String lineItems[]; style="color: rgb(0, 128, 0);">//Array of line items

style="color: rgb(43, 145, 175);">void setup(){
comPort = style="color: rgb(0, 0, 255);">new Serial(style="color: rgb(0, 0, 255);">this, Serial.list()[0], 9600); style="color: rgb(0, 128, 0);">//Setup the COM port
comPort.bufferUntil(style="color: rgb(163, 21, 21);">'\n'); style="color: rgb(0, 128, 0);">//Generate a SerialEvent when a newline is received
background(255,0,0); style="color: rgb(0, 128, 0);">//Start with a Red background
}

style="color: rgb(0, 128, 0);">/* Draw method is not used in this sketch */
style="color: rgb(43, 145, 175);">void draw(){
}

style="color: rgb(0, 128, 0);">//When the mouse is pressed, write an "E" to COM port.
style="color: rgb(0, 128, 0);">//The Arduino should send back an "A" in return. This will
style="color: rgb(0, 128, 0);">//generate a serialEvent - see below.
style="color: rgb(43, 145, 175);">void mousePressed() {
comPort.write(style="color: rgb(163, 21, 21);">"E");
}

style="color: rgb(43, 145, 175);">void serialEvent(Serial cPort){
comPortString = cPort.readStringUntil(style="color: rgb(163, 21, 21);">'\n');
style="color: rgb(0, 0, 255);">if(comPortString != null) {
comPortString=trim(comPortString);

style="color: rgb(0, 128, 0);">/*If the String received = A, then import the text file
style="color: rgb(0, 128, 0);"> change the background to Green, and start by sending the
style="color: rgb(0, 128, 0);"> first line of the text file to the Arduino */
style="color: rgb(0, 0, 255);">if(comPortString.equals(style="color: rgb(163, 21, 21);">"A")){
textFileLines=loadStrings(style="color: rgb(163, 21, 21);">"D:/LEDdata.txt");
background(0,255,0);
sendLineNum(counter);
}

style="color: rgb(0, 128, 0);">/*If the the String received = S, then increment the counter
style="color: rgb(0, 128, 0);"> which will allow us to send the next line in the text file.
style="color: rgb(0, 128, 0);"> If we have reached the end of the file, then reset the counter
style="color: rgb(0, 128, 0);"> and change the background colour back to red. */
style="color: rgb(0, 0, 255);">if(comPortString.equals(style="color: rgb(163, 21, 21);">"S")){
counter++;
style="color: rgb(0, 0, 255);">if(counter > (textFileLines.length-1)){
background(255,0,0);
counter=0;
} style="color: rgb(0, 0, 255);">else {
sendLineNum(counter);
}
}
}
}


style="color: rgb(0, 128, 0);">/*The sendLineNum method is used to send a specific line
style="color: rgb(0, 128, 0);"> from the imported text file to the Arduino. The first
style="color: rgb(0, 128, 0);"> line item tells the Arduino to either switch the LED on or off.
style="color: rgb(0, 128, 0);"> The second line item, tells the Arduino how long to keep the
style="color: rgb(0, 128, 0);"> LED on or off. The full-stop is sent to the Arduino to indicate
style="color: rgb(0, 128, 0);"> the end of the line. */

style="color: rgb(43, 145, 175);">void sendLineNum(style="color: rgb(43, 145, 175);">int lineNumber){
lineItems=splitTokens(textFileLines[lineNumber],style="color: rgb(163, 21, 21);">",");
comPort.write(lineItems[0]);
comPort.write(lineItems[1]);
comPort.write(style="color: rgb(163, 21, 21);">".");
}


Stage Twelve: To be continued..


I need to finish my XBee tutorial before doing this stage. But am just about to start studying again. So this stage probably won't get completed for another couple of months. But I hope there is enough content to keep you satisfied for the time being.





100,000 view Celebration

      Image source

Just had a mini celebration. My Blog just hit 100,000 page-views. 

To celebrate this milestone I have given the Arduino Basics Blog a little face lift (just in case you wondering why things looked a little different). If this is the first time you have seen my site, I would encourage you to have a look at my projects page, where you will find some of my Arduino/Processing tutorials and more recently the introduction of Android and Bluetooth. 

 Thank you to each and every one of you who have spent some time at my site, and I really hope that my effort in putting these tutorials together has either inspired you, or helped you. I have learnt a lot in the process... but this is just the beginning. 

Friday, April 5, 2013

Finally got all RPi & UNO combinations working for nRF24L01

I have finally setup my second Raspberry Pi with 512M memory, clone the github RF24 ( https://github.com/stanleyseow/RF24 ) and can finally test all the combinations :-

rpi-hub.cpp


sendto_hub.cpp
Possible combo :-

- Raspberry Pi as hub
- Arduino as node

- Raspberry Pi as hub
- Raspberry Pi as node

- Arduino as hub
- Arduino as node

- Aduino as hub
- Raspberry Pi as node




If anyone got the above codes tested on other platform like  Arduino Mega2560, Due or other platforms, please let me know the details and links so that I can update my summary links for others..

My latest github repo have combined forked from https://github.com/gcopeland/RF24/ and I've added some of the changes into the Raspberry Pi codes.

Do read an articl from Greg on RF24 performance enchantments at http://maniacalbits.blogspot.com/2013/04/rf24-avoiding-rx-pipe-0-for-enhanced.html



As usual, I've all summary links below :-

- Raspberry Pi as hub ( rpi-hub.cpp )
- Raspberry Pi as node ( sendto_hub.cpp )

- Arduino as hub nRF24_Arduino_as_hub
- Arduino as node nRF24_sendto_hub





Monday, April 1, 2013

Bluetooth Android Processing 4

PART FOUR

The Video





This is part 4 of my tutorial on designing an Android Phone Bluetooth App using the Android/Processing language. The App sends information to an Arduino via Bluetooth after pressing a button on the phone. The RGB LED attached to the Arduino Uno (or compatible board) will change colour depending on the button being pressed on the phone. The Arduino gains Bluetooth capabilities through the Seeedstudio Bluetooth shield (which can be found here).

Parts 1-3 of the tutorial were designed to take you step-by-step through designing the app. If you are wondering what you missed, here is a summary:

This is what you'll find in part one:
  • Downloading and setting up the Android SDK
  • Downloading the Processing IDE
  • Setting up and preparing the Android device
  • Running through a couple of Processing/Android sketches on an Andoid phone.

This is what you will find in part two:

  • Introducing Toasts (display messages)
  • Looking out for BluetoothDevices using BroadcastReceivers
  • Getting useful information from a discovered Bluetooth device
  • Connecting to a Bluetooth Device
  • An Arduino Bluetooth Sketch that can be used in this tutorial

This is what you will find in part three:

  • InputStreams and OutputStreams
  • Error Logs using logcat
  • Testing the InputStreams and OutputStreams
  • Using the APWidgets library to create buttons
  • Adding Buttons to the BlueTooth Project



In Part 4, we simplify and strip down the App so that it will only sends a specific String to the Arduino via Bluetooth. The String sent to the Arduino depends on the Button being pressed. The code has been cleaned up and has many comments to help you understand what is going on. You should be able to run this sketch without having to go back through parts one, two or three of the tutorial. This fourth part of the tutorial was designed for those people who want the final end product, and are happy to work it out for themselves. I hope this serves you well.
I will therefore assume that you have already setup your phone and have downloaded all the neccesary drivers, libraries, SDKs and IDEs. If not, then here are a few quick links:
If you are a bit lost and want want a bit more information then please go through parts one, two and three of this tutorial.
Make sure that you have selected the Bluetooth permissions as per the following:

  • Android > Sketch permissions  (as per the picture below)


Make sure that BLUETOOTH and BLUETOOTH_ADMIN are selected (as per the picture below). Then press the OK button.



Then copy and paste the following sketch into the processing/android IDE:

Android/Processing Sketch 9: Bluetooth App2
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
/* BluetoothApp2: Written by ScottC on 1st April 2013 using 
Processing version 2.0b8
Tested on a Samsung Galaxy SII, with Android version 2.3.4
Android ADK - API 10 SDK platform
Apwidgets version: r44 : http://code.google.com/p/apwidgets/
*/


/*------------------------------------------------------------------------------
IMPORT statements required for this sketch
-----------------------------------------------------------------------------*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;

import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;
import android.util.Log;

import apwidgets.APWidgetContainer;
import apwidgets.APButton;
import apwidgets.APWidget;
import apwidgets.OnClickWidgetListener;


/*------------------------------------------------------------------------------
GLOBAL Variables to be used between a number of classes.
-----------------------------------------------------------------------------*/
public int[] bg={0,80,0};
public BluetoothDevice btShield = null;
public BluetoothSocket btSocket = null;
public OutputStream btOutputStream = null;
public APWidgetContainer widgetContainer=null;
public Connect2BtDevice ConBTdevice=new Connect2BtDevice();



/*------------------------------------------------------------------------------
The following variables are used to setup the Buttons used in the GUI
of the phone. It includes the variables that determine the
- text on the buttons
- the number of buttons
- the letters that will be sent to Arduino when the buttons are pressed
- the colour that the background will change to when the buttons are pressed
- the dimensions of the buttons (width and height)
- The gap between each button
-----------------------------------------------------------------------------*/
String[] buttonText = { "RED", "GREEN", "BLUE", "OFF"}; //Button Labels
String[] sendLetter={"r","g","b","x"}; //Letters to send when button pressed
int n= buttonText.length; //Number of buttons
int[][] buttonColour = { {255,10,10},
{10,255,10},
{10,10,255},
{0,0,0}
}; //The Background colour on phone when button pressed


APButton[] guiBtns = new APButton[n]; //Array of buttons
int gap=10; //gap between buttons
int buttonWidth=0; //initialising the variable to hold the WIDTH of each button
int buttonHeight=0; //initialising the variable to hold the HEIGHT of each button




/*------------------------------------------------------------------------------
The setup() method is used to connect to the Bluetooth Device, and setup
the GUI on the phone.
-----------------------------------------------------------------------------*/
void setup(){
new Thread(ConBTdevice).start(); //Connect to SeeedBTSlave device
orientation(LANDSCAPE); //Make GUI appear in landscape mode

//Setup the WidgetContainer and work out the size of each button
widgetContainer = new APWidgetContainer(this);
buttonWidth=((width/n)-(n*(gap/2))); //button width depends on screen width
buttonHeight=(height/2); //button height depends on screen height

//Add ALL buttons to the widgetContainer.
for(int i=0; i<n;i++){
guiBtns[i]= new APButton(((buttonWidth*i)+(gap*(i+1))), gap, buttonWidth, buttonHeight, buttonText[i]);
widgetContainer.addWidget(guiBtns[i]);
}
}



/*------------------------------------------------------------------------------
The draw() method is only used to change the colour of the phone's background
-----------------------------------------------------------------------------*/
void draw(){
background(bg[0],bg[1],bg[2]);
}




/*------------------------------------------------------------------------------
onClickWidget is called when a button is clicked/touched, which will
change the colour of the background, and send a specific letter to the Arduino.
The Arduino will use this letter to change the colour of the RGB LED
-----------------------------------------------------------------------------*/
void onClickWidget(APWidget widget){
String letrToSend="";

/*Identify the button that was pressed, Change the phone background
colout accordingly and choose the letter to send */
for(int i=0; i<n;i++){
if(widget==guiBtns[i]){
ConBTdevice.changeBackground(buttonColour[i][0],
buttonColour[i][1],
buttonColour[i][2]);
letrToSend=sendLetter[i];
}
}

/* Send the chosen letter to the Arduino/Bluetooth Shield */
if(ConBTdevice!=null){
ConBTdevice.write(letrToSend);
}
}



/*==============================================================================
CLASS: Connect2BtDevice implements Runnable
- used to connect to remote bluetooth device and send values to the Arduino
==================================================================================*/
public class Connect2BtDevice implements Runnable{

/*------------------------------------------------------------------------------
Connect2BtDevice CLASS Variables
-----------------------------------------------------------------------------*/
BluetoothAdapter btAdapter=null;
BroadcastReceiver broadcastBtDevices=null;
private UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");



/*------------------------------------------------------------------------------
DEFAULT CONSTRUCTOR: Connect2BtDevice()
- Create a BroadcastReceiver (registered in run() method).
- Get the default Bluetooth Adapter
- Enable the adapter (if it is not already enabled).
- Discover available Bluetooth devices to connect to
-----------------------------------------------------------------------------*/
public Connect2BtDevice(){
broadcastBtDevices = new btBroadcastReceiver();
getBtAdapter();
enableBtAdapter();
discoverBtDevices();
}



/*------------------------------------------------------------------------------
run() method
- used to register the broadcast receiver only
-----------------------------------------------------------------------------*/
@Override
public void run() {
registerReceiver(broadcastBtDevices, new IntentFilter(BluetoothDevice.ACTION_FOUND));
}



/*------------------------------------------------------------------------------
getBtAdapter() method
- get the default Bluetooth adapter
-----------------------------------------------------------------------------*/
void getBtAdapter(){
btAdapter = BluetoothAdapter.getDefaultAdapter();
}



/*------------------------------------------------------------------------------
enableBtAdapter() method
- Enable the default Bluetooth Adapter if it isn't already enabled
-----------------------------------------------------------------------------*/
void enableBtAdapter(){
if (!btAdapter.isEnabled()) {
btAdapter.enable();
}
}



/*------------------------------------------------------------------------------
discoverBtDevices() method
- Discover other Bluetooth devices within range (ie SeeedBTSlave device)
-----------------------------------------------------------------------------*/
void discoverBtDevices(){
while(!btAdapter.isEnabled()){
//Wait until the Bluetooth Adapter is enabled before continuing
}
if (!btAdapter.isDiscovering()){
btAdapter.startDiscovery();
}
}



/*------------------------------------------------------------------------------
connect2Bt() method: called by the btBroadcastReceiver
- Create a BluetoothSocket with the discovered Bluetooth device
- Change background to yellow at this step
- Connect to the discovered Bluetooth device through the BluetoothSocket
- Wait until socket connects then
- Attach an outputStream to the BluetoothSocket to communicate with Bluetooth
device. (ie. Bluetooth Shield on the the Arduino)
- Write a "g" string through the outputStream to change the colour of the LED
to green and change the phone background colour to green also.
A green screen and green LED suggests a successful connection, plus the
Bluetooth shield's onboard LED starts flashing green slowly (1 per second),
which also confirms the successful connection.
-----------------------------------------------------------------------------*/
void connect2Bt(){
try{
btSocket = btShield.createRfcommSocketToServiceRecord(uuid);
changeBackground(255,255,0); //YELLOW Background
try{
btSocket.connect();
while(btSocket==null){
//Do nothing
}
try {
btOutputStream = btSocket.getOutputStream();
changeBackground(0,255,0); //Green Background
write("g"); //Green LED (Successful connection)
}catch (IOException e) {
Log.e("ConnectToBluetooth", "Error when getting output Stream");
}
}catch(IOException e){
Log.e("ConnectToBluetooth", "Error with Socket Connection");
changeBackground(255,0,0); //Red background
}
}catch(IOException e){
Log.e("ConnectToBluetooth", "Error with Socket Creation");
changeBackground(255,0,0); //Red background
try{
btSocket.close(); //try to close the socket
}catch(IOException closeException){
Log.e("ConnectToBluetooth", "Error Closing socket");
}return;
}
}


/*------------------------------------------------------------------------------
write(String str) method
- Allows you to write a String to the remote Bluetooth Device
-----------------------------------------------------------------------------*/
public void write(String str) {
try {
btOutputStream.write(stringToBytes(str));
} catch (IOException e) {
Log.e("Writing to Stream", "Error when writing to btOutputStream");
}
}



/*------------------------------------------------------------------------------
byte[] stringToBytes(String str) method
- Used by the write() method
- This method is used to convert a String to a byte[] array
- This code snippet is from Byron:
http://www.javacodegeeks.com/2010/11/java-best-practices-char-to-byte-and.html
-----------------------------------------------------------------------------*/
public byte[] stringToBytes(String str) {
char[] buffer = str.toCharArray();
byte[] b = new byte[buffer.length << 1];
for(int i = 0; i < buffer.length; i++) {
int bpos = i << 1;
b[bpos] = (byte) ((buffer[i]&0xFF00)>>8);
b[bpos + 1] = (byte) (buffer[i]&0x00FF);
}
return b;
}



/*------------------------------------------------------------------------------
cancel() method
- Can be called to close the Bluetooth Socket
-----------------------------------------------------------------------------*/
public void cancel() {
try {
btSocket.close();
} catch (IOException e){
}
}



/*------------------------------------------------------------------------------
changeBackground(int bg0, int bg1, int bg2) method
- A method to change the background colour of the phone screen
-----------------------------------------------------------------------------*/
void changeBackground(int bg0, int bg1, int bg2){
bg[0] = bg0;
bg[1] = bg1;
bg[2] = bg2;
}
}


/*==============================================================================
CLASS: btBroadcastReceiver extends BroadcastReceiver
- Broadcasts a notification when the "SeeedBTSlave" is discovered/found.
- Use this notification as a trigger to connect to the remote Bluetooth device
==================================================================================*/
public class btBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action=intent.getAction();
/* Notification that BluetoothDevice is FOUND */
if(BluetoothDevice.ACTION_FOUND.equals(action)){
/* Get the discovered device Name */
String discoveredDeviceName = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);

/* If the discovered Bluetooth device Name =SeeedBTSlave then CONNECT */
if(discoveredDeviceName.equals("SeeedBTSlave")){
/* Get a handle on the discovered device */
btShield = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
/* Connect to the discovered device. */
ConBTdevice.connect2Bt();
}
}
}
}


Here is a picture of the components used in this sketch:
Bluetooth Shield with Grove RGB LED



Please take notice of the Jumper pin placement on the Bluetooth Shield. This ensures communication between the Arduino and Bluetooth Shield, and is reflected in the Arduino code further down this page. The Arduino transmits information to the Bluetooth Shield on Digital pin 7, and therefore the Bluetooth Shield receivesinformation from the Arduino on Digital pin 7. On the other hand, the Bluetooth shield transmits and the Arduino receives information on Digital pin 6 (see picture below).  This serial communication between the Arduino and the Bluetooth Shield occurs through the SoftwareSeriallibrary. This is different from the Serial library used in some of my other tutorials (often to display information in the Serial Monitor). The Arduino UNO's Serial pins are 0 (RX) and 1 (TX). It is worth looking at the Arduino Serialpage if you happen to have an Arduino Leonardo, because there are some differences that you should take into consideration when running this sketch.



Jumpers on Shield


Make sure that your Arduino has the following code installed and running BEFORE you launch the Android/Processing Sketch on your Android Device. If you don't do it in this order, your Android phone will not discover the Bluetooth Device attached to the Arduino, and you will waste a lot of time. Make sure that the Bluetooth shield is flashing it's red/green LEDs. Once you see this alternating red/green LED display, launch the Android/Processing sketch on the Android device. When you see the chainable RGB LED turn from white to green, you know you have a successful connection. You may then press the GUI buttons on the Android phone to change the colour of the LED to either Red, Green, Blue or Off.

Arduino Sketch 3: Bluetooth RGB Colour Changer (with OFF option)

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* This project combines the code from a few different sources.
This project was put together by ScottC on the 15/01/2013
http://arduinobasics.blogspot.com/

Bluetooth slave code by Steve Chang - downloaded from :
http://www.seeedstudio.com/wiki/index.php?title=Bluetooth_Shield

Grove Chainable RGB code can be found here :
http://www.seeedstudio.com/wiki/Grove_-_Chainable_RGB_LED#Introduction

Updated on 25 March 2013: Receive 'x' to turn off RGB LED.

*/


#include <SoftwareSerial.h>
//Software Serial Port

#define uint8
unsigned char
#define uint16
unsigned int
#define uint32
unsigned long int

#define RxD 6
// This is the pin that the Bluetooth (BT_TX) will transmit to the Arduino (RxD)
#define TxD 7
// This is the pin that the Bluetooth (BT_RX) will receive from the Arduino (TxD)

#define DEBUG_ENABLED 1

int Clkpin = 9; //RGB LED Clock Pin (Digital 9)
int Datapin = 8; //RGB LED Data Pin (Digital 8)

SoftwareSerial blueToothSerial(RxD,TxD);
/*----------------------SETUP----------------------------*/ void setup() {
Serial.begin(9600);
// Allow Serial communication via USB cable to computer (if required)
pinMode(RxD, INPUT);
// Setup the Arduino to receive INPUT from the bluetooth shield on Digital Pin 6
pinMode(TxD, OUTPUT);
// Setup the Arduino to send data (OUTPUT) to the bluetooth shield on Digital Pin 7
pinMode(13,OUTPUT);
// Use onboard LED if required.
setupBlueToothConnection();
//Used to initialise the Bluetooth shield

pinMode(Datapin, OUTPUT);
// Setup the RGB LED Data Pin
pinMode(Clkpin, OUTPUT);
// Setup the RGB LED Clock pin

}
/*----------------------LOOP----------------------------*/ void loop() {
digitalWrite(13,LOW);
//Turn off the onboard Arduino LED
char recvChar;
while(1){
if(blueToothSerial.available()){//check if there's any data sent from the remote bluetooth shield
recvChar = blueToothSerial.read();
Serial.print(recvChar);
// Print the character received to the Serial Monitor (if required)

//If the character received = 'r' , then change the RGB led to display a RED colour
if(recvChar=='r'){
Send32Zero();
// begin
DataDealWithAndSend(255, 0, 0);
// first node data
Send32Zero();
// send to update data
}

//If the character received = 'g' , then change the RGB led to display a GREEN colour
if(recvChar=='g'){
Send32Zero();
// begin
DataDealWithAndSend(0, 255, 0);
// first node data
Send32Zero();
// send to update data
}

//If the character received = 'b' , then change the RGB led to display a BLUE colour
if(recvChar=='b'){
Send32Zero();
// begin
DataDealWithAndSend(0, 0, 255);
// first node data
Send32Zero();
// send to update data
}

//If the character received = 'x' , then turn RGB led OFF
if(recvChar=='x'){
Send32Zero();
// begin
DataDealWithAndSend(0, 0, 0);
// first node data
Send32Zero();
// send to update data
}
}

//You can use the following code to deal with any information coming from the Computer (serial monitor)
if(Serial.available()){
recvChar = Serial.read();

//This will send value obtained (recvChar) to the phone. The value will be displayed on the phone.
blueToothSerial.print(recvChar);
}
}
}

//The following code is necessary to setup the bluetooth shield ------copy and paste----------------
void setupBlueToothConnection()
{
blueToothSerial.begin(38400);
//Set BluetoothBee BaudRate to default baud rate 38400
blueToothSerial.print("
\r\n+STWMOD=0\r\n"); //set the bluetooth work in slave mode
blueToothSerial.print("
\r\n+STNA=SeeedBTSlave\r\n"); //set the bluetooth name as "SeeedBTSlave"
blueToothSerial.print("
\r\n+STOAUT=1\r\n"); // Permit Paired device to connect me
blueToothSerial.print("
\r\n+STAUTO=0\r\n"); // Auto-connection should be forbidden here
delay(2000);
// This delay is required.
blueToothSerial.print("
\r\n+INQ=1\r\n"); //make the slave bluetooth inquirable
Serial.println("
The slave bluetooth is inquirable!");
delay(2000);
// This delay is required.
blueToothSerial.flush();
}

//The following code snippets are used update the colour of the RGB LED-----copy and paste------------
void ClkProduce(void){
digitalWrite(Clkpin, LOW);
delayMicroseconds(20);
digitalWrite(Clkpin, HIGH);
delayMicroseconds(20);
}
void Send32Zero(void){
unsigned char i;
for (i=0; i<32; i++){
digitalWrite(Datapin, LOW);
ClkProduce();
}
}

uint8 TakeAntiCode(uint8 dat){
uint8 tmp = 0;
if ((dat & 0x80) == 0){
tmp |= 0x02;
}

if ((dat & 0x40) == 0){
tmp |= 0x01;
}

return tmp;
}
// gray data
void DatSend(uint32 dx){
uint8 i;
for (i=0; i<32; i++){
if ((dx & 0x80000000) != 0){
digitalWrite(Datapin, HIGH);
}
else {
digitalWrite(Datapin, LOW);
}

dx <<= 1;
ClkProduce();
}
}
// data processing
void DataDealWithAndSend(uint8 r, uint8 g, uint8 b){
uint32 dx = 0;

dx |= (uint32)0x03 << 30;
// highest two bits 1,flag bits
dx |= (uint32)TakeAntiCode(b) << 28;
dx |= (uint32)TakeAntiCode(g) << 26;
dx |= (uint32)TakeAntiCode(r) << 24;

dx |= (uint32)b << 16;
dx |= (uint32)g << 8;
dx |= r;

DatSend(dx);
}


Please note that this Arduino code/project will work with SeeedStudio's Bluetooth Shield.  You may need to modify the Arduino Code (lines 95-107) to coincide with your own bluetooth shield. I got the code snippet within the my setupBlueToothConnection() method from some example code from Steve Chang which was found on SeeedStudio's Bluetooth Shield Wiki page. Here is some other useful information in relation to setting up this Bluetooth Shield that could be of help in your project (here).

Much of the code used within the Android/Processing sketch was made possible through constant reference to these sites:
And I would also like to thank Pauline303 who made the suggestion within the Processing Forums to use APWidgets Library for my Buttons in the App.
The Arduino and Processing Forums are always a great place to get help in a short amount of time.