Netduino Electromyograph (EMG)

One of CodeClub’s sponsors is Orion Health so I had been looking for some reasonably priced sensors for health focused projects. We already use the SeeedStudio Heart rate sensor for one of our projects so I ordered a Grove EMG Detector for evaluation.

Netduino with Seeedstudio EMG

Netduino with Grove EMG Detector

The EMG detector outputs a single analog signal which we connected to analog input 0. For the proof of concept we averaged for 500 samples to determine the steady state offset.

for (int sampleCounter = 0; sampleCounter < calibrationSampleCount; sampleCounter++)
{
   double value = emg.Read();
   sampleSum += value;
}
offset = sampleSum / calibrationSampleCount ;

We then read the analog input applied the offset and displayed the magnitude of the signal on a Seeedstudio LED bar using code written by Famoury Toure

while(true)
{
   double value = emg.Read() - offset;

   if (value < valueMinimum) { valueMinimum = value; } if (value > valueMaximum)
   {
      valueMaximum = value;
   }
   range = valueMaximum - valueMinimum;

   if (value < 0)
   {
      value = value / valueMaximum * 10.0;
   }
   else
   {
      value = value / valueMinimum * 10.0;
   }

   Debug.Print("Val " + value.ToString("F3") + " Max " + valueMaximum.ToString("F3") + " Min " +valueMinimum.ToString("F3"));

   int bar = 1;
   value = 10.0 - value;
   bar = bar << (int)value ;
   ledBar.setLED((uint)bar);
   Thread.Sleep(100);
   }
}

Bill of Materials (Prices as at October 2014)

The proof of concept worked surprisingly well, the LED illuminated on the LED bar appeared to move in response to arm movements and when I clenched my fist.

Electric Vehicle Camp 2014-06

The Hardware

The software

Flash an LED

OutputPort led = new OutputPort(Pins.ONBOARD_LED, false);
while ( true)
{
   Led.Write(!Led.Read())
   Thread.Sleep(500)
}

Digital Input – Polled

InputPort button = new InputPort(Pins.ONBOARD_SW1, false, Port.ResistorMode.Disabled);
OutputPort led = new OutputPort(Pins.ONBOARD_LED, false);
while (true)
{
   led.Write(button.Read());
   Thread.Sleep(1000);
}

Digital Input – Interrupt

static OutputPort interuptled = new OutputPort(Pins.ONBOARD_LED, false);
InterruptPort button = new InterruptPort(Pins.ONBOARD_SW1, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
button.OnInterrupt += new NativeEventHandler(button_OnInterrupt);&amp;amp;lt;/span&amp;amp;gt;&amp;amp;lt;/code&amp;amp;gt;

Thread.Sleep(Timeout.Infinite);
static void button_OnInterrupt(uint data1, uint data2, DateTime time)
{
   interuptled.Write(!interuptled.Read());
}

Analog Input

AnalogInput Sensor = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);
while ( true)
{
   Debug.Print( &quot;Value &quot; + Sensor.Read(&quot;F2&quot;));
   Thread.Sleep(500)
}

Pulse Width Modulation Output

AnalogInput brightness = new AnalogInput(AnalogChannels.ANALOG_PIN_A0);
PWM led = new PWM(PWMChannels.PWM_PIN_D5, 1000, 0.0, false);

led.Start();

while (true)
{
   Debug.Print(&amp;amp;quot;Brightness &amp;amp;quot; + led.DutyCycle.ToString("F2"));
   led.DutyCycle = brightness.Read();
   Thread.Sleep(500);
}
led.Stop();

Telemetry – Mobile station

Configure the NRF24L01 library for the  elecfreaks Joystick ShieldV2.4, for more detail see this post 

_module.OnDataReceived += OnReceive;
_module.OnTransmitFailed += OnSendFailure;
_module.OnTransmitSuccess += OnSendSuccess;
_module.Initialize(SPI.SPI_module.SPI1, Pins.GPIO_PIN_D10, Pins.GPIO_PIN_D9, Pins.GPIO_PIN_D1);
_module.Configure(myAddress, channel);
_module.Enable();

Timer joystickPositionUpdates = new Timer(JoyStickTimerProc, null, 500, 500);
Thread.Sleep( Timeout.Infinite ) ;

Send the data to the base station (converting it from Unicode to ASCII)

private void JoyStickTimerProc(object state)
{
   double xVal = x.Read();
   double yVal = y.Read();
   Debug.Print("X " + xVal.ToString("F1") + " Y &" + yVal.ToString("F1"));

   _module.SendTo(baseStationAddress, Encoding.UTF8.GetBytes( xVal.ToString("F1") + " " + yVal.ToString("F1")));
}

Telemetry – Base Station

