Interfacing BeagleBoard with Simulink and Arduino

From Matt Bilsky
Jump to: navigation, search

Contents

Overview

Clean Installation vs. Virtual Machine

To attempt to build a clean environment for development is a large undertaking. It will take many hours and most likely you will encounter a few issues along the way. To ease development I have created a Virtual Machine image of the development environment I created. Using this will allow you to skip these first steps and only require you to begin at topic 3.1.

All the demonstrations listed in the tutorial are located in the /home/matt/Documents/MATLAB folder on the virtual machine.

The image can be viewed using the free VMware player located here: http://www.vmware.com/products/player/

Software Configuration

This guide is based around Matlab 2010b for Linux running on Ubuntu 11.10 32-bit. Updates have been turned off in the Virtual Machine to help preserve compatibility.

The BeagleBoard support package only works with Matlab 2010b.

Hardware Configuration

Here is a list of hardware used in this tutorial and the accompanying demonstrations:

  • USB serial breakout board http://www.sparkfun.com/products/718
  • BeagleBoard Classic Revision C5
  • Toshiba USB "Dynadock U" laptop dock (for USB Ethernet)
  • USB Mini A to OTG female cable
  • 5-Volt power cable for BeagleBoard
  • Arduino Uno
  • Logitech 9000 Pro webcam

You can get everything you need for the BeagleBoard here: https://specialcomp.com/beagleboard/order.htm

Here is a shot of the setup:

Beagleboard-hardware-overview.JPG

Common Sources of Error

  • Make sure that you can SSH to root@BeagleBoardIP without having to enter your password.
  • Ensure that you have set your Matlab environment variables each time you launch the program.
  • If your BeagleBoard's IP address changes, you need to change it both in eclipseidesetup and in the mex-file arguments under configure parameters in your Simulink model.

Project History

At the beginning of this project, the Hopper Space Simulator at Lehigh University has had all of its control algorithms programmed in the Arduino language, and executed by an on-board Arduino. I was tasked to explore the feasibility of interfacing an Arduino with a Gumstix or BeagleBoard board and using Simulink to generate the code for them. The idea is that we can continue to use an Arduino Mega to handle the input/output to the servos, speed controllers, and sensors. The control algorithms will then be executed on the higher speed computer, and the Arduino would just talk to the sensors.

I was given complete freedom, as no one had attempted this before on the team. I then began my research with no background, eventually exploring the abilities of Simulink for code generation, setting up and installing Angstrom Linux on the BeagleBoard, and finally how to use C code in Simulink S-functions for serial communication. I also explored the blocks that are available for the BeagleBoard including the audio input/output blocks and the video capture blocks.

After many issues along the way, I ultimately was successful in this goal. While the demonstrations at the bottom of this page are quite trivial, they show that we have the ability to send and receive data to the Arduino. It is a simple matter of adding more data coming to and from Simulink, and replacing the LEDs with the desired hardware to make the BeagleBoard the full brains behind the Hopper.

More information about the Hopper Project is available here: http://www.youtube.com/watch?v=b3Gdt-OvaKo

Getting Started

Generating GNU Toolchain using BitBake

To install and configure the BitBake program for OpenEmbedded, we are going to follow the guide published on the Gumstix website:

http://gumstix.org/software-development/open-embedded/61-using-the-open-embedded-build-system.html

Follow Steps until you get to the section "Environmental Setup"

I have found the Method B is the easiest for setting up the enviroment, specifically:

source ~/overo-oe/build/profile

The machine type should also be set to BeagleBoard. To do this open the terminal and execute the following:

cd ~/overo-oe/build/conf
nano auto.conf

Next change the specified machine to "beagleboard"

To save your changes press "Ctrl" and "X" and at the prompt that appears type "y" followed by enter.

The only package necessary for code generation is the gdbcross recipe. To build it, type the following:

bitbake gdb-cross

Note that this will take some time as it needs to download and extract all the necessary packages.

It is common for the compiling to fail due to an error within a package. The best solution is to first try the following:

bitbake -c clean <failed recipe>
bitbake -c rebuild <failed recipe>

If bitbake gdb-cross fails on the same package again the best solution is to google your error. A search such as "<failed recipe> bitbake openembedded" will ofter return numerous forum results from users who have had similar issues.

