6 min read

In today’s tutorial, we will build a simple Raspberry Pi 3 project. Since our Raspberry Pi now runs Windows 10 IoT Core, .NET Core applications will run on it, including Universal Windows Platform (UWP) applications.

From a blank solution, let’s create our first Raspberry Pi application. Choose Add and New Project. In the Visual C# category, select Blank App (Universal Windows). Let’s call our project FirstApp. Visual Studio will ask us for target and minimum platform versions. Check the screenshot and make sure the version you select is lower than the version installed on your Raspberry Pi.

In our case, the Raspberry Pi runs Build 15063. This is the March 2017 release. So, we accept Build 14393 (July 2016) as the target version and Build 10586 (November 2015) as the minimum version. If you want to target the Windows 10 Fall Creators Update, which supports .NET Core 2, you should select Build 16299 for both.

In the Solution Explorer, we should now see the files of our new UWP project:

New project

Adding NuGet packages

We proceed by adding functionality to our app from downloadable packages, or NuGets. From the References node, right-click and select Manage NuGet Packages. First, go to the Updates tab and make sure the packages that you already have are updated. Next, go to the Browse tab, type Firmata in the search box, and press Enter. You should see the Windows-Remote-Arduino package. Make sure to install it in your project. In the same way, search for the Waher.Events package and install it.

Aggregating capabilities

Since we’re going to communicate with our Arduino using a USB serial port, we must make a declaration in the Package.appxmanifest file stating this. If we don’t do this, the runtime environment will not allow the app to do it. Since this option is not available in the GUI by default, you need to edit the file using the XML editor. Make sure the serialCommunication device capability is added, as follows:

<Capabilities> 
   <Capability Name="internetClient" /> 
   <DeviceCapability Name="serialcommunication"> 
         <Device Id="any"> 
               <Function Type="name:serialPort" /> 
         </Device> 
   </DeviceCapability> 
</Capabilities>

Initializing the application

Before we do any communication with the Arduino, we need to initialize the application. We do this by finding the OnLaunched method in the App.xml.cs file. After the Window.Current.Activate() call, we make a call to our Init() method where we set up the application.

   Window.Current.Activate(); 
   Task.Run((Action)this.Init);
We execute our initialization method from the thread pool, instead of the standard thread. This is done by calling Task.Run(), defined in the System.Threading.Tasks namespace. The reason for this is that we want to avoid locking the standard thread. Later, there will be a lot of asynchronous calls made during initialization. To avoid problems, we should execute all these from the thread pool, instead of from the standard thread.

We’ll make the method asynchronous:

private async void Init() 
{ 
   try 
   { 
         Log.Informational("Starting application."); 
         ... 
   } 
   catch (Exception ex) 
   { 
         Log.Emergency(ex); 
          
         MessageDialog Dialog =  
new MessageDialog(ex.Message, "Error"); 
         await Dialog.ShowAsync(); 
} IoT Desktop  
}

The static Log class is available in the Waher.Events namespace, belonging to the NuGet we included earlier. (MessageDialog is available in Windows.UI.Popups, which might be a new namespace if you’re not familiar with UWP.)

Communicating with the Arduino

The Arduino is accessed using Firmata. To do that, we use the Windows.Devices.Enumeration, Microsoft.Maker.RemoteWiring, and Microsoft.Maker.Serial namespaces, available in the Windows-Remote-Arduino NuGet. We begin by enumerating all the devices it finds:

DeviceInformationCollection Devices =  
   await UsbSerial.listAvailableDevicesAsync(); 