Configure the NRF24L01 library for the Embedded Coolness board, for more detail see this post

private readonly NRF24L01Plus _module;

_module.OnDataReceived += OnReceive;
_module.OnTransmitFailed += OnSendFailure;
_module.OnTransmitSuccess += OnSendSuccess;

_module.Initialize(SPI.SPI_module.SPI1, Pins.GPIO_PIN_D7, Pins.GPIO_PIN_D3, Pins.GPIO_PIN_D2);
_module.Configure(_myAddress, channel);
_module.Enable();

Display the inbound message (converting it from ASCII to Unicode)

private void OnReceive(byte[] data)
{
string message = new String(Encoding.UTF8.GetChars(data));
Debug.Print("Receive " + message); ;
}

Code Camp Christchurch 2014

The Hardware

Flash an LED

OutputPort led = new OutputPort(Pins.ONBOARD_LED, false);
while ( true)
{
   Led.Write(!Led.Read())
   Thread.Sleep(500)
}

Digital Input – Polled

InputPort button = new InputPort(Pins.ONBOARD_SW1, false, Port.ResistorMode.Disabled);
OutputPort led = new OutputPort(Pins.ONBOARD_LED, false);
while (true)
{
   led.Write(button.Read());
   Thread.Sleep(1000);
}

Digital Input – Interrupt

static OutputPort interuptled = new OutputPort(Pins.ONBOARD_LED, false);
InterruptPort button = new InterruptPort(Pins.ONBOARD_SW1, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
button.OnInterrupt += new NativeEventHandler(button_OnInterrupt);

Thread.Sleep(Timeout.Infinite);

static void button_OnInterrupt(uint data1, uint data2, DateTime time)
{
   interuptled.Write(!interuptled.Read());
}

Analog Input

AnalogInput Sensor = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);
while ( true)
{
   Debug.Print( "Value " + Sensor.Read().ToString("F2"));
   Thread.Sleep(500);
}

Pulse Width Modulation Output

AnalogInput brightness = new AnalogInput(AnalogChannels.ANALOG_PIN_A0);
PWM led = new PWM(PWMChannels.PWM_PIN_D5, 1000, 0.0, false);

led.Start();
while (true)
{
   Debug.Print("Brightness " + led.DutyCycle.ToString("F2"));
   led.DutyCycle = brightness.Read();
   Thread.Sleep(500);
}
led.Stop();

Power Consumption Monitor

Developing the software for the Energy Monitor Shield

Robot

Developing the software

  • Determine the distance to objects
  • Control the speed & direction of the motors using a Motor Shield Driver
  • Basic obstacle avoidance
  • Avoid obstacles using a state machine
  • Fine tune the motor speeds using a rotary encoder
  • Connect the GPS
  • Upload the position information to Xively

Heart Rate Monitor

Developing the software

  • Read the buttons using an AnalogInput
  • Count the number of button presses using an InterruptPort and a Timer
  • Determine the pulse rate in BPM by counting
  • Determine the average pulse rate in BPM
  • Display and manage the pulse rate info on the DFRobot 16×2 Lcd Shield
  • Upload the pulse rate information to xively

 

Canterbury Software Cluster Internet of Things Presentation

For my presentation last week I prepared a sample xively and Netduino based application to illustrate what could be built with off the shelf kit. I built a wireless home monitoring system which had two energy consumption monitoring devices and a dual temperature sensor device. These devices uploaded their data using MQTT to xively in close to real time. Prices as at May 2014

The devices connected to the internet via a gateway.

Image

The software running on the Netduino was built using the NetMF library from KittyHawkMQ and the nRF24L01+ library from codeplex

Testing the solar powered temperature sensor monitoring my kitchen fridge. The fridge was 4° and the freezer was -18°

Image

The software was based on the nRF24L01library on codeplex,  Brad’s One-Wire and DS18B20 library with fixes from here.

Testing the power consumption monitor devices, with my “modified” power lead.

Image

The software was based on the approach in the Arduino code of the emon libraries from the Open Energy Monitor project which I’ll discuss in more detail in a future post.

Freaduino MP3 Music Shield

For code club one of the projects I had been considering was an MP3 player with a simple user interface (UI) based on a joystick providing track next/previous , volume up/down, and pause/play. I looked for suitable Arduino shields which had Netduino driver support. I narrowed the list down to (Prices as at April 2014) these VS1053 based shields

For Code Club I purchased 5 of the Elecfreaks Freaduino shields as the price and on-board joystick made it ideal for our application. The Freaduino MP3 Shield wiki page indicated that the following pins were used by the SPI bus

D10 – Used for SPI Chip Select.
D11 – Used for SPI MOSI.
D12 – Used for SPI MISO.
D13 – Used for SPI SCK.

