External Libraries

Basic Operation

Sometimes, you may wish to use an existing library for the devices that are connected to the microcontroller or for the microcontroller itself.

Such libraries can be included by specifying their paths in the "Libraries" property as (PackageLink[MicrocontrollerEmbedCode, paclet:MicrocontrollerKit/ref/MicrocontrollerEmbedCode, MicrocontrollerKit Package Symbol])[…,<|…,"Libraries"->paths,…|>].

The code from the external library for a device can be injected alongside the generated code by specifying the input or output channel to be of type "ExternalLibrary" and adding additional channel specifications as suboptions. Thus an input or output channel that uses functionality from an external library is specified as "ExternalLibrary"-><|(Subscript[libkey, 1])->(Subscript[val, 1]),…|>.

If the library is being used by the microcontroller itself the specifications for the code from the external library must be specified in the the second microcontroller argument as (PackageLink[MicrocontrollerEmbedCode, paclet:MicrocontrollerKit/ref/MicrocontrollerEmbedCode, MicrocontrollerKit Package Symbol])[sys, <|…,(Subscript[libkey, i])->(Subscript[value, i]),…|>,…].

The keys (Subscript[libkey, i]) for external libraries specify at which segments of the program the external library code needs to be injected are the following:

The possible suboptions for an external library.

The location of segments can be seen from the general layout of the program.

Pololu Library Example

The Zumo robot from Pololu has a pushbutton and a buzzer. They also provide (WebLink[libraries, https://github.com/pololu/zumo-shield]) to interact with them. Follow the standard procedure for installing the libraries for Arduino. This will allow you to run the Arduino examples that are provided and verify that it is working correctly.

For this example we only need the contents of the folders PushButton and ZumoBuzzer. For our purposes these folders can in any location in the file system.

The library locations.

lib=Table[FileNameJoin[{$HomeDirectory,"Documents","Arduino","libraries",f}],{f,{"Pushbutton","ZumoBuzzer"}}];

The code in the includes and utilities segments.

incls={"<Pushbutton.h>","<ZumoBuzzer.h>"};

utils={"ZumoBuzzer buzzer","Pushbutton button(ZUMO_BUTTON)"};

The button library has a isPressed function that can be used to check if the button it pressed or not. That can be used to get a 1 or 0 reading using the library depending on the button state.

The input specification.

l={"button.isPressed()?1:0"};
ic="ExternalLibrary"-><|"Loop"->l|>;

The systems simply passes the input through. Thus the output of sys is also 1 or 0.`

The system.

sys=(StateSpaceModelFull[1, 0.1`, ExternalTypeSignature->"uint8_t", , ]);

The buzzer library has a playNote function that can be used to play a specified note. The note is defined in the library's header file. The output is set to the variable playQ, and the note is played only if the output of sys is 1.

The output specification.

l={"uint8_t playQ","if(playQ){buzzer.playNote(NOTE_E(5),100,15);}"};oc="ExternalLibrary"-><|"Loop"->l|>;

After the code is embedded the buzzer will sound at each button press.

Load the package.

Needs["MicrocontrollerKit`"]

Embed the code.

MicrocontrollerEmbedCode[sys,<|"Target"->"ArduinoUno","Inputs"->ic,"Outputs"->oc,"IncludeFiles"-> incls,"Utilities"-> utils|>,"/dev/tty.usbmodem14101",<|"Libraries"->lib|>]

Arduino Library Example

The Arduino language has a function called random to generate psuedo-random numbers. Just as in the previous example, we have to specify the library location and other segments of the code.

Use the Arduino function random to generate random numbers between -10 and 10.

lib=FileNameJoin[{$RootDirectory,"Applications","Arduino.app","Contents","Java","hardware","arduino","avr","cores"}];

ic="ExternalLibrary"-><|"IncludeFiles"->"Arduino.h","Loop"->"random(-10,11)"|>;

Embed code that returns the values over a serial port.

ℳ=MicrocontrollerEmbedCode[(StateSpaceModelFull[1, 0.1`, , ]),<|"Target"->"ArduinoUno","Inputs"->ic,"Outputs"->"Serial"|>,"/dev/tty.usbmodem14101",<|"Libraries"->lib|>]

We can now use the device framework to read in the values.

A function to parse the incoming data.

parse[d_]:=With[{res=ToExpression@FromCharacterCode@Rest@d},
Which[NumericQ[res],res,True, Nothing]]

Open a serial connection and set up a scheduled task to read the data.

dv=DeviceOpen["Serial","/dev/tty.usbmodem14101"]

y={};
task=SessionSubmit@ScheduledTask[
If[DeviceExecute[dv,"SerialReadyQ"],AppendTo[y,parse[DeviceReadBuffer[dv,"ReadTerminator"->ℳ["Serial"]["EndByte"]]]];
DeviceExecute[dv,"ReadFlush"]]
,
0.1
];

Remove the task and close the connection after some time.

TaskRemove[task];
DeviceClose[dv]

We can do some post analysis of the data that was collected.

Generate a histogram.

Histogram[y,20]

Estimate the parameters of the distribution.

FindDistributionParameters[y,UniformDistribution[{min,max}]]