foreach (DeviceInformationDeviceInfo in Devices) 
{

If our Arduino device is found, we will have to connect to it using USB:

if (DeviceInfo.IsEnabled&&DeviceInfo.Name.StartsWith("Arduino")) 
{ 
   Log.Informational("Connecting to " + DeviceInfo.Name); 
 
   this.arduinoUsb = new UsbSerial(DeviceInfo); 
   this.arduinoUsb.ConnectionEstablished += () => 
         Log.Informational("USB connection established.");

Attach a remote device to the USB port class:

this.arduino = new RemoteDevice(this.arduinoUsb);

We need to initialize our hardware, when the remote device is ready:

this.arduino.DeviceReady += () => 
{ 
   Log.Informational("Device ready."); 
 
   this.arduino.pinMode(13, PinMode.OUTPUT);    // Onboard LED. 
   this.arduino.digitalWrite(13, PinState.HIGH); 
 
   this.arduino.pinMode(8, PinMode.INPUT);      // PIR sensor. 
   MainPage.Instance.DigitalPinUpdated(8,
          this.arduino.digitalRead(8)); 
   this.arduino.pinMode(9, PinMode.OUTPUT);     // Relay. 
   this.arduino.digitalWrite(9, 0);             // Relay set to 0 
 
   this.arduino.pinMode("A0", PinMode.ANALOG); // Light sensor. 
   MainPage.Instance.AnalogPinUpdated("A0",
          this.arduino.analogRead("A0")); 
};
Important: the analog input must be set to PinMode.ANALOG, not PinMode.INPUT. The latter is for digital pins. If used for analog pins, the Arduino board and Firmata firmware may become unpredictable.

Our inputs are then reported automatically by the Firmata firmware. All we need to do to read the corresponding values is to assign the appropriate event handlers. In our case, we forward the values to our main page, for display:

this.arduino.AnalogPinUpdated += (pin, value) => 
{ 
   MainPage.Instance.AnalogPinUpdated(pin, value); 
}; 
 
this.arduino.DigitalPinUpdated += (pin, value) => 
{ 
   MainPage.Instance.DigitalPinUpdated(pin, value); 
};

Communication is now set up. If you want, you can trap communication errors, by providing event handlers for the ConnectionFailed and ConnectionLost events. All we need to do now is to initiate communication. We do this with a simple call:

this.arduinoUsb.begin(57600, SerialConfig.SERIAL_8N1);

Testing the app

Make sure the Arduino is still connected to your PC via USB. If you run the application now (by pressing F5), it will communicate with the Arduino, and display any values read to the event log. In the GitHub project, I’ve added a couple of GUI components to our main window, that display the most recently read pin values on it. It also displays any event messages logged. We leave the relay for later chapters.

For a more generic example, see the Waher.Service.GPIO project at https://github.com/PeterWaher/IoTGateway/tree/master/Services/Waher.Service.GPIO. This project allows the user to read and control all pins on the Arduino, as well as the GPIO pins available on the Raspberry Pi directly.

Deploying the app

You are now ready to test the app on the Raspberry Pi. You now need to disconnect the Arduino board from your PC and install it on top of the Raspberry Pi. The power of the Raspberry Pi should be turned off when doing this. Also, make sure the serial cable is connected to one of the USB ports of the Raspberry Pi. Begin by switching the target platform, from Local Machine to Remote Machine, and from x86 to ARM:

Run on a remote machine with an ARM processor

Your Raspberry Pi should appear automatically in the following dialog. You should check the address with the IoT Dashboard used earlier, to make sure you’re selecting the correct machine:

Select your Raspberry Pi

You can now run or debug your app directly on the Raspberry Pi, using your local PC. The first deployment might take a while since the target system needs to be properly prepared. Subsequent deployments will be much faster. Open the Device Portal from the IoT Dashboard, and take a Screenshot, to see the results. You can also go to the Apps Manager in the Device Portal, and configure the app to be started automatically at startup:

App running on the Raspberry Pi

To summarize, we saw how to practically build a simple application using Raspberry Pi 3 and C#. You read an excerpt from the book, Mastering Internet of Things, written by Peter Waher. This book will help you design and implement scalable IoT solutions with ease.

Mastering Internet of Things

Read Next

Meet the Coolest Raspberry Pi Family Member: Raspberry Pi Zero W Wireless

AI and the Raspberry Pi: Machine Learning and IoT, What’s the Impact?

 

 

LEAVE A REPLY

Please enter your comment!
Please enter your name here