Temperature monitoring Tutorial with Scilab/Xcos and Arduino Document version 1 – Yann Debray -­‐ Scilab Enterprises © -­‐ 08/11/2015 This tutorial aims at acquiring a temperature signal through a Arduino board. Configuration/Arduino Setup In order to follow this tutorial you need the following configuration: Software: -­‐ -­‐ -­‐ -­‐ -­‐ Scilab on Windows 32 or 64 bits (Version >= 5.5.2) Arduino IDE http://arduino.cc/en/Main/Software Serial toolbox http://atoms.scilab.org/toolboxes/serial Arduino toolbox http://atoms.scilab.org/toolboxes/arduino Help on the installation of the module: https://www.scilab.org/en/community/education/si/install Analog displays https://fileexchange.scilab.org/toolboxes/312000 Hardware: -­‐ -­‐ -­‐ Arduino Board (driver installation on http://www.arduino.cc/en/Guide/Windows#toc4 ) Breadboard, wires B & B Thermotechnik CON-­‐TF-­‐LM35DZ Temperature Sensor LM 35 DZ For Relative Humidity Detectors. -­‐55 -­‐ +150 °C http://www.conrad.com/ce/en/product/156600/ Hardware Set-­‐up Set up the following hardware configuration: Flash the firmware in the Arduino board Plug your Arduino Board to your PC, open the Arduino IDE and flash the file scilab_temp_reading.ino on the Arduino Board. 1. 2. 3. 4. 5. 6. //TMP36 Pin Variables int sensorPin = 0; //the analog pin the TMP36's Vout (sense) pin is connected to //the resolution is 10 mV / degree centigrade with a //500 mV offset to allow for negative temperatures /* 7. * setup() -­‐ this function runs once when you turn your Arduino on 8. * We initialize the serial connection with the computer 9. */ 10. void setup() 11. { 12. Serial.begin(9600); //Start the serial connection with the computer 13. //to view the result open the serial monitor 14. } 15. 16. void loop() // run over and over again 17. { 18. //getting the voltage reading from the temperature sensor 19. int reading = analogRead(sensorPin); 20. 21. // converting that reading to voltage, for 3.3v arduino use 3.3 22. float voltage = reading * 5.0; 23. voltage /= 1024.0; 24. 25. // print out the voltage 26. Serial.print(voltage); Serial.println(" volts"); 27. 28. // now print out the temperature 29. float temperatureC = (voltage -­‐ 0.5) * 100 ; //converting from 10 mv per degree wit 500 mV offset 30. //to degrees ((voltage -­‐ 500mV) times 100) 31. Serial.print(temperatureC); Serial.println(" degrees C"); 32. 33. // now convert to Fahrenheit 34. float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0; 35. Serial.print(temperatureF); Serial.println(" degrees F"); 36. 37. delay(1000); //waiting a second 38. } Scilab-­‐side script for temperature acquisition The temperature acquisition is directed through the serial communication from the Arduino board to the pc. The serial communication toolbox enables to get the data wired through this protocol in Scilab. The way to exchange data with the serial communication is the following: -­‐ -­‐ -­‐ Open serial communication Read/write on the serial communication Close the serial communication First we open the serial communication on the COM port 1 (example running on Windows OS). We have to enter the communication parameters, in the form "baud,parity,data_bits,stop_bits": -­‐-­‐>h=openserial(1,"9600,n,8,1") Second, we will in this case read the data on the serial port, coming from the temperature sensor on the Arduino board: -­‐-­‐>readserial(h) At last, as we have received the data, we have to close the serial communication: -­‐-­‐>closeserial(h) Graphical User Interface 1: instant temperature value visualization Cf. annexe 1 for the scilab code generating this graphical user interface Graphical User Interface 2: historical temperature values visualization Cf. annexe 2 for the scilab code generating this graphical user interface (with the serial communication) Alternative procedure with the Arduino toolbox for Xcos Go on the following website: http://www.demosciences.fr/projets/scilab-­‐arduino And download the following file: toolbox_arduino_v3.ino Plug your Arduino Board to your PC, open the Arduino IDE and flash the file toolbox_arduino_v3.ino on the Arduino Board. This sketch is based on the demo “potentiometre” of the Arduino toolbox: Start to build the Xcos schema, with the configuration blocks: This allows a serial communication between Arduino and Scilab. Double click on the block to let the following dialog box appear: Set the Serial com port number with the information acquired in the previous step. The sampling of the signal for the blocks of the model and the time of acquisition are configured by this block: The sampling period can be specified and has to be at least twice smaller than the period of evolution of the model (Nyquist-­‐Shannon sampling theorem) Sources Adafruit -­‐ Using a Temp Sensor https://learn.adafruit.com/tmp36-­‐temperature-­‐sensor/using-­‐a-­‐temp-­‐sensor Real-­‐time Temperature Monitoring and Control https://fileexchange.scilab.org/toolboxes/311000/1.0 More readings TP3 : Acquérir et piloter des systèmes à l'aide de cartes Arduino et d'une Toolbox Xcos dédiée -­‐ TP3 Démosciences 2012.pdf http://www.demosciences.fr/projets/scilab-­‐arduino Scilab / Xcos pour l’enseignement des sciences de l’ingénieur – © 2013 Scilab Enterprises chapitre « 4-­‐ acquisition et pilotage de moteur (module arduino) » -­‐ livret_Xcos.pdf www.scilab.org/fr/content/download/1017/9485/file/livret_Xcos.pdf Annexe 1: GUI 1 Scilab script //THIS FUNCTION WILL CREATE A THERMOMETER LIKE DISPLAY OF THE INPUT DATA // //var1: 1xn vector --> data to be displayd //var2: string --> data unit //var3: string --> figure name //var4: [1x2] matrix --> figure position //var5: integer --> figure color //var6: integer --> display color //var7: integer --> the time pause [in milliseconds] after that the // next data point will be displayed. function thermometer(data, unit, figname, figpos, figcolor, dispcolor, tstep) CENTER = [0 0]; END = max(size(data)); fignr = 1002; // use big numbers, so normal figures won't be affected f = figure(fignr); delmenu(fignr,'Datei'); delmenu(fignr,'Zusatzprogramme'); delmenu(fignr,'Editieren'); delmenu(fignr,'?'); toolbar(fignr,'off'); f.background = figcolor; f.figure_size = [5 300]; f.figure_name = figname; f.figure_position = figpos; // define the frame for the thermometer rect=[-1,min(data),1,max(data)]; plot2d(0,0,0,rect=rect); a = gca(); a.visible = "on"; a.box = "off"; a.margins = [0.1,0.4,0.1,0.1]; a.axes_visible = ["off","on","off"]; a.x_location = "middle"; a.y_location = "right"; y_label = a.y_label; y_label.text = unit; a.y_label.font_angle = 0; a.y_label.position = [1.25 max(data)]; a.foreground = dispcolor; a.font_foreground = dispcolor; a.y_label.font_foreground = dispcolor; plot(CENTER(1), CENTER(2),'ro'); e = gce(); p = e.children(1); // get the point as a handle p.mark_style = 1; p.mark_size = 6; // display actual temperature for i=1:END; drawlater(); if data(i) == 0 then; rect=[-0.5,data(i),1,abs(data(i))]; xrect(rect); a = gca(); a.axes_visible = ["off","on","off"]; e = a.children(1); e.background = 1; e.thickness = 1; elseif data(i) > 0; rect=[-0.5,data(i),1,abs(data(i))]; xfrect(rect); a = gca(); a.axes_visible = ["off","on","off"]; e = a.children(1); e.foreground = 5; e.background = 5; e.thickness = 3; else rect=[-0.5,0,1,abs(data(i))]; xfrect(rect); a = gca(); a.axes_visible = ["off","on","off"]; e = a.children(1); e.foreground = 2; e.background = 2; e.thickness = 3; end drawnow(); xpause(tstep*1000); // xpause counts in microseconds, tstep is for milliseconds, thatswhy factor 1000 if i < END delete(e); end end endfunction clc; temp = [0 -5 -10 -15 -25 -40 -10 -5 0 5 10 15 18 20 22 24 26 28 30 35 20 10 5 4 3 2 1 0]; thermometer (temp,'°C','thermometer',[500 300],1,7,50); Annexe 2: GUI 2 Scilab script + serial communication // // Copyright (C) 2014 - A. Khorshidi <[email protected]> // // This file is distributed in the hope that it will be useful; // It must be used under the terms of the CeCILL. // http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt // // // The following work provided the inspiration for this challenge. // https://www.scilab.org/content/view/full/847 // // I owe thanks to Bruno Jofret, the author of the original GUI. // https://fileexchange.scilab.org/toolboxes/270000 // ind = x_choose(["RS-232" ;"USB"; "Ethernet" ;"Wireless"],["Please select the type of communication interface: ";"Just double-click on its name. "],"Cancel"); if ind==0 then msg=_("ERORR: No types of communication interfaces has been chosen. "); messagebox(msg, "ERROR", "error"); error(msg); return; elseif ind==2 if (getos() == "Windows") then if ~(atomsIsInstalled('serial')) then msg=_("ERROR: A serial communication toolbox must be installed."); messagebox(msg, "Error", "error"); error(msg); return; else flag=1; end elseif (getos() == "Linux") then if ~(atomsIsInstalled('serialport')) & ~(atomsIsInstalled('serial')) then msg=_("ERROR: A serial communication toolbox must be installed."); messagebox(msg, "Error", "error"); error(msg); return; elseif (atomsIsInstalled('serialport')) & (atomsIsInstalled('serial')) then stoolbx = x_choose(['serialport';'serial' ],"Which serial ... commiunication toolbox you prefer to use? "," Cancel ") if stoolbx==1 then flag=2; elseif stoolbx==2 then flag=3; else msg=_("ERROR: No serial toolbox has been chosen. "); messagebox(msg, "Error", "error"); error(msg); return; end elseif (atomsIsInstalled('serialport')) then flag=2; elseif (atomsIsInstalled('serial')) then flag=3; end else msg=_(["WARNING: This program has been tested and works under Gnu/Linux ... and Windows."; "On other platforms you may need modify this script. "]) messagebox(msg, "WARNING", "warning"); warning(msg); return; end else error("Not possible yet."); return; end // if (getos() == "Linux") then [rep,stat,stderr]=unix_g("ls /dev/ttyACM*"); if stderr ~= emptystr() then msg=_(["No USB device found. ";"Check your USB connection or try ... another port. "]) messagebox(msg, "ERROR", "error"); error(msg); return; end ind = x_choose(rep,["Please specify which USB port you wanna use for ... communication. ";"Just double-click on its name. "],"Cancel"); if ind==0 then msg=_("ERORR: No serial port has been chosen. "); messagebox(msg, "ERROR", "error"); error(msg); return; end port_name = rep(ind); end if (getos() == "Windows") then port_name=evstr(x_dialog('Please enter COM port number: ','13')) if port_name==[] then msg=_("ERORR: No serial port has been chosen. "); messagebox(msg, "ERROR", "error"); error(msg); return; end end // global %serial_port if flag==2 then %serial_port = serialopen(port_name, 9600, 'N', 8, 1); while %serial_port == -1 btn=messagebox(["Please check your USB connection, and then click on ... Try again. "; "To choose another port click on Change. "], "Error", ... "error", [" Try again " " Change "], "modal"); if ~btn==1 then [rep,stat,stderr]=unix_g("ls /dev/ttyACM*"); ind = x_choose(rep,["Please specify which USB port you wanna use... for communication. ";"Just double-click on its name. "],"Cancel"); if ind==0 then msg=_("ERORR: No serial port has been chosen. "); messagebox(msg, "ERROR", "error"); error(msg); return; end port_name = rep(ind); end %serial_port = serialopen(port_name, 9600, 'N', 8, 1); end elseif flag==1 | flag==3 %serial_port=openserial(port_name,"9600,n,8,1"); //error(999) else msg=_("ERROR: Could not specify which serial toolbox to use. "); messagebox(msg, "Error", "error"); error(msg); return; end // // * Monitoring Phase: // global %MaxTemp %MaxTemp = 35; global %MinTemp %MinTemp = 30; f=figure("dockable","off"); f.resize="off"; f.menubar_visible="off"; f.toolbar_visible="off"; f.figure_name="Real-time Temperature Monitoring and Control"; f.tag="mainWindow"; bar(.5,0,'blue'); e = gce(); e = e.children(1); e.tag = "instantSensor"; // plot([0, 1], [%MinTemp, %MinTemp]); e = gce(); e = e.children(1); e.tag = "instantMinTemp"; e.line_style = 5; e.thickness = 2; e.foreground = color("orange"); // plot([0, 3], [%MaxTemp, %MaxTemp]); e = gce(); e = e.children(1); e.tag = "instantMaxTemp"; e.line_style = 5; e.thickness = 2; e.foreground = color("red"); a = gca(); a.data_bounds = [0, 0; 1, 45]; a.grid = [-1, color("darkgrey")]; a.axes_bounds = [0.1, 0.2, 0.25, 0.85]; a.axes_visible(1) = "off"; a.tag = "liveAxes"; //a.title.text="Current Temperature"; // f.figure_position = [0 0]; f.figure_size = [1000 700]; f.background = color(246,244,242) //color("darkgrey") // minTempSlider = uicontrol("style", "slider", "position", [60 30 30 440], ... "min", 0, "max", 45, "sliderstep", [1 5], "value" , %MinTemp, ... "callback", "changeMinTemp", "tag", "minTempSlider"); maxTempSlider = uicontrol("style", "slider", "position", [20 30 30 440], ... "min", 0, "max", 45, "sliderstep", [1 5], "value" , %MaxTemp, ... "callback", "changeMaxTemp", "tag", "maxTempSlider"); // // Functions: function changeMinTemp() global %MinTemp e = findobj("tag", "minTempSlider"); %MinTemp = e.value //45 - e.value; e = findobj("tag", "instantMinTemp"); e.data(:,2) = %MinTemp; endfunction // function changeMaxTemp() global %MaxTemp e = findobj("tag", "maxTempSlider"); %MaxTemp = e.value //45 - e.value; e = findobj("tag", "instantMaxTemp"); e.data(:,2) = %MaxTemp; endfunction // function closeFigure() stopSensor(); global %serial_port if flag == 2 then serialclose(%serial_port); elseif flag == 1 | flag == 3 then closeserial(%serial_port); end f = findobj("tag", "mainWindow"); delete(f); endfunction // function stopSensor() global %Acquisition %Acquisition = %f; endfunction // function launchSensor() global %MaxTemp global %serial_port global %Acquisition %Acquisition = %t; global %fanStatus %fanStatus = 0; // Arduino toolbox values=[]; value=ascii(0); while %Acquisition while(value~=ascii(13)) then if flag == 2 then value=serialread(%serial_port,1); elseif flag == 1 | flag == 3 then value=readserial(%serial_port,1); end values=values+value; v=strsubst(values,string(ascii(10)),'') v=strsubst(v,string(ascii(13)),'') data=evstr(v) end // xinfo("Temperature = "+v+"°C"); values=[] value=ascii(0); updateSensorValue(data); // global %RegulationEnable if %RegulationEnable == 1 then if data > %MaxTemp then enableFan(); else disableFan(); end end updateFanValue(%fanStatus); end endfunction // function updateSensorValue(data) global %MaxTemp global %MinTemp e = findobj("tag", "instantSensor"); e.data(2) = data; if data > %MaxTemp then e.background = color("red"); else if data > %MinTemp then e.background = color("orange"); else e.background = color("green"); end end // e = findobj("tag", "minuteSensor"); lastPoints = e.data(:, 2); e.data(:, 2) = [lastPoints(2:$) ; data]; e = findobj("tag", "hourSensor"); lastPoints = e.data(:, 2); e.data(:, 2) = [lastPoints(2:$) ; data]; endfunction // // * Regulation Phase: // global %RegulationEnable %RegulationEnable = 1; global %PController %PController = 0; global %PIController %PIController = 0; global %PIDController %PIDController = 0; // top_axes_bounds = [0.25 0 0.8 0.5]; bottom_axes_bounds = [0.25 0.5 0.8 0.5]; minTempDisplay = 20; maxTempDisplay = 45; minRegulationDisplay = -0.2; maxRegulationDisplay = 1.2; // Temperature variations in the last 5 minutes timeBuffer = 300; subplot(222); a = gca(); a.axes_bounds = top_axes_bounds; a.tag = "minuteAxes"; plot2d(0:timeBuffer, zeros(1,timeBuffer + 1), color("red")); a.title.text="Temperature variations in the last 5 minutes"; a.data_bounds = [0, minTempDisplay; timeBuffer, maxTempDisplay]; e = gce(); e = e.children(1); e.tag = "minuteSensor"; // adding a second vertical axis on the right side ... // to show the On/Off status of the DC Fan. a = newaxes(); a.y_location = "right"; a.filled = "off" a.axes_bounds = top_axes_bounds; plot2d(0:timeBuffer, zeros(1,timeBuffer + 1), color("blue")); a.data_bounds = [0, minRegulationDisplay; timeBuffer, maxRegulationDisplay]; a.axes_visible(1) = "off"; a.foreground=color("blue"); a.font_color=color("blue"); e = gce(); e = e.children(1); e.tag = "minuteRegulation"; // Temperature variations in the last hour timeBuffer = 4000; subplot(224); a = gca(); a.axes_bounds = bottom_axes_bounds; a.tag = "hourAxes"; plot2d(0:timeBuffer, zeros(1,timeBuffer + 1), color("red")); a.title.text="Temperature variations in the last hour"; a.data_bounds = [0, minTempDisplay; timeBuffer, maxTempDisplay]; e = gce(); e = e.children(1); e.tag = "hourSensor"; // 2nd vertical axis a = newaxes(); a.y_location = "right"; a.filled = "off" a.axes_bounds = bottom_axes_bounds; a.axes_visible = "off"; plot2d(0:timeBuffer, zeros(1,timeBuffer + 1), color("blue")); a.data_bounds = [0, minRegulationDisplay; timeBuffer, maxRegulationDisplay]; a.axes_visible(1) = "off"; a.foreground=color("blue"); a.font_color=color("blue"); e = gce(); e = e.children(1); e.tag = "hourRegulation"; // // Functions: function resetDisplay() e = findobj("tag", "instantSensor"); e.data(:, 2) = 0; e = findobj("tag", "minuteSensor"); e.data(:, 2) = 0; e = findobj("tag", "hourSensor"); e.data(:, 2) = 0; e = findobj("tag", "minuteRegulation"); e.data(:, 2) = 0; e = findobj("tag", "hourRegulation"); e.data(:, 2) = 0; endfunction // function changeRegulationStatus() global %RegulationEnable e = findobj("tag", "enableRegulationCBO"); %RegulationEnable = e.value; if %RegulationEnable == 0 then disableFan(); end endfunction // function updateFanValue(data) e = findobj("tag", "minuteRegulation"); lastPoints = e.data(:, 2); e.data(:, 2) = [lastPoints(2:$) ; data]; e = findobj("tag", "hourRegulation"); lastPoints = e.data(:, 2); e.data(:, 2) = [lastPoints(2:$) ; data]; endfunction // function enableFan() global %serial_port if flag == 2 then serialwrite(%serial_port,'H'); elseif flag == 1 | flag == 3 then writeserial(%serial_port,ascii(72)); end global %fanStatus %fanStatus = 1; endfunction // function disableFan() global %serial_port if flag == 2 then serialwrite(%serial_port,ascii(76)); elseif flag == 1 | flag == 3 then writeserial(%serial_port,"L"); end global %fanStatus %fanStatus = 0; endfunction // // Buttons: // * Main Panel mainFrame = uicontrol(f, "style", "frame", "position", [15 560 305 80], ... "tag", "mainFrame", "ForegroundColor", [0/255 0/255 0/255],... "border", createBorder("titled", createBorder("line", "lightGray", 1)... , _("Main Panel"), "center", "top", createBorderFont("", 11, "normal"), ... "black")); // startButton = uicontrol(f, "style", "pushbutton", "position", ... [20 595 145 30], "callback", "launchSensor", "string", "Start Acquisition", ... "tag", "startButton"); // stopButton = uicontrol(f, "style", "pushbutton", "position", ... [170 595 145 30], "callback", "stopSensor", "string", "Stop Acquisition", ... "tag", "stopButton"); // resetButton = uicontrol(f, "style", "pushbutton", "position", ... [20 565 145 30], "callback", "resetDisplay", "string", "Reset", ... "tag", "resetButton"); // quitButton = uicontrol(f, "style", "pushbutton", "position", ... [170 565 145 30], "callback", "closeFigure", "string", "Quit", ... "tag", "quitButton"); // RegulationFrame = uicontrol(f, "style", "frame", "position", [15 490 305 65]... ,"tag", "mainFrame", "ForegroundColor", [0/255 0/255 0/255],... "border", createBorder("titled", createBorder("line", "lightGray", 1), ... _("Regulation Mode"), "center", "top", createBorderFont("", 11, "normal"),... "black")); // // * Regulation Mode enableRegulation = uicontrol(f, "style", "checkbox", "position", ... [20 520 140 20],"string", "ON/OFF", "value", %RegulationEnable, ... "callback", "changeRegulationStatus", "tag", "enableRegulationCBO"); // enableP = uicontrol(f, "style", "checkbox", "position", [20 500 140 20], ... "string", "P Controller", "value", %PController, ... "callback", "", "tag", ""); // enablePI = uicontrol(f, "style", "checkbox", "position", [170 520 140 20], ... "string", "PI Controller", "value", %PIController, ... "callback", "", "tag", ""); // enablePID = uicontrol(f, "style", "checkbox", "position", [170 500 140 20], ... "string", "PID Controller", "value", %PIDController, ... "callback", "", "tag", ""); //