.NET nanoFramework is a free and open-source platform that enables the writing of managed code applications for constrained embedded devices. It is suitable for many types of projects including IoT sensors, wearables, academic proof of concept, robotics, hobbyist/makers creations or even complex industrial equipment. It makes the development for such platforms easier, faster and less costly by giving embedded developers access to modern technologies and tools used by desktop application developers.
Developers can harness the powerful and familiar Microsoft Visual Studio IDE and their .NET C# knowledge to quickly write code without having to worry about the low-level hardware intricacies of a microcontroller. It includes a reduced version of the.NET Common Language Runtime (CLR) and features a subset of the.NET base class libraries along with the most common APIs allowing code reuse from desktop applications, IoT Core applications, thousands of code examples and open source projects.Using Microsoft Visual Studio, a developer can deploy and debug the code directly on real hardware!
To install the necessary tools, see the great starter guides. That should take you few minutes depending on the speed of your internet connection! I do recommend to follow as well the hello world example to check all is working perfectly.
And check out all the samples, all the libraries available on nanoframework/Home: The landing page for nanoFramework repositories. (github.com)
The projectThe idea of the project is to pilot, an old and very basic robotic arm thru Web API, using https, with a login and password, all connected in wifi! I choose to use an ESP32 because of the small size, idea is to have all the electronic hidden in the part which used to contain the batteries and the basic old electronic.
Once everything is done, you can place all the hardware in the back of the arm. Be careful with the cables!
nanoFramework.WebServer.NET nanoFramework.WebServer is a fully functional Web Server, allowing to serve files, supporting https, event or controller based. Think of it as a very light version of ASP.NET but for embedded devices. You will find the source code of the Web Server and detailed example on nanoframework/lib-nanoFramework.WebServer: A simple web server for nanoFramework serving static files and can handle multithread requests and parameters in query URL (github.com).
Features include but not limited to:
- Handle multi-thread requests
- Serve static files on any storage
- Handle parameter in URL
- Possible to have multiple WebServer running at the same time
- supports GET/PUT and any other word
- Supports any type of header
- Supports content in POST
- Reflection for easy usage of controllers and notion of routes
- Helpers to return error code directly facilitating REST API
- HTTPS support
- URL decode/encode
Limitations:
- Does not support any zip compression in the request or response stream
Clone the repository Ellerbach/RoboticArm (github.com)
Once cloned, open the project in Visual Studio. You should see the following files:
You can choose to use HTTP or HTTPS with the web server. With HTTPS, you'll need to setup certificates, all is documented in the Program.cs file, so you just have to follow the instructions.
In case you setup https:
X509Certificate _myWebServerCertificate509 = new X509Certificate2(_myWebServerCrt, _myWebServerPrivateKey, "1234");
using (WebServer server = new WebServer(443, HttpProtocol.Https, new Type[] { typeof(ControllerPerson), typeof(ControllerTest), typeof(ControllerAuth) }))
{
server.HttpsCert = _myWebServerCertificate509;
server.SslProtocols = System.Net.Security.SslProtocols.Tls11 | System.Net.Security.SslProtocols.Tls12;
server.Start();
Thread.Sleep(Timeout.Infinite);
}
In case you setup http only
using (WebServer server = new WebServer(80, HttpProtocol.Http, new Type[] { typeof(ControllerApi), typeof(ControllerWebpages) }))
{
server.Start();
Thread.Sleep(Timeout.Infinite);
}
You'll note that when creating the server, you pass classes like controllerApi and ControllerWebpages. Those are the controllers containing the main code. We can first have a look at the one serving the static content.
Serving static contentThe files located in resources are the static files that the Web Server will serve.
The code to serve those files is located in ControllerWebpages.cs and looks like this:
using nanoFramework.WebServer;
namespace RoboticArm
{
[Authentication("Basic:user p@ssw0rd")]
public class ControllerWebpages
{
[Route("favicon.ico")]
public void Favico(WebServerEventArgs e)
{
WebServer.SendFileOverHTTP(e.Context.Response, "favico.ico", Resources.GetBytes(Resources.BinaryResources.favico), "image/ico");
}
[Route("script.js")]
public void Script(WebServerEventArgs e)
{
e.Context.Response.ContentType = "text/javascript";
WebServer.OutPutStream(e.Context.Response, Resources.GetString(Resources.StringResources.script));
}
[Route("image.svg")]
public void Image(WebServerEventArgs e)
{
WebServer.SendFileOverHTTP(e.Context.Response, "image.svg", Resources.GetBytes(Resources.BinaryResources.image), "image/svg+xml");
}
[Route("default.html"), Route("index.html"), Route("/")]
public void Default(WebServerEventArgs e)
{
e.Context.Response.ContentType = "text/html";
WebServer.OutPutStream(e.Context.Response, Resources.GetString(Resources.StringResources.page));
}
}
}
The attribute Route will be used to call the function and the Authentication for authentication. Refer to the samples in the nanoFramework.WebServer repository for more information on how to use them.
Resources.GetString and GetBytes are generated automatically when you add specific resources in your project. Refer to the examples on .NET nanoFramework to understand more about the specificities.
Both static functions WebServer.SendFileOverHTTP and WebServer.OutPutStream are helpers to facilitate sending content over the http stream. OutPutStream is more generic and allow to push any kind of content while the SendFileOverHTTP one have embedded features specifically for files including the possibility to read them directly from an SD card for example if you have one connected.
When accessing the web page through http or https depending on what you'll have setup and after authentication, you'll then see something like this:
I am not a designer, so it's just a raw view of a very simple web page and its associated script
By clicking on the arrow, you'll move the various motors. Let's see how this is implemented.
The controller for APIThe file containing the controller for the API is located in ControllerApi.cs. You'll find an authentication like in the previous controller and routes as well.
The Initialize function is called before starting the web server and allows to initialize the Motors using GpioController to pilot the H-Bridge. Here is an extract of the code allowing to initialize the GpioController, create an array of motors and create one motor.
_controller = new GpioController();
_motors = new MotorDetails[MaxNumberMotor];
_motors[0] = new MotorDetails(0, TimeMillisec1);
_motors[0].GpioPinUp = _controller.OpenPin(PinMotor1Up, PinMode.Output);
_motors[0].GpioPinDown = _controller.OpenPin(PinMotor1Down, PinMode.Output);
Every motor has 2 pins, they are connected to the H-Bridge allowing to have the motor turning in both directions. It has also a default time out when the API is called without specifying how long the motors should turn.
This is an example of querry you can do:
http(s)://ipaddress/mu?p=2&t=500
This will call this part of the code:
[Route("mu")]
public void MotorUp(WebServerEventArgs e)
{
var paramsQuery = WebServer.DecodeParam(e.Context.Request.RawUrl);
var motorNum = GetMotorNumber(paramsQuery);
if (motorNum < 0)
{
WebServer.OutputHttpCode(e.Context.Response, HttpStatusCode.BadRequest);
return;
}
var timing = GetTiming(paramsQuery);
_motors[motorNum].Up(timing);
e.Context.Response.ContentLength64 = 0;
WebServer.OutputHttpCode(e.Context.Response, HttpStatusCode.OK);
}
The route is "mu". You can setup multiple routes for the same functions, you can has well have the function called for a specific verb like GET or POST or anything else. By default, it will be called whatever the verb is. And you can have it case sensitive if you want. By default it is non case sensitive so all the routes needs to be written in lowercase.
You will note the DecodeParam function that will split all what is after the question mark in the URL and decode it to find all parameters. This is used then to find the motor number or the timing.
The function GetMotorNumber looks like this:
private int GetMotorNumber(UrlParameter[] paramsQuery)
{
try
{
foreach (var param in paramsQuery)
{
if (param.Name == "p")
{
var motor = Convert.ToInt32(param.Value);
if ((motor >= MinNumberMotor) && (motor <= MaxNumberMotor))
{
return motor - 1;
}
}
}
}
catch (Exception) { }
return -1;
}
It basically checks all the parameters and try to find the first one with the name "p" and then try to convert the vale as an int. The GetTiming one is very similar.
The function Up is then called and the status code OK (200) is returned from the web server to the caller. In case of problem a Bad Request is returned.
The WebServer has static functions allowing to quickly return codes.
ConclusionThe webserver allows to simply have a notion of routes, have authentication, supports http and https, can be used with any port, and is real multithread.
As explained a bit earlier, you can specify specific verbs for specific routes and have a level of granularity as needed.
It does support as well an event based mechanism on top of the routes. this allow to have even more flexibility.
You'll find more examples on the nanoFramework.WebServer git hub.
Comments
Please log in or sign up to comment.