Monitoring auto sensor data with the Raspberry Pi
Jr_candump
A boot-up script, performs all necessary steps when the Rasp Pi starts up:
ifconfig can0 up /home/pi/can-utils/jr_candump can0 -D &
The first line of the script activates the network interface of the CAN adapter, and then jr_candump
starts. This is the modified Candump program with its accompanying parameters. It was modified so that the received data can be written to a database via the -D
option. After the program starts, jr_candump
creates a database, builds a table in the database with the SQL statement from line 1 of Listing 5, then prepares the SQL statement from line 2 to store the data.
Listing 5
Storing Data in the Database
CREATE TABLE IF NOT EXISTS candata(id FLOAT, timestamp FLOAT, yawrate VARCHAR(4), \ accy VARCHAR(4), rollrate VARCHAR(4), accx VARCHAR(4), accz VARCHAR(4), \ fueltemp VARCHAR(4), watertemp VARCHAR(4), oilpressure VARCHAR(4), \ oiltemp VARCHAR(4)) ENGINE = MEMORY INSERT INTO candata (id, timestamp, yawrate, accy, \ rollrate, accx, accz, fueltemp, watertemp, oilpressure, oiltemp) \ VALUES (?,?,?,?,?,?,?,?,?,?,?)
As shown at the end of line 1, the database resides in the central memory of the Rasp Pi. The data cannot be saved directly onto the SD card because it arrives too fast. In the final step, the jr_candump
utility connects the correct variables with the corresponding placeholders in the INSERT
statement from line 2. After the preparation of the database, jr_candump
calls a function to interpret each received CAN message. The basic structure can be seen in Listing 6.
Listing 6
Interpreting CAN Messages
01 switch (frame.can_id) { 02 case 0x713: 03 sprintf(fueltemp, "%02x", frame.data[4]); 04 sprintf(watertemp, "%02x", frame.data[7]); 05 sprintf(oilpressure, "%02x", frame.data[0]); 06 sprintf(oiltemp, "%02x", frame.data[5]); 07 InsertCANframe(); 08 break; 09 /* next CAN-ID ... */ 10 }
The interpretation routine determines the CAN ID of an incoming message via a switch
statement and then writes the current data received to the appropriate variables. This is followed by a call to the InsertCANframe()
function, which increases the ID counter that numbers the individual records in the database and uses the previously prepared INSERT
statement to write the variable values to the database.
Visualizing the Data
The Apache web server that is running on the Rasp Pi reads the data from the database and then makes it available online with the help of a small PHP application.
In the process, the data stream is constantly updated via Ajax (asynchronous JavaScript and XML). And, at the same time, the data is visualized via jqPlot [6] by means of the jQuery framework [7] (see Figure 6).
Here, a web application uses JavaScript to gather new data continuously from the server and display it on a website. As a result, the team receives online access to all relevant parameters.
A PHP script called by Ajax at three-second intervals is responsible for loading measurements from the database. The script delivers the data as a JSON file (JavaScript Object Notation, a compact, text-based and easy-to-read (via eval()
) data exchange format for humans and computers.
Listing 7 shows a somewhat abbreviated version of this script. You can see that the code delivers the most recently received ID, ($maxID
) each time the script is called up, so only the new data is retrieved.
Listing 7
Loading Data from the Database
01 <?php 02 $maxID = $_GET['maxID']; 03 $sqlhost = 'localhost'; 04 $sqluser = 'user'; 05 $sqlpwd = '*****'; 06 $sqldb = 'jr_data'; 07 08 $dbh = new PDO("mysql:host=$sqlhost;dbname=$sqldb", $sqluser, $sqlpwd); 09 $sth = $dbh->prepare('SELECT * FROM candata WHERE id > ?;'); 10 $sth->execute(array($maxID)); 11 $cnt = 0; 12 while ($row = $sth->fetch(PDO::FETCH_OBJ)) { 13 $ID[$cnt] = $row->id; 14 $TIMEST[$cnt] = $row->timestamp; 15 $FUELTEMP[$cnt] = hexdec($row->fueltemp); 16 $WATERTEMP[$cnt] = hexdec($row->watertemp); 17 $OILPRESSURE[$cnt] = hexdec($row->oilpressure); 18 $OILTEMP[$cnt] = hexdec($row->oiltemp); 19 $cnt++; 20 } 21 $result = array( 22 'NEWid' => $ID, 23 'NEWtime' => $TIMEST, 24 'NEWfueltemp' => $FUELTEMP, 25 'NEWwatertemp' => $WATERTEMP, 26 'NEWoilpressure' => $OILPRESSURE, 27 'NEWoiltemp' => $OILTEMP 28 ); 29 echo trim(json_encode($result)); 30 ?>
As a result, the current data values appear on the website with three to five seconds of lag time. Here, jqPlot offers wide ranging possibilities. Listing 8 and Figure 7 illustrate a simple example for the display of a JavaScript array.
Listing 8
Displaying a JavaScript Array
01 <?xml version="1.0" encoding="UTF-8"?> 02 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 03 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 04 <html xmlns="http://www.w3.org/1999/xhtml"> 05 <head> 06 <title>Oil Temperature Plot</title> 07 <script type="text/javascript" src="jquery.min.js"></script> 08 <script type="text/javascript" src="jquery.jqplot.min.js"></script> 09 <link rel="stylesheet" type="text/css" href="jquery.jqplot.css" /> 10 </head> 11 12 <body> 13 <div id="chartdiv" style="height:200px;width:500px;"></div> 14 <script type="text/javascript"> 15 16 // An example, the values of the array are updated 17 // using AJAX in reality: 18 var oiltemp = [50, 53, 55, 50, 52, 60, 60, 50, 53, 50]; 19 $.jqplot('chartdiv', [oiltemp], { 20 axes: { 21 xaxis: { label: 'Time' }, 22 yaxis: { label: 'Oil Temperature' } 23 } 24 }); 25 </script> 26 </body> 27 </html>
Buy this article as PDF
Pages: 8
(incl. VAT)