A good site to get answers from is Old Nabble: http://old.nabble.com. Try different searches and try the parent recipe for the one that is failing.

Often times the fix includes modifying the recipe version or changing a dependency

Once BitBake is finished it will display a summary:

NOTE: Tasks Summary: Attempted 580 tasks of which 580 didn't need to be rerun and 0 failed.

Installing Angstrom Distribution for BeagleBoard

Rather than building an image for the BeagleBoard ourselves, it is much easier to use the Narcissus online image builder located here: http://narcissus.angstrom-distribution.org/

  • Set the machine type to BeagleBoard
  • Set the name of the image to something easy to type (since you will have to extract it later)
  • Under "User environment selection" select X11
  • Under "Additional console packages" select GDBServer
  • Under "Platform specific packages" select all of the packages from "Texas Instruments OMAP3x/AM3x family" and "Texas Instruments OMAP3x/DaVinci/OMAPL family (using DSP)"

Select "Build me!" and wait as your distribution is assembled. Then save the created archive to your desktop.

Next follow the directions located here: http://treyweaver.blogspot.com/2010/10/installing-angstrom-on-beagleboard-xm.html to setup and install OpenEmbedded to a SD card.

Put the card in your BeagleBoard and fire it up.

Once booted, run the following commands to setup ssh

ipkg remove dropbear
ipkg update
ipkg install openssh
ipkg install openssh-sftp
ipkg install openssh-sftp-server

To give your BeagleBoard a static IP address for the entire time it is booted enter:

ifconfig 192.168.X.X netmask 255.255.255.0

To create a Key based authentication system for the BeagleBoard and your host computer, at the Linux terminal type "sudo ssh root@192.168.X.X" where the IP address is that of your BeagleBoard. The system will ask you if you trust the host and if you want to cache the key. Type "yes" and then continue to log in until you see the root@beagleboard prompt. Type "exit" to end the connection.

Now try the ssh command again. This time it should not prompt you for a password, but should just connect automatically. If this is not the case, try following the instructions here to generate a new key pair and transfer it over: https://help.ubuntu.com/community/SSH/OpenSSH/Keys

Installing Eclipse Ganymede

A pre-requisite for Eclipse to work is the JRE version 6.0. It is available here:http://www.oracle.com/technetwork/java/javase/downloads/jre-6u30-download-1377142.html. We want the Java SE 6.0 JRE package for Linux x86

Although it is not the most recent release, the supported version of Eclipse is Ganymede version Sr2 You can download it here: http://www.eclipse.org/downloads/packages/release/ganymede/sr2. We want the package "Eclipse IDE for C/C++ Developers" for 32 bit Linux systems

Extract the archive to a location you can find easily. I chose to place it on the desktop at ~/Desktop/eclipse

Located within this folder is the eclipse executable. Launch this (double click on eclipse). When it launches, a window will appear asking you to specify a workspace location. Set this to a folder where you want eclipse to store your compiled files. I chose ~/matlab_workspace

Once you are in Eclipse, we need to configure the location of the shared files so that they can be included when building the Simulink models.

At top of the Eclipse window select Window -> Preferences

In the Preferences pane, navigate to C/C++ -> Debug -> Common Source Lookup

To add folders select Add -> File System Directory -> OK -> Browse

Navigate to each of the directories posted in the image below in the browse menu. Note the folder name is listed to the left, followed by its path (matlab_workspace-/home/matt). In the browse window enter the directory you are looking for, then select "OK". It will appear correct in the dialog before you click "OK" for a second time. When you are back at the window pictured below it will be displayed in the re-arranged format.

Replace /home/matt with the appropriate path on your system. Also note that the 3rd folder down, MATLAB is the working directory we are using in Matlab, and where all of the models are saved.

Eclipse-source-setup.png

Select "Apply" then "OK"

Eclipse is now fully configured.

Configuring Matlab 2010b Code Generation

The first step is to extract and install the BeagleBoard support package from MathWorks here: http://www.mathworks.com/academia/beagleboard/. Follow the ReadMe file in the archive for installation directions.

I was unable to get the package to install correctly, so I made the changes manually. If you analyze the installer, it changes the file name of the files it is going to overwrite to filename_old. It is up to you if you wish to do this for each file that you are going to replace. Inside the support package is a zip file with a directory structure similar to /usr/local/MATLAB/R2010b/. This is because you need to take the files from the same location in this zip file's structure and move them to the same location in the Matlab root. Yes it it tedious, but it gets the job done.

