AzeoTech Posted July 26, 2008 Share Posted July 26, 2008 In a previous post I talked about how to do one of the two main types of "recipes". In that case a recipe was a set of preset values that would be sent to a device. This might be used, for example, when mixing paints. A recipe would be the amount of the primary colors to make the final result. In this post I'd like to show you how to do the other type of recipe. In this case, a recipe is really just a high level set of steps to perform. Truthfully, DAQFactory scripting is just low level, highly flexible, recipe system of this sort, but with power comes some learning, and you may only want to give you end users a few choices. My description is a little detailed, but the sample is pretty easy to expand on without completely understanding it all, and truthfully, the sample shows some good ways to make many tasks easier, so is worth figuring out if you are going to do any advanced DAQFactory scripting. In the attached sample (requires 5.78+), I have created a simple heater / temperature simulation that can be controlled from a simple, user definable recipe. The user can create up to five steps in their recipe and they have a few choices for what they can do in each step, mainly, turn the heater on, turn the heater off, wait for the temperature to reach a certain point, and do a pause. The user can specify the recipe by selecting from these options in combo boxes, with edit boxes that appear when a parameter is required. As usual, I designed this sample so you can easily build on it. The possible recipe steps are stored in three arrays, one for the name of the step, one for the action and one for a flag that marks if there is a parameter for the action. These are all defined in StartUp. To add more steps possibilities, just add on to the array in StartUp. Note that the StepAction is a string that contains a DAQFactory script line. It is injected with a value using format() which is what allows a parameter to be set. Just use %f in the line wherever you want the parameter. The recipe itself is stored in two arrays, one for the step index, and one for the parameter (if any for that step). At the end of startup, I filled all the combos with the choices. I only made 5 combos, but you could easily make the recipes longer by adding more combos and edit boxes. Just change MAXSTEPS and add the new screen components, remembering to edit the parameters for each. Speaking of the screen components, the recipe gets specified by the user using a set of combo's and edit boxes. The edit boxes appear and disappear depending on whether the selected step has a parameter to specify. This is done in the OnPaint event of the edit box (you have to View - Events to see it). Yes, I know I've previously lectured on why you shouldn't use edit boxes on main screens, but presumably you would NOT put a recipe specification on a main screen, and instead would create a popup or secondary screen that has to be acknowledged. Finally, the actual recipe gets run in the RunRecipe sequence, which really just loops through each step and calls execute() on it. Notice how, instead of using delay() for the pause step, I created a sequence function. This allows the recipe to be stopped midway in a controlled manner. This is better than simply stopping the RunRecipe sequence because if we do endseq() on a sequence, we don't know where it ended. So, to try it, I recommend creating a recipe something like this: Heater On WaitForTemperature xx.xxx Heater Off where xx.xxx is some temperature that is about 0.5 higher than the current displayed temperature. Then run the recipe. Feel free to post with questions. Again, this sample requires DAQFactory 5.78 or later. recipesample2.ctl Link to comment Share on other sites More sharing options...
opticaldynamics Posted April 20, 2009 Share Posted April 20, 2009 Hi, This is a real good piece of information. I guess you can ignore my post from sequences and scripting (switch, case statements), unless you have some time and it is easy to show. I would like to be able to upload my current temp control code into your recipee code. For the future, I figure I will vary recipees for example by only adding a few lines of code such as a digital output line that will trigger a cooling system in my temperature reactor. Link to comment Share on other sites More sharing options...
thermocouplesohmy Posted April 28, 2009 Share Posted April 28, 2009 Hello I have a similar question as well. In your example, how can I hold the temperature at a certain value. For example, If I want to go from 80 celsius and then down to 50 celsius and stay there for 3 hours? Thanks Link to comment Share on other sites More sharing options...
AzeoTech Posted April 28, 2009 Author Share Posted April 28, 2009 Well, if you just want to delay for 3 hours without control, there is already a step for that. Otherwise if you want control, you'll have to add another step. I'd duplicate the delayfor() sequence, then modify it and add some control script. You'd then add a new possible step in the startup sequence, it will be [6] and might look like: StepName[6] = "Hold" StepAction[6] = "HoldFor(%f)" // %f means put a floating point value here, this is the parameter. StepParameter[6] = 1 The HoldFor sequence might look like: function HoldFor(len) // capture current temp and hold at that temp: private holdtemp = temperaturein[0] // hysteresis on controller private hyster = 3 private endtime = systime() + len while ((systime() < endtime) && RecipeRunning) // control if (temperatureIn[0] > holdtemp + hyster) heater = 0 endif if (temperatureIn[0] < holdtemp - hyster) heater = 1 endif // always delay in loop: delay(1) endwhile Link to comment Share on other sites More sharing options...
thermocouplesohmy Posted April 29, 2009 Share Posted April 29, 2009 Hi again, I have tried the code and I am getting hung up when I run the recipee. I have Daq Express and have virtually no access to create many components. I don't know if this is my problem. Anyway, I added a sequence called control and wrote the code as you had it, starting with: function HoldFor(len) I also edited startup and added maxsteps as 6 now. I had to edit your combo boxes and added an option for Hold. It was number 6 in order and F. That is all I did. When I run the recipee I do for example: Heater on Waitfortemp 90 heater off waitfortemp 60 hold 60 ( I don't know if this is right.....at this point I want it to hold the 60....I think the parameter entry is in seconds and is the amount I want to hold it for???) Either way, when it gets to hold 60 it just ends the recipee. I also get an error: Ch or fxn not found: Line 1: RunRecipe Line 7 - Uncaught error in sequence RunRecipe (the line is: execute[format(StepAction[stepnum], RecipeParams[RecipeStepCount])) There is also an error in the control code: the line: private endtime=systime() + len (what is len...is it length? and do I have to specify it as anything?) I am relatively new with this application and I couldn't find many guides on recipees. I am working on a project for school and I have to create a GUI kind of like the recipee and eventually I have to add more steps. For example: If I want heater on waitfortemp90 heateroff waitfortemp60 hold (for three or whatever hours at 60) maybe a rapidcooling output here endrecipee As you can see that is more options than your recipee. To make more combo boxes, do I need a newer version of daqfactory such as starter???? or can I just copy and paste the components. Thanks Link to comment Share on other sites More sharing options...
AzeoTech Posted April 29, 2009 Author Share Posted April 29, 2009 Can you please post your .ctl document? Link to comment Share on other sites More sharing options...
thermocouplesohmy Posted April 29, 2009 Share Posted April 29, 2009 I've attached the file TempRecipee.ctl Link to comment Share on other sites More sharing options...
thermocouplesohmy Posted April 29, 2009 Share Posted April 29, 2009 I'm an idiot. I posted the document on another topic that I found similar to mine. I've been searching through them and some are really helpful for other stuff i've been doing. It is in the components forum and called edit boxes. I had trouble loading it here for you. Sorry Link to comment Share on other sites More sharing options...
particleman Posted May 21, 2013 Share Posted May 21, 2013 Hi there, We are applying a recipe approach to control and synchronize several instruments, based loosely on the control file given in this thread. I am getting snagged on one step, and feel like I'm missing something obvious. We have defined a step where we want to 'delay' the continuation of the recipe until a data file is written to a directory. An instrument (the ACSM) takes a slightly variable amount of time to complete a run, but writes a data file based on the time (at UTC) at which the run is completed. So we just want to scan its data directory for when that file is written and then resume the recipe (following steps) when that's done. I have written a sequence (pasted below) that polls the directory and seems to work, however if I implement it as a sequence (using beginseq) it just runs in parallel with the 'run recipe' sequence and doesn't cause anything to actually pause. On the other hand, if I implement it as a function (as the recipe steps are, and as is shown below), then DAQFactory hangs until the file is actually written (at least the interface does, I'm not sure if acquisition and control are affected). I have tried changing the thread priority and that doesn't help. I've also played around with making a channel that polls the directory, but didn't get any traction. This seems like it should be a straightforward thing to do - what am I missing? many thanks, Andy My sequence/function: function ACSM_check() private string temp_path private string temp_date private string temp_filename private string ACSM_path = "z:\ACSMData\ScanData\" private utc_time private time_lag = 5 //to allow for time lag in writing/accessing file private ACSM_done = 0 if(file.getfileexists(ACSM_Path+"\*") == 0) throw("Can't find ACSM Directory Specified!") endif while(ACSM_done == 0) utc_time = systime()+4*3600 - time_lag temp_date = FormatDateTime("%Y%m%d",utc_time) temp_filename = temp_date+"_"+FormatDateTime("%H_%M_%S",utc_time)+".itx" temp_path = ACSM_path+temp_date+"\"+temp_filename ACSM_done = file.GetFileExists(temp_path) //flag for whether ACSM file has been written this second delay(0.2) endwhile Link to comment Share on other sites More sharing options...
AzeoTech Posted May 21, 2013 Author Share Posted May 21, 2013 If you call it as a function from the user interface thread (meaning from the command / alert window, or in a component Action), then yes, it will hang the user interface until complete. However, presumably you are running the recipe in its own sequence? If you start that sequence using beginseq() or similar and not as a function, then it will run as its own thread. Then if it calls this sequence as a function, the function will run in that sequence's thread and not hang the UI. Note that sequence priority has no effect if you call the sequence as a function. Link to comment Share on other sites More sharing options...
particleman Posted May 21, 2013 Share Posted May 21, 2013 Aha! I knew it was something silly like that... Thanks so much, I now also better understand the difference between a function and a sequence! Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.