I initially tried the NetduinoVS1053 library from SoftElectoTech but found that no sound was produced. I tried different pin configurations, format and bitrate music files but nothing worked. I then had a look at the shield schematic and noticed that D11/D12/D13 were not connected to the VS1053, only D10 which is used for chip selected on the MicroSD card socket was connected.

I soldered some jumpers to the board and connected the SPI pins on the ICSP socket to the D11,D12 & D13 on the edge connector and the shield now works. It would be good if elecfreaks could make the pins the SPI bus uses configurable using jumpers or similar.

Modified Freaduino Music Shield

Modified Freaduino Music Shield

The library needs to be initialised with the following pins

Player = newVs1053B(Pins.GPIO_PIN_A1, Pins.GPIO_PIN_A3, Pins.GPIO_PIN_A2, Pins.GPIO_PIN_A0);

The joystick operations can be handled with Interrupts with the following configuration

InterruptPort volumeDownButton = newInterruptPort(Pins.GPIO_PIN_D7, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow);

InterruptPort volumeUpButton = newInterruptPort(Pins.GPIO_PIN_D3, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow);

InterruptPort nextSongButton = newInterruptPort(Pins.GPIO_PIN_D4, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow);

InterruptPort previousSongButton = newInterruptPort(Pins.GPIO_PIN_D6, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow);

InterruptPort playStopButton = newInterruptPort(Pins.GPIO_PIN_D5, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow);

volumeUpButton.OnInterrupt += new NativeEventHandler(volumeUpButton_OnInterrupt);

volumeDownButton.OnInterrupt += new NativeEventHandler(volumeDownButton_OnInterrupt);

nextSongButton.OnInterrupt += new NativeEventHandler(nextSongButton_OnInterrupt);

previousSongButton.OnInterrupt += new NativeEventHandler(previousSongButton_OnInterrupt);

playStopButton.OnInterrupt += new NativeEventHandler(playStopButton_OnInterrupt);

I could now play MP3 files off the SD card on my Netduino Plus 2 but couldn’t adjust the volume or change the track being played. Using an interrupt based approached for the UI also highlighted some problems with the driver code which I will discuss in a future post.

Netduino Plus PulseRate Monitor V2

In the final couple of code club sessions we built a pulse rate monitor to show a practical application for the NetMF InterruptPort, and communication between threads using the Interlocked class (Increment & exchange). This was then enhanced to display the data locally and upload it to the cloud to illustrate a basic HTTP interaction and serial communications.

The application displays the approximate pulse rate in Beats Per Minute (BPM) on a 16×2 character LCD display and also uploads the information to a free developer account at Xively a “Public Cloud for the Internet of Things”.

Netduino Plus 2 rate monitor

The xively trial account has a limit of 25 calls a minute, rolling 3 minute average (Dec 2013) which was more than adequate for our application and many other educational projects.

The xively API supports managing products, managing devices,  reading & writing data, reading & wiring metadata, querying historical data and searching for data feeds, using a RESTful approach.

The NetduinoPlus2 has full support for the NetMF system.http and sufficient memory so that there is plenty of room left for an application. If you are using a Netduino Plus (or other NetMF device with limited memory) an approach which reduces memory consumption is detailed here.

The xively data API supports JSON, XML and CSV formats for upload of data and for the pulse rate monitor we used CSV. The following code was called roughly every 20 seconds.

static void xivelyFeedUpdate( string ApiKey, string feedId, string channel, string value )
{
try
{
using (HttpWebRequest request = (HttpWebRequest)WebRequest.Create(xivelyApiBaseUrl+ feedId + ".csv"))
{
byte[] buffer = Encoding.UTF8.GetBytes(channel + "," + value);


request.Method = "PUT";
request.ContentLength = buffer.Length;
request.ContentType = "text/csv";
request.Headers.Add("X-ApiKey", ApiKey);
request.KeepAlive = false;
request.Timeout = 5000;
request.ReadWriteTimeout = 5000;


// request body
using (Stream stream = request.GetRequestStream())
{
stream.Write(buffer, 0, buffer.Length);
}


using (var response = (HttpWebResponse)request.GetResponse())
{
Debug.Print("HTTP Status:" + response.StatusCode + " : " + response.StatusDescription);
}
}
}
catch (Exception ex)
{
Debug.Print(ex.Message);
}
}

The pulse rate information can then displayed by xively in tables and graphs.

Pulse Rate data gaph at xively

Pulse Rate data display

At the end of term presentation several parents and family members were doing press-ups and other exercises to see how high their pulse rate went and how quickly it recovered.

Bill of materials (Prices as at Dec 2013)