To launch Matlab 2010b first open the terminal then execute the following:

sudo sh /usr/local/MATLAB/R2010b/bin/matlab

Once the Matlab window appears, type the follwing at the command prompt:

eclipseidesetup

The "Embedded IDE Link: Eclipse Adapter Setup" window should appear. Modify the settings to match those in the picture below

  • Set "Executable" to the location of your Eclipse installation folder
  • Set "Workspace" to the folder you created to serve as your Eclipse workspace
  • Set "IP Address" to the IP address of your BeagleBoard

Ide-setup.png

Click "Apply" followed by "OK"

The last step is to set the shared library search path.

This configuration assumes that you also built using BitBake the omap3-console-image or omap3-desktop-image. If you are using the Virtual Machine image, this has been done for you.

Execute the following in the Linux terminal:

sudo nano /usr/local/MATLAB/R2010b/toolbox/idelink/extensions/eclipseide/host/.gdbinit_angstrom

Comment out all the lines except:

handle SIG34 ...
and handle SIG35 ...

At the bottom of the file add the following:

Set solib-search-path /home/matt/overo-oe/tmp/rootfs/omap3-console-image/lib

Then type "Ctrl" and "x" followed by "y" to save the changes and exit.

Generating Code Using Simulink for the BeagleBoard

Launching Matlab

To launch Matlab 2010b first open the terminal then execute the following:

sudo sh /usr/local/MATLAB/R2010b/bin/matlab

Wait for the Matlab window to appear

If you have Changed the IP address of your BeagleBoard, you need to update it in the IDE setup, otherwise you can continue to setting up the environment

To update the IDE setup type the follwing at the command prompt:
eclipseidesetup
*Set "IP Address" to the IP address of your BeagleBoard
*Click "Apply" followed by "OK"

Next we need to change the Matlab Current Folder to the one where we have all our model files stored. I normally use /home/matt/Documents/MATLAB (This is where all the file are on the Virtual Machine). If you do not change this, you will get an error when you try to build your model that you are in the MATLAB bin folder.

Setup the Matlab environment

At the Prompt enter the following (where /home/matt/overo-oe is the location of your OpenEmbedded BitBake folder):

setenv('OETREE', '/home/matt/overo-oe/')
setenv('PATH', ['/home/matt/overo-oe/tmp/sysroots/i686-linux/usr/armv7a/bin' ':' getenv('PATH')])

Now that the variables have been set, we can being working in Simulink.

Launch Simulink by typing "Simulink" at the command prompt.

Configuring Simulink Parameters

In the library browser go to Embedded IDE Link -> Common

Drag the Target Preferences block to the model

Target-preferences.png

Hit yes on the pop-up dialog, we will configure the parameters ourselves.

Double click on the Target Preferences block, the configuration window will appear.

  • Set the IDE/Toolchain drop-down menu to Eclipse
  • Set the board to BeagleBoard ARM
  • Set the CPU Clock to match your board (leave at 600 Mhz for BeagleBoard)

Select "Apply" then "OK"

Target-set-preferences.png


Launch the Simulation Parameters menu by navigating to Simulation -> Configure Parameters

First under "Solver" set how long you want the simulation to run. To make it run until you stop it set Stop Time: to "inf"

Scroll down to Real-Time Workshop -> Interface

Set Interface: to "External mode"

Set your parameters to match those in the picture below. Change "Mex-file Arguemnts" to your board's IP address (remember to put it in single quotes)

Rtw-interface.png

Now look at the settings in Real-Time Workshop -> Embedded IDE Link

Set the Compiler option string to:

-O2 -g -mfloat-abi=softfp

Set the maximum build time and maximum operation time to 10000

Rtw-idelink.png


The final item that needs to be configured are the model properties. Launch the dialog from File -> Model Properties

In this dialog, you can specify Matlab functions to be executed in the background during each step of a programs execution.

The only parameters that must be set are the close functions. These are located under CloseFCN. Enter the following commands where "working_video" is replaced by the name of your sketch:

 rtwprivate ssgencode ModelCloseRequest working_video

Select "Apply" then "OK"

Model-properties.png

