Netduino Plus PulseRate Monitor V1

In the final couple of code club sessions we built a pulse rate monitor to illustrate a practical application for the NetMF InterruptPort, and communication between threads using Interlocked (Increment & exchange). The V1 application displays the approximate pulse rate in Beats Per Minute (BPM) using Debug.Print.

The SeeedStudio Grove Ear clip heart rate sensor strobes a digital input for each heart beat it detects and this is used to trigger an interrupt handler. In the interrupt handler we incremented a counter using Interlocked.Increment.

A timer fires every 15 seconds which takes a copy of the current count, resets it to zero using Interlocked.Exchange. This code then multiplies the count by the number of times the timer fires per minute to convert it to BPM for display.

We discussed different approaches for determining the pulse rate and for V1 a 15 second timer seemed to be a reasonable trade off between accuracy and reading update latency.

Netduino Plus rate monitor

Pulserate monitor

public class Program
{
   const int mSecPerMinute = 60000;
   const int displayUpdateRatemSec = 15000;
   private static InterruptPort heartBeatSensor = new InterruptPort(Pins.GPIO_PIN_D1, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
   private static OutputPort heartBeatDisplayLed = new OutputPort(Pins.GPIO_PIN_D6, false);
   private static int heartBeatCount = 0;</code>

   public static void Main()
   {
      heartBeatSensor.OnInterrupt += pulse_OnInterrupt;
      Timer pulseRateDisplayTimer = new Timer(PulseRateDisplayTimerCallback, null, displayUpdateRatemSec, displayUpdateRatemSec);
      Thread.Sleep(Timeout.Infinite);
   }

   static void pulse_OnInterrupt(uint data1, uint data2, DateTime time)
   {
      heartBeatDisplayLed.Write(!heartBeatDisplayLed.Read());
      Interlocked.Increment(ref heartBeatCount);
   }

   static void PulseRateDisplayTimerCallback(object state)
   {
      int displayPulseCount ;</code>

      displayPulseCount = Interlocked.Exchange(ref heartBeatCount, 0 );
      displayPulseCount = displayPulseCount * (mSecPerMinute / displayUpdateRatemSec);
      Debug.Print("Pulse rate " + displayPulseCount + " bpm");
   }
}

Bill of materials (Prices as at Dec 2013)

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

Some fun with a Netduino Plus and the icndb

A chat with some co-workers about displaying the status of the team’s Jenkins build process led to bit of research into calling RESTful services and JSON support on NetMF devices. Previously this had required a bit of hand crafted code but now it looks like the library support has matured a bit. I don’t run Jenkins at home so I decided to build a NetduinoPlus client for the internet Chuck Norris database which has a RESTful API.

This API returns Chuck Norris “facts”…

“Chuck Norris doesn’t read books. He stares them down until he gets the information he wants.”
“There is no theory of evolution, just a list of creatures Chuck Norris allows to live.”
“Some people wear Superman pajamas. Superman wears Chuck Norris pajamas.”
“Chuck Norris can slam a revolving door.”

The icndb API returns JSON

{ "type": "success", "value": { "id": 109, "joke": "It takes Chuck Norris 20 minutes to watch 60 Minutes.", "categories": [] } }

I used the NetMF system.HTTP libraries to initiate the request and Json.NetMF to unpack the response. This snippet illustrates how I processed the request/response

using (HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"http://api.icndb.com/jokes/random"))
{
   //request.Proxy = proxy;
   request.Method = "GET";
   request.KeepAlive = false;
   request.Timeout = 5000;
   request.ReadWriteTimeout = 5000;

   using (var response = (HttpWebResponse)request.GetResponse())
   {
      if (response.StatusCode == HttpStatusCode.OK)
      {
         byte[] buffer = new byte[response.ContentLength];

         using (Stream stream = response.GetResponseStream())
         {
            stream.Read(buffer, 0, (int)response.ContentLength);

            string json = new string(Encoding.UTF8.GetChars(buffer));

            Hashtable jsonPayload = JsonSerializer.DeserializeString(json) as Hashtable;

            Hashtable value = jsonPayload["value"] as Hashtable ;
            Debug.Print(value["joke"].ToString());
         }
      }
   }
}

icndb Netduino client

Bill of materials

HTTPS with NetMF calling an Azure Service Bus endpoint

Back in Q1 of 2013 I posted a sample application which called an Azure Service Bus end point just to confirm that the certificate configuration etc. was good.