SeeedStudio Grove GPS IteadStudio Shield Comparison

I use the SeeedStudio Grove system for prototyping and teaching. One of the modules is a Global Positioning System (GPS) unit based on the u-blox 5 engine. To get this unit to work you just plug it into the UART socket on the base shield and load the necessary software onto an Arduino (or compatible) board. My day job is working on Microsoft .Net applications so I use a Netduino Plus or a Netduino plus 2.

SeeedStudio GPS unit

SeeedStudio base shield and GPS unit

The Seeedstudio 4 wire connector system has some advantages but for a couple of projects I was looking at I needed to be able to run on a different serial port and access the one pulse per second output. I had a look at several other vendors and the iteadstudio GPS Shield + Active Antenna which is based on the u-blox 6 engine looked like a reasonable alternative.

IteadStudio GPS

IteadStudio GPS shield and Antenna

After some testing I found that the Iteadstudio GPS shield appears to have a shorter time to first fix after a power cycle, I averaged 10 sets of readings for each device and found that in my backyard it took on average 46sec for the Iteadstudio shield and 55sec for the SeeedStudio device.

Both devices output National Marine Electronics Association (NMEA) 0183 sentences and I use the NetMF Toolbox NMEA code to process the data streams. I have modified the NetMF toolbox code with an additional event handler which empties the serial input buffer if there is an error and one of the validation checks needed to be tweaked as it was possible to get an exception due to an empty string.

Around line 45

this._Uart = newSerialPort(SerialPort, BaudRate);
this._Uart.ErrorReceived += newSerialErrorReceivedEventHandler(_Uart_ErrorReceived);
this._Uart.DataReceived += newSerialDataReceivedEventHandler(_Uart_DataReceived);


void _Uart_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
if (_Uart.IsOpen)
{
_Uart.Flush();
}
}

Around line 323

// Have we received a full line of data?
int Pos = this._Buffer.IndexOf("\r\n");
if (Pos >= 1)
{

With these modifications my Netduino Plus 2 can runs for days at a time without buffer overflows or other issues, you just need to be careful to make your event handlers block for as little time as possible.

I have been looking at building an NetMF NMEA driver which runs on a background thread and doesn’t use any string manipulation methods e.g. string.splt so the garbage collector has less to do, but this will be a topic for a future post.

netduino Plus + nerf supersoaker

A few weeks ago my 6 year old son took his Nerf SuperSoaker to the beach and the salt water damaged the battery pack. Yesterday he pulled it apart to see how it worked and after a couple of quick tests with the multimeter we worked out the switch on the battery pack was the problem.

While it was dismantled we decided to “enhance” it with a Netduino+ and an ultrasonic range finder so it squirted water automatically when a target got with 2.5m. The code for the Ultrasonic range finder was adapted from Dave’s code on Netduino.com

Netduino SuperSoaker++

Bill of Materials

MyFirst mobile phone for Code club

One of my co-workers is involved with a group that run “code clubs” at local schools teaching high school students how to code.

We got talking about projects which would appeal to the students and I suggested making a mobile phone. This is my prototype

Image

It’s more Nokia 5110 than Nokia Lumia 820

If you want to build your own (the parts list will grow as I add GPS, accelerometer, compass, screen etc..)

For V0.1 of code one button sends and SMS to my mobile, the other button initiates a voice call to my mobile. The initial version of the code was based on the SeeedStudio GSM Shield Netduino driver on codeplex.

The later versions are based on the CodeFreakout Seeedstudio GPRS Shield drivers which are available via NuGet. I have added some functionality for dialling and hanging up voice calls which I will post for others to use once I have tested it some more.

I2C read rates on Netduino Plus vs Netduino plus 2

As part of my quadcopter project I purchased a Netduino Plus 2 for the flight controller. The increased performance 48MHz vs. 168MHz CPU and other improvements looked like it could make it possible to implement most or all of the control algorithms in C#.

So I could compare the performance of the I2C interfaces I setup two test rigs which polled an ADXL345 Accelerometer (using the Love Electronics sample code) 10,000 times for X,Y & Z acceleration values.

NetduinoPlusAccelerometer

The different I2C pins on the Netduino plus 2 required some jumper cables

Netduino2PlusAccelerometer

Both devices were running NetMF 4.2 and I monitored the output of the test harness using MF Deploy.

Netduino Plus

22.2797,22.3126,22.3313,22.3129,22.3590,22.3689,22.3497,22.3049,22.3649,22.3836

Average 22.3 seconds roughly 450/sec

Netduino Plus 2

6.8312,6.8059,6.8003,6.8051,6.8319,6.7999,6.8104,6.8194,6.8233,6.8096

Average 6.8 seconds roughly 1470/sec