Finally, set your model to execute in External Mode by going Simulation -> External

Now your model is configured properly.

Generating Code

Once you have created your model, the next step is to build the code. Simulink will automatically launch the Eclipse IDE, which will build then debug your code.

To begin the build process type "Ctrl" and "B" or select Tools -> Real-Time Workshop -> Build Model

Watch you code build, and check for any errors. Matlab will display errors, and so will the console in the Eclipse IDE.

This video shows what you should see in the Eclipse console when the code is compiling. If the Matlab command window seems to be stuck at Downloading Program for a few minutes, look at this console to see if there were any errors when compiling.


Executing Code

The build process should automatically launch your code in the Eclipse IDE and on the BeagleBoard.

If everything is running correctly it should look like this:

Ide-debug.png

To connect your model to the BeagleBoard simulation go Simulation -> Connect to Target. This will allow data to be sent to the scopes and displays connected in your sketch.

It is possible to disconnect from the target without stopping the code execution by selecting Simulation -> Disconnect from Target

To stop the code on the BeagleBoard select Simulation -> Stop Real-Time Code. You can also hit the red stop button in the middle of the Eclipse debug window.


It is also possible to manually copy and execute the compiled files to the BeagleBoard. This is extremely useful if your model starts then exits immediately in the GDB debugger pane in Eclipse.

To copy the file navigate to the following location where "matlab_workspace" is the location of your Eclipse workspace, and "tutorial" is the name of your model.

/home/matt/matlab_workspace/tutorial/CustomMW

Next run the following command to copy the compiled executable to the BeagleBoard. Change the IP address to match that of your BeagleBoard and change "tutorial" to the name of your model:

scp tutorial root@192.168.X.X:/home/root

Finally, to execute the model type the following. The following output will be the diagnostic information from the code's execution (replace "tutorial" with the name of your model):

ssh root@192.168.X.X /home/root/tutorial

Using S-Functions to Communicate Over Serial

Setting Library Locations

Once you have created a S-function builder block, double click on it to configure it.

The first thing we need to do is add the library files we are using for Serial communication and for String manipulation.

Under the Library tab go to Include files and external function decelerations. Enter the following libraries and external function decleration(along with any other files you may want to use in your C code):

Sfunction-include.png

If during code generation you get an error stating that a library is missing, or you want to add your own custom files to include, place the files in /usr/include, and call them with their full file paths.

Configuring Inputs and Outputs

We need to create input and output ports on our S-function so that we can pass data to and from the Arduino. To specify your inputs navigate to the Input Ports tab and configure your input variables similar to the example below:

Sfunction-inputs.png

You can receive arrays and vectors, but if you are only receiving a double, which is the case here, specify the number of rows to 1.


It is also necessary to specify the outputs. This is done under the Output Ports tab. See an example below:

Sfunction-outputs.png

Again you can customize the outputs to your specifications.

Adding Communication Functions