Since I published that sample the Azure Root certificate has been migrated so I have created a new project which uses the Baltimore Cyber Trust Root certificate.

The sample Azure ServiceBus client uses a wired LAN connection (original one used wifi module) and to run it locally you will have to update the Date information around line 24.

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.

Someone else has a working NetMF Quadcopter

So according to cuno and co NetMF is a viable processing platform for a quadcopter. I was worried about the GC and it looks like as long as I’m really careful about allocating memory (strings, buffers etc.) I should be okay. It will be like writing code for embedded micro controllers (V25 & HC11) in C not long after I left university,

Have also been reading up about proportional-integral-derivative controllers (PID controller) here and building a basic C# implementation.

Next step some PWM code for interfacing to my Turnigy Multistar 10 Amp ESCs. I wonder if my larger scale quadcopter will cause any issues?

SQL Azure Database performance oddness

For a few years I have worked on a midsize Azure application for managing promotional vouchers which are delivered via SMS or email and redeemed via software integrated into the point of sale terminal software of several local vendors.

A promotion has a batch of vouchers which are available for allocation to consumers and I had noticed from the logs and performance counters that the process of getting the next voucher slowed down significantly as the number of available vouchers decreased.

Voucher batches range in size from 100’s to 100,000’s of vouchers and the performance of a small promotion for a local wine shop was where I initially noticed how much the duration increased. The promotion had roughly 850 vouchers the allocation of the first vouchers took 10’s of mSec each but the last 10 vouchers sometimes took more than 1000mSec each.

I took a copy of the live database and removed the customer data so I could explore the performance of my TSQL in a controlled environment. I initially downloaded a copy of the database to one of my development servers and tried to simulate the problem while monitoring performance using SQL Profiler and other tools but the allocation time was fast and consistent.

The database performance appeared to be a SQL Azure specific issue so I built a cut back web role test harness which called the underlying stored procedure so I could closely monitor the performance. The test harness could make a specified number of calls recording the duration of each call and the overall duration. I then de allocated all the vouchers in the wine shop promotion and allocated them in chunks(all durations are in mSec and are the average time it takes to make a single call)

100 vouchers at a time (0 – 800 of 843 vouchers)

43, 88, 136, 191, 260, 305, 358, 379

10 vouchers at a time (800-840 of 843 vouchers)

431, 440, 404, 412

1 voucher at a time (840-843 of 843 vouchers, last one is failure)

400, 423,404, 390

After some debugging, progressive removal of code and looking at query plans I identified the problematic TSQL statement.

UPDATE TOP(1) Voucher SET
Voucher.AllocatedByActivity = @ActivityUID,
Voucher.AllocatedAtUTC = @RequestDateTimeUTC,
Voucher.AllocationReference = @ClientReference,
@VoucherCode = Voucher.Code
WHERE (( Voucher.VoucherBatchUID = @VoucherBatchUID ) AND ( Voucher.AllocatedByActivity IS NULL ))

This update statement uses a single statement transaction to get the next random un-allocated voucher code in the specified voucher batch.

After some conversations with a SQL Azure support engineer at Microsoft (who was very helpful) he figured out that in SQL Azure the query processor needed a query hint to tell it to use an existing index to make it perform consistently.

UPDATE TOP(1) Voucher SET
Voucher.AllocatedByActivity = @ActivityUID,
Voucher.AllocatedAtUTC = @RequestDateTimeUTC,
Voucher.AllocationReference = @ClientReference,
@VoucherCode = Voucher.Code
FROM Voucher WITH (INDEX(IX_VoucherByVoucherBatchUIDAllocatedByActivity))
WHERE (( Voucher.VoucherBatchUID = @VoucherBatchUID ) AND ( Voucher.AllocatedByActivity IS NULL ))

100 vouchers at a time (0 – 800 of 843 vouchers)

20, 8, 13, 9, 32, 7, 15, 9

10 vouchers at a time (800-840 of 843 vouchers)

17, 9, 14, 13

1 voucher at a time (840-843 of 843 vouchers, last one is failure)

12,11,13, 5

I always have plenty of performance counters and logging (using the enterprise library) on my Azure web and worker roles but I was also lucky that I noticed something odd in the logs while checking on the progress of another promotion. I actively monitor the performance of my Azure applications as over time the performance characteristics of the underlying hardware will change as fixes and enhancements are released.