Servo Block Library for Simulink Arduino Target
The goal of the library is to allow users to control servos within Simulink models compiled for the Arduino Target.
The library was developed using the Arduino Target located here: [Arduino Target] the version used was last updated 11/22/2011.
Although it is not the latest release of the Arduino IDE (1.0 at this time), version 0023 is being used as it is the highest compatible with this version of the Arduino Target.
It is assumed that you already have the Arduino Target installed and working. If you need help installing it, see my tutorial located here: Installing the Arduino Target for Simulink
- Download the Servo Library here: (servoLibrary.zip)
- Extract it to an easy to locate directory (C:/servoLibrary)
- Copy the files Servo.h, Servo.cpp, io_wrappers.h, io_wrappers.cpp, and servo.jpg to the directory you extracted the Arduino Target to (C:/arduinoTarget)
- Allow windows to overwrite the io_wrappers files. This will allow the extended wrappers needed for the Servo Library to be added to the stock Mathworks file
- Launch MATLAB and navigate to File->Set Path...
- Select "Add Folder" and select the servoLibrary folder (C:/servoLibrary)
- Select "OK" and the servoLibrary should appear at the top of the path list
- Click "Save" then "Close"
- Exit and re-open MATLAB
- The Arduino Servo Library should appear below the Arduino Target (select the title "Arduino Servo Library"
The servo blocks may be used like any of the other blocks in the Arduino Target. By double clicking on the block or bringing up the set block parameters dialog you can set the pin that the servo is attached to.
The block expects an input of type uint8
- Note that there is no check in place to ensure that the value fed in is between 0 and 180 (the same requirements as utilizing the Servo Library in the Arduino IDE)
On the Arduino UNO, utilizing a servo will automatically disable PWM on pins 9 and 10
Each physical servo must utilize its own block (ServoA-ServoH). This is due to the design of the blocks. Each blocks represents an instance of a Servo Object. See #How it Works more more details.
An Arduino UNO can theoretically control 12 servos, the MEGA can control 48
- Note that controlling more than 12 servos on the Arduino MEGA will disable PWM on pins 11 and 12
This video shows 8 servos being controlled by the Arduino. The current value being written to the servos is sent via serial to the host computer where it is graphed by Simulink. The 2 model files can be downloaded after the video.
The serial host model is the demo from the Arduino target. It can be launched by typing demo_arduino_serial_communication_host if you have the package installed.
The photo below shows my configured version. Set the serial configuration and serial receive blocks to use the COM port your Arduino is attached to. I had mine attached to port COM9
The Arduino model is available here: [Servo_Demonstration.mdl] (Right-click -> Save as)
I put the files in the C:/arduinoTarget folder, but it should work putting them elsewhere too so long as you make that folder your current working directory.
Note how each servo (Servo A-H) is assigned to a different port on the Arduino (digital ports only). If you have completed the configuration of the Arduino Target, and have your Arduino attached, you should be able to build the model to the Arduino by pressing CTRL+B.
Here is a screenshot of the Arduino side model:
How it Works
The basis of this library is the Servo library included with the Arduino IDE. Looking at the files Servo.h and Servo.cpp in the arduino-0023\libraries\Servo directory. Because it is a C++ library, we cannot simply include it in a TLC file and utilize its functions. The key to solving this problem is wrapper functions. Using these the C++ functions can be wrapped in a C function which can then be called by the TLC file.
To understand what is happening behind the scenes, first look at the digitalOutput block. It is a mask for the S-function sfunar_digitalOutput and its source files are located in the C:\arduinoTarget\blocks directory. Navigating to this directory will reveal 4 files with the name sfunar_digitalOutput with extensions .c, .tlc, .mex32, and .mex64. The C file is what defines the block. No calls to the digitalOutput command happen here, it only tells the S-function name. To make the servo blocks, I changed the name here to the one I used for each block (digitalServo, digitalServo2, ect.)
The next piece of the puzzle is the TLC files. The TLC file tells Simulink how to compile the code for the Arduino and what needs to happen. Looking at sfunar_digitalOutput.tlc shows two familiar Arduino commands: pinMode() and digitalWrite(). p1_val is the variable representing the 1st parameter (the pin number) and u1_val is the first input (the value to write). Near the top you can see a file being included block_common_includes.tlc. Navigating to this file also located in the blocks directory reveals that there are 2 files being included WProgram.h and io_wrappers.h. WProgram.h is a file from the Arduino IDE that takes care of defining ports and also includes the other necessary libraries to perform the basic i/o functions on Arduino along with HardwareSerial.h.
io_wrappers.h and io_wrappers.cpp are where all the C++ to C magic happens. Opening the files located in the blocks directory reveals 3 functions which at first glance look familiar: Serial_begin, Serial_read, Serial_write. In io_wrappers.cpp the wrapping happens creating a C function to call the C++ function. Serial_begin calls Serial.begin and the same for the other two functions.
Those familiar with programming will say, where is the Serial object coming from that we can begin, read, and write from? The answer is in the HardwareSerial.h and .cpp files located in arduino-0023\hardware\arduino\cores\arduino. Looking at the bottom of the file we can see the Serial objects being created based on the board that has been selected. This is where I decided it will be necessary to pre-define each servo object we will use, which lead to the creating of 8 individual servo blocks. As an aside I tried changing the board to the Mega 2560 and changing the Serial.begin to Serial1.begin in the io_wrappers file, but was unsuccessful. I think it may be related to how the if statements are worded and what variables are manipulated by the Arduino Target when a particular board configuration is selected.
With this new understanding of how the Serial blocks work through the use of io_wrappers files, I created the servo blocks. Following the syntax of the Serial blocks, I created 8 versions of the Servo_attach and Servo_write functions in both the .h and .cpp files. In the .cpp file it is necessary to include the Servo.cpp file at the top so we can make calls to the functions. Another addition to the .cpp file is adding the definitions of the 8 servo objects (Servo ServoA;).
After modifying the io_wrappers files we can return to the TLC file. Using the sfunar_digitalOutput file as the basis for the Servo blocks, I took the basic servo setup used in the Arduino demo Sweep (in the Arduino IDE under examples->Servo->sweep). There are 2 things needed to make the servo work. First we need to attach it to a port and then we need to write a value to it. Instead of setting pinMode the corresponding Servo_attach(int pin) function from io_wrappers.h is called. In the outputs section of the .TLC file we no longer need to digitalWrite so we call the corresponding Servo_write(int position) function. Also note that the names of the function have been changed for each instance of the digitalServo.tlc file.
The final piece is creating the mex files. The mex files are compiled from the .c file and based on whether you are on a 32 or 64-bit computer a .mex32 or .mex64 file will be completed. To create the mex file, simple type at the MATLAB command prompt "mex your_file.c". This will generate the .mex file (I only created .mex32 files since I am using 32-bit Windows 7 and MATLAB)
The blocks are simply S-functions that have been masked (again I based it all on the existing Arduino Target blocks)
As for areas of expansion, as mentioned early the Arduino UNO and MEGA both support more than 8 servos, but at the time I do not foresee myself needing more than 8. It should not be too difficult for a user of this package to add more servos as needed following the pattern I followed. Additional functions are available in the Servo library, and thus blocks may be created for these too also following the technique used in the creation of these blocks. Some users may wish to define their servo max and mins. It is possible to add additional parameters to the S-function for max and min (and also set defaults should the user not want to set them). The user would have to add the additional parameters to the Servo_attach function and also change the call to the Servo.attach function which can either accept 1 or 3 parameters.
The Arduino Target for Simulink and all of its files are copyrights of the MathWorks.