Regardless of what data you wish to send and receive from the Arduino, it is necessary to define these functions in the top of the Outputs tab before you begin coding. Copy and paste the following functions: (Based on the Arduino-serial C program located here: http://todbot.com/blog/2006/12/06/arduino-serial-c-code-to-talk-to-arduino/)

int serialport_writebyte( int fd, uint8_t b)
{
    int n = write(fd,&b,1);
    if( n!=1)
        return -1;
    return 0;
}

int serialport_write(int fd, const char* str)
{
    int len = strlen(str);
    int n = write(fd, str, len);
    if( n!=len ) 
        return -1;
    return 0;
}

int serialport_read_until(int fd, char* buf, char until)
{
    char b[1];
    int i=0;
    do { 
        int n = read(fd, b, 1);  /* read a char at a time*/
        if( n==-1) return -1;    /* couldn't read*/
        if( n==0 ) {
            usleep( 10 * 1000 ); /* wait 10 msec try again*/
            continue;
        }
        buf[i] = b[0]; i++;
    } while( b[0] != until );

    buf[i] = 0;  /* null terminate the string*/
    return 0;
}

/* takes the string name of the serial port (e.g. "/dev/tty.usbserial","COM1")
and a baud rate (bps) and connects to that port at that speed and 8N1.
opens the port in fully raw mode so you can send binary data.
returns valid fd, or -1 on error*/
int serialport_init(const char* serialport, int baud)
{
    struct termios toptions;
    int fd;
    
    /*fprintf(stderr,"init_serialport: opening port %s @ %d bps\n",
            serialport,baud);*/

    fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1)  {
        perror("init_serialport: Unable to open port ");
        return -1;
    }
    
    if (tcgetattr(fd, &toptions) < 0) {
        perror("init_serialport: Couldn't get term attributes");
        return -1;
    }
    speed_t brate = baud; /* let you override switch below if needed*/
    switch(baud) {
    case 4800:   brate=B4800;   break;
    case 9600:   brate=B9600;   break;
#ifdef B14400
    case 14400:  brate=B14400;  break;
#endif
    case 19200:  brate=B19200;  break;
#ifdef B28800
    case 28800:  brate=B28800;  break;
#endif
    case 38400:  brate=B38400;  break;
    case 57600:  brate=B57600;  break;
    case 115200: brate=B115200; break;
    }
    cfsetispeed(&toptions, brate);
    cfsetospeed(&toptions, brate);

    /* 8N1*/
    toptions.c_cflag &= ~PARENB;
    toptions.c_cflag &= ~CSTOPB;
    toptions.c_cflag &= ~CSIZE;
    toptions.c_cflag |= CS8;
    /*no flow control*/
    toptions.c_cflag &= ~CRTSCTS;

    toptions.c_cflag |= CREAD | CLOCAL;  /* turn on READ & ignore ctrl lines*/
    toptions.c_iflag &= ~(IXON | IXOFF | IXANY); /* turn off s/w flow ctrl*/

    toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* make raw*/
    toptions.c_oflag &= ~OPOST; /* make raw*/

    /* see: http://unixwiz.net/techtips/termios-vmin-vtime.html*/
    toptions.c_cc[VMIN]  = 0;
    toptions.c_cc[VTIME] = 20;
    
    if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
        perror("init_serialport: Couldn't set term attributes");
        return -1;
    }

    return fd;
}

Sending and Receiving Data

Let's look at the basics for sending and receiving data in a S-Function.

unsigned char buf[4096]; 

char buffer [50];

The char array buf is the holding array for the incoming data from the serial port. buffer holds the output string.

int  cp = serialport_init("/dev/ttyUSB0",115200);

usleep(50000);

These lines initialize the serial port and then pauses 50ms. To figure out what port you need to use unplug and plug back in your USB serial port, then on the BeagleBoard type "dmesg | grep tty". The output will be the name of your serial port. Replace ttyUSB0 with your port.

115200 is the Baud rate specification. This can be changed to any standard Baud, but make sure it matches the one set on your Arduino.

int  r = serialport_read_until(cp,buf,"\n");

usleep(50000);

This block of code reads the serial buffer to the array buf, and then pauses.

int outStr = sprintf(buffer,"%f,%f\n",u0[0],u1[0]);
int m = serialport_write(cp,buffer);
usleep(50000);

This code snippit converts data we wish to send to the Arduino to a string using sprintf. It then prints the data through the port and then pauses again.

close(cp);

This final command closes the serial port so that we can open it again on the next iteration.

2-Way Communication Between Simulink and Arduino

Simulink Side

Below is the entire S-function Outputs code for the video and Arduino demonstration listed at the bottom. It is all of the code discussed above, just in one place so you can easily copy and paste it. Be sure to include the Serial functions in the Outputs tab before pasting in the code below.

unsigned char buf[4096];

char buffer [50];
  
int  cp = serialport_init("/dev/ttyUSB0",115200);

usleep(50000);
int  r = serialport_read_until(cp,buf,"\n");
y0[0]=atof(buf);

usleep(50000);
int outStr = sprintf(buffer,"%f,%f\n",u0[0],u1[0]);
  int m = serialport_write(cp,buffer);

usleep(50000);

close(cp);

Arduino Side

Below is the sketch running on the Arduino in the video and Arduino demonstration.

#include <stdio.h>
#include <string.h>
#include <Servo.h> 

char* incoming;
int i = 0;
double data[5];
void setup(){
  Serial.begin(115200);
  incoming = "000000000000000000000000000000000000000000000000";
 pinMode(11,OUTPUT);
 }

void loop(){
  int n = Serial.available();
  i=0;
  while(n>0){
    n--;
   incoming[i++]=Serial.read(); 
    
}
i=0;
delay(350);
  char * pch;
    pch = strtok (incoming,",");
  while (pch != NULL)
  {
    data[i++]=atof(pch);
    pch = strtok (NULL, ",");
  }
  i=0;
  int z = map(data[0],0,12,0,255);
  
analogWrite(11,z);

Serial.println(analogRead(0));
}

Demonstrations and Code Examples

Sum-Diff Codegen Example

Follow the MathWorks tutorial located within Matlab help entitled "Linux-ARM Code Generation for Texas Instruments OMPA35xx Processors"

Since we already configured the system for code generation, we can skip down to the section "Generate Code for Linux-ARM"

At the command line enter "sumdiff_codegen"

Connect a scope to "Out1"

When the model opens, configure the "Target Preferences" and "Configurations Parameters" to those described above rather than those specified in the tutorial.

Build the code, connect to the target, and double click on the scope. You should see the numbers increasing. This means that your model is successfully working on the BeagleBoard!

Parametric Audio Equalizer

This demonstration is based on the Parametric Audio Equalizer demo. In Matlab help search for "Parametric Audio Equalizer" and select the one for the Target Support Package.

Right click and select Save As to save my version of this demo: Parametric Audio Equalizer

Scroll down to Task 6 - Device Driver Integration. Next to step 1 select the Device Driver Integration Model Template.

To get the ADC and DAC blocks, at the Matlab command prompt type alsalib. This will bring up the audio in and out blocks for the BeagleBoard.

Again we want to follow the configuration settings listed above in this document rather than those in the demo.

For the Audio Capture block, set the parameters as follows:

Alsa-in.png

Here are the settings for Audio Playback:

Alsa-out.png

Double click on "Edit Parameters" in blue and set the Sampling Rate to 22050.

Build the model and connect to the target. After plugging in a music source to the line in port on the BeagleBoard, and speakers to the output, you should be able to hear the sound change as you adjust the parameters on your host computers.

Here is a video of what my setup looked like on the host computer, and the sound that resulted from the BeagleBoard:


Arduino and Video Capture

The following demonstration shows the video capture tools of the BeagleBoard, along with a demonstration of the BeagleBoard <-> Arduino interface.

There are 2 parts to the demonstration. One half counts the number of pennies in front of the camera, then sends the number to the Arduino which adjusts the brightness of the blue LED accordingly. The second half sends the current reading of the optical sensor to the BeagleBoard over serial and then receives the brightness to set the red LED to.

Right-click on the following links and select Save As to save them to your computer

The Arduino with the Serial sketch discussed above (download it HERE).

The Simulink model is called working_video (download it HERE).

The circuit consists of 2 LEDs with 1k pull-up resistors wired to digital outputs 11(blue) and 9(red). A TI OPT101 Photodiode is attached to analog input A0. Between the Arduino and the Rs232 adapter, the Rx <=> Tx and Tx <=> Rx lines are crossed. Be sure to ground the two devices to each other to prevent noise in the data.

If you want to get to the video capture block, type "v4l2lib" at the Matlab command line.

Here is a picture of the actual setup:

Arduino-beagleboard-circuit.JPG


And the video capture setup:

Video capture setup.JPG


Here is a video showing the output on the connected host computer:



This next video shows the LEDs being adjusted and the pennies being placed:



Finally, a test of the optical sensor:


Sources

http://pixhawk.ethz.ch/wiki/tutorials/omap/openembedded_bitbake_installation https://help.ubuntu.com/community/SSH/OpenSSH/Keys http://www.debuntu.org/ssh-key-based-authentication-p2 https://help.ubuntu.com/community/MATLAB/R2010b http://rafaelaroca.wordpress.com/2011/08/24/webspectrum/ http://cboard.cprogramming.com/networking-device-communication/119973-rs232-serial-port-library-linux-windows.html http://www.arduino.cc/playground/Interfacing/LinuxTTY http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/ http://todbot.com/blog/2006/12/06/arduino-serial-c-code-to-talk-to-arduino/ http://www.cplusplus.com/reference/clibrary/cstdlib/atof/ http://www.mathworks.com/academia/beagleboard/ http://www.easysw.com/~mike/serial/serial.html http://blog.integrii.net/?p=115

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox
Subscribe to me on YouTube





Hosting By: