Newbie sequence question


middlehill

Recommended Posts

Hi,

I'm a total beginner beginner with Labjack and Daqfactory, I was hoping someone you could point me in the right direction with a solution I'm trying to put together.

I've been playing around with the basic functions and features, and I think I have some basic understanding how to set up channels and how to convert sensor data into correct units. The stumbling block for me is the construction of a sequence for logging and showing data, my attempts based on various examples just don't seem to work...

The application is a mobile laptop/Labjack measuring unit attached to a motorcycle. The objective is to measure the deceleration rate and braking power during one braking event.

So far I have set up three channels:

- WheelSpeed (a counter channel receiving pulses from the opto hook sensor, attached to an additional measuring wheel)

- BrakePower (an analog input channel, attached to a power sensor in the brake handle)

- StartSwitch (digital input channel, used as a start switch)

The test procedure would be something like this:

1. driving the bike 100-150 km/h

2. press the Start switch (I guess this could also be triggered by the brake handle power sensor?)

3. Start braking

4. Log the deceleration and brake handle force during the braking until halt.

The results should be viewable as a table and a graph, showing deceleration rate and brake handle force as a function of time. Total braking time would also be useful.

I'd be really grateful, I someone could give me pointers regarding the basic structure of a sequence that would accomplish this. (Setting up the channels at least seems to be the easy part, but the sequences are not so easy to grasp for a beginner...)

Jari V

Link to comment
Share on other sites

Why do you need a sequence at all? Would it be a problem to just read and graph your three inputs continuously? Create a graph object with 3 separate traces - one for each input. then you can select any data that you want to save.

Link to comment
Share on other sites

That is true. It just depends on how much you want DAQFactory to do for you while taking data, and how much you want to do afterwards using a data analysis tool. Personally I would log all data as jfiddler recommended and then analyze it afterwards, but if you only wanted to log after the brake was depressed, go to the event for the brake channel and add code something like this:

if (Brakechannel[0]) // assume 1 means brake depressed, 0 not
   beginlogging(mylog)
endif

You'll have to stop logging manually, or use an event on the speed channel to turn off logging when it gets to 0.

Finally, I delayed initially responding to this post because I am concerned about the danger of modifying a motorcycle and the potential of adversely affecting the braking system on the bike and injuring yourself. This is much more of an issue on a motor bike than a car. Remember, even tapping into an existing system can cause problems if not done correctly, especially with today's advanced automotive systems. Tapping into safety systems (like brakes, airbags, steering, etc.) should only be done by the manufacturer of the safety systems and with proper testing. For this reason AzeoTech is strongly recommending that you do not do this experiment on the road and instead do it on a stationary dyno, which is the proper place to do it and would be much, much safer. Even if you do it on the dyno, you should probably replace any modified parts before riding the same bike on the road.

Please re-read the end user license agreement of DAQFactory and the warning in the beginning of the LabJack manuals as well.

Link to comment
Share on other sites

Thanks for your replies,

Why do you need a sequence at all? Would it be a problem to just read and graph your three inputs continuously? Create a graph object with 3 separate traces - one for each input. then you can select any data that you want to save.

Well, I don't know exactly what I need as far as the logging application is concerned...

For the logging itself, there is a requirement to be able to save the logged brake tests in some form, preferably a graph/table combination.

Would this be possible without using sequences?

Finally, I delayed initially responding to this post because I am concerned about the danger of modifying a motorcycle and the potential of adversely affecting the braking system on the bike and injuring yourself. This is much more of an issue on a motor bike than a car. Remember, even tapping into an existing system can cause problems if not done correctly, especially with today's advanced automotive systems. Tapping into safety systems (like brakes, airbags, steering, etc.) should only be done by the manufacturer of the safety systems and with proper testing. For this reason AzeoTech is strongly recommending that you do not do this experiment on the road and instead do it on a stationary dyno, which is the proper place to do it and would be much, much safer. Even if you do it on the dyno, you should probably replace any modified parts before riding the same bike on the road.

The logging of the brake tests is for a company, that is certified to evaluate various motorcycle related modifications in order to get approval from authorities, so this is not anything unusual for them.

Jari V

Link to comment
Share on other sites

For the logging itself, there is a requirement to be able to save the logged brake tests in some form, preferably a graph/table combination.

Would this be possible without using sequences?

Yes, just create a logging set and log to a CSV (ASCII delimited) file as is shown in the guided tour and in the logging section of the help. Once in CSV form you can load into any application to do graphing. The easiest and most common for most people is Excel.

The logging of the brake tests is for a company, that is certified to evaluate various motorcycle related modifications in order to get approval from authorities, so this is not anything unusual for them.

Great, it sounds like you have a handle on it. I hope you understand our concern.

Link to comment
Share on other sites

  • 3 weeks later...

Why do you need a sequence at all? Would it be a problem to just read and graph your three inputs continuously? Create a graph object with 3 separate traces - one for each input. then you can select any data that you want to save.

I have made following virtual channels to calculate acceleration/deceleration and speed:

(Counter is set to 0.1 sec timing)

V. Accel = (Counter[6]-Counter[10])*0.1659-(Counter[1]-Counter[5])*0.1659

V.Speed = (Counter[0]-Counter[10])*0.1659

The data appears to be correct when looked at using a variable value component.

I just can't figure out how to set a 2D graph component to show these channels in the graph.

Adding traces with Y expression = V. Accel or V.Speed and X Expression = Time are not showing anything (the only channel that I got working in the graph is the Counter).

I must be missing something here...?

Also, is it somehow possible to reset the X axis time values, so that in a 60 second test the X-axis values would be between 0-60 secs?

Any help would be greatly appreciated.

Jari V

Link to comment
Share on other sites

The problem is that your expressions for your V channels result in scalars, not arrays. You can see this by clicking on the V channel in the workspace and then going to the Table tab. A graph cannot display a scalar because thats only one data point and you need two data points to draw a line.

I can tell you have a scalar by looking at your expression:

V. Accel = (Counter[6]-Counter[10])*0.1659-(Counter[1]-Counter[5])*0.1659

Here you have some constants (0.1659), which is of course a scalar, and you reference the counter channel. When you reference the counter channel though you are subsetting to a scalar value. [6] means return the 7th most recent value. [1] means the 2nd most recent value. So, you basically have an expressions with only scalars, so the result is a scalar.

So, to get V.Accel to be an array of values you need to keep Counter as an array. How you do this depends a little on what you want, but I'm going to assume that a running count will work for. Lets assume your history is set to the default 3600:

V. Accel = (Counter[6,3600]-Counter[10,3600])*0.1659-(Counter[1,3600]-Counter[5,3600])*0.1659

By doing counter[x,3600] we are getting an array of values starting at the x data point and going to the end of the history. For example, if Counter had:

{1,2,3,4,5, ...}

and we did:

Counter[1,3600] - Counter[2,3600]

this would reduce to:

{2,3,4,5,...} - {3,4,5,....}

or

{-1,-1,-1,....}

As you can see, the end result is an array, and so can be graphed. Note that [0] is the most recent value, not [1]. Also, obviously [1,3600] and [2,3600] are two different sized arrays. DAQFactory will automatically truncate the larger array to the size of the smaller array (by truncating the end, or oldest, data points).

Now, for your other question. Yes, you can. To do this, you need a global variable storing the start or 0 time. Something like:

global starttime

and then when you want the 0 time, put:

starttime = systime()

Now, in your graph, put this, for example, for the X Expression:

V.Accel.Time - starttime

That will simply subtract the starttime from the time of each data point in V.Accel. You'll need to set the bottom axis style to "Lin" as well, turn of "Use Time Width" and set the scaling to 0 to 60.

Link to comment
Share on other sites

Thanks a lot,

I got the graph working, and even seconds are displayed from the point where starttime = systime() is set. (allthough running a sequence with a row: v.starttime = systime() shows an "uncaught error in sequence" error)

But I'm afraid I still have some obvious newbie questions left...

Now that the graph is displaying correct data, I can manually freeze the graph when the test is completed for taking a pdf or a printout of the screen. Is it possible to freeze the graph automatically once the test is done (for example when the speed has gone to 0)?

Also, is it possible to have the same data displayed simultaneously in a table where the columns would be something like: time (secs), speed, acceleration and brake pressure, and which also could be frozen like the graph?

I noticed that if the graph is frozen, and the data is then exported from the graph, the program keeps adding data in the background and produces different data from which is shown in the frozen graph, also the x-axis time values (secs) are not exported at all.

Thanks in advance,

Jari V

Link to comment
Share on other sites

Now that the graph is displaying correct data, I can manually freeze the graph when the test is completed for taking a pdf or a printout of the screen. Is it possible to freeze the graph automatically once the test is done (for example when the speed has gone to 0)?

Yes:

1) name your graph by selecting it, then right clicking and selecting Component name.... Lets say you named it MyGraph.

2) In script somewhere you can freeze the graph by doing Component.MyGraph.XAxisFrozen = 1

The other thing you could do is simply scale the graph appropriately in the x axis. This is probably a better way. So, you set the Scale From to 0 (the start), and then set the Scale To to a variable. Lets say you used GraphScaleTo. In the event your speed channel, you would put code like this:

if (speed[0]) // non-zero
   GraphScaleTo == Systime() - starttime
endif

So, the graph scaling will only change when the speed is non-zero.

Also, is it possible to have the same data displayed simultaneously in a table where the columns would be something like: time (secs), speed, acceleration and brake pressure, and which also could be frozen like the graph?

Yup, just use the table component. This time you'll want to subset each column by time. DAQFactory will automatically subset by the time of the data instead of the index if the values in the [] are time values. So:

speed[starttime,starttime+GraphScaleTo] 

will return an array of all values in the experiment, and only between starttime and the last graphscaleto time.

You may need to add scrollbars, in which case you'll need another variable and more subsetting. Lets call the other variable TableScroll and initialize it to 0:

global tablescroll = 0

Then, use a scroll bar, or buttons to change this value. In the table, your expressions will be doubly subset. For exmple:

(speed[starttime,starttime+GraphScaleTo])[tablescroll,tablescroll+20]

The inside subset gives us the data within the experiment, and then we further subset it to give us just 21 rows starting at tablescroll. That means as you change tablescroll, new values will appear.

v.starttime = systime() shows an "uncaught error in sequence" error

Did you create a v channel called starttime? Really you should use variables for this and not v channels. V channels are a bit of a left over from earlier versions of DAQFactory, and are really only useful for what you are doing with them in that calc, namely, making a dynamic variable that is simply a calculation, which saves you from retyping the calc everytime.

Link to comment
Share on other sites

  • 2 months later...

Hi again,

Now I'm trying to set up a number of indicator leds for various braking-start-speeds (leds are located at the control unit attached to the handle)

I've created a few Dig out channels for the signal leds (L_Green, L_Red, LYellow etc). How can I make them light up automatically at a given speed (+/- 1 km/h)?

The speed is calculated from the counter signal (Counter[0]-Counter[4])*0.1659)

I've tried to play around with the channnel events, but so far I've only managed to crash the application...maybe they are not the way to do this?

Thanks in advance,

Jari V.

Link to comment
Share on other sites

I'm not sure what you did in the channel events to crash it, maybe put a while loop?

Anyhow, you should be able to go to the event on Counter and do something like this:

private speed = (Counter[0]-Counter[4])*0.1659)
switch
   case(speed > 10)
	   LGreen = 1
	   LYellow = 0
	   LRed = 0
   case(speed > 20)
	   LGreen = 0
	   LYellow = 1
	   LRed = 0
   case(speed > 30)
	   LGreen = 0
	   LYellow = 0
	   LRed = 1
endcase   

Now with the U12, this will slow down your acquisition as for every counter read, you are setting 3 digital outputs (at 20 ms each). The U3 / UE9 won't have this problem nearly as much, though if you are streaming the counter real fast it might be an issue. If your are acquiring counter real fast (say > 10hz), you may want to simply use a sequence instead of an event. The code would be very similar:

private speed
while (1)
   speed = (Counter[0]-Counter[4])*0.1659)
   switch
	  case(speed > 10)
		  LGreen = 1
		  LYellow = 0
		  LRed = 0
	  case(speed > 20)
		  LGreen = 0
		  LYellow = 1
		  LRed = 0
	  case(speed > 30)
		  LGreen = 0
		  LYellow = 0
		  LRed = 1
   endcase   
   delay(0.5)
endwhile

Then just let this sequence run continuously. By putting this code in a sequence you are separating out the acquisition of your input signal from the setting of your LEDs so they won't interfere with each other (unless you have a U12, since the U12 itself will be a bottleneck). Since LEDs are visual, really a delay of 0.5 seconds before the LED turns on / off shouldn't be a problem. You can tighten this up by reducing the delay but that will of course use more CPU / LabJack power.

Link to comment
Share on other sites

Thanks a lot again.

It seems that a sequence is probably better option here.

I'd need the leds to light up only very close to a certain speed, for example LRed at 99-101 km/h and LGreen at 59-61 km/h.

How can you specify a range for a single led? Also, can you run several such "background-service-type" sequences in the backround simultaneously without problems?

Jari V.

Link to comment
Share on other sites

Well, if you are using a U3 or UE9 where communications speed with the device is not much of an issue (as opposed to the U2 which takes like 20ms to do any one thing), you can do this very easily using simple boolean math. Instead of the case statement, put something like:

private speed = (Counter[0]-Counter[4])*0.1659)
while (1)
   LRed = (speed >= 99) && (speed <= 101)
   LGreen = (speed >= 59) && (speed <= 61)
   delay(0.5)
endwhile

This uses a bit of extra communication bandwidth since we are setting the LEDs every time, even if their state doesn't change, but as I said, with the U3 and UE9 this is probably not a problem.

As for your question about sequences, yes, you most definitely can create a number of sequences that all run concurrently and do different things. This is one of the cool features of DAQFactory. You can split your tasks as you deem fit and do a sort of "fire and forget" with each one. You have to think about any cross linking though, i.e. when two different sequences work with the same hardware. With fast devices like the U3 / UE9, this isn't much of a problem, but with the U12 it could be. Even though you have two different sequence doing things simultaneously, doesn't mean you can do more than the hardware can, and most hardware devices can only handle one command at a time.

That said, if you had multiple devices, U12 or otherwise, you can really optimize your performance using sequences by creating a separate sequence for each device. You can even do this with Channels by using different Timing/Offset combinations for each device. This puts them in different threads and so they don't interfere with each other.

Link to comment
Share on other sites

Thanks again,

I made a continuously running sequence with the code:

private speed = (Counter[0]-Counter[4])*0.1659)
while (1)
   LRed = (speed >= 99) && (speed <= 101)
   LGreen = (speed >= 59) && (speed <= 61)
   delay(0.5)
endwhile

(there was an additional/missing bracket in the first row, I changed that to:

private speed = ((Counter[0]-Counter[4])*0.1659)

For some reason, this doesn't seem to switch on the leds (Dig Out). Which part of the code sets the led channel to 1?

Any ideas where the problem might be?

Btw, we have an old U12, it seems like a good idea to get a U3/U9 for this application?

Jari V.

Link to comment
Share on other sites

Hi again,

I played a bit more with the sequence, maybe this helps for troubleshooting.

If you set the speed first at either of the specified ranges, and then start the sequence, correct led will light up. But when the speed goes out of the range, the led doesn't come off. Also, if the start speed is outside the specified range, and when the speed reaches it, then the led doesn't come on.

Jari V.

Link to comment
Share on other sites

Sorry about that typo. My keyboard has been dying over the past week and not typing characters or getting stuck in Shift or Ctrl mode. Very annoying, but almost as annoying is getting used to my new keyboard :)

First, yes, a U3 would work better for this, though as long as your loops are long and you aren't doing anything too quick the U12 might be OK.

I'm not sure why your code isn't working. LRed and LGreen should be the name of your digital out channels. To test the code, I created this sequence:

global speed = 0
global lred = 0
global lgreen = 0
while (1)
   lred = (speed >= 99) && (speed <= 101)
   lgreen = (speed >= 59) && (speed <= 61)
   delay(0.5)
endwhile

and then created two LEDs on a page showing the status of lred and lgreen. Then at the command line I simply typed in different speed numbers:

speed = 100

and watched the LEDs switch on and off as expected.

(Note that if you start with this and then try and move lred / lgreen to channels, you're going to have to do clearglobals() to get rid of the lred/lgreen global variables as well as eliminating it from the sequence.)

Link to comment
Share on other sites

Hi again,

Sometimes, but not every time, there is an error displayed when the sequence Speedleds is started:

private speed = ((Counter[0]-Counter[4])*0.1659)
while (1)
   LRed = (speed >= 99) && (speed <= 101)
   LGreen = (speed >= 59) && (speed <= 61)
   delay(0.5)
endwhile

Error:

C1086 One of the parameters was empty: Speedleds Line 3 - Uncaught error in sequence Speedleds

One more thing, what do you exactly mean by "do clearglobals()", I couldn't find anything about that in the manual?

Jari V

Link to comment
Share on other sites

This may happen when you first start and haven't read 5 counter readings yet. Counter[4] then is empty, and Counter[1] - empty = empty, so speed becomes empty, which is fine until you do the comparison in line 3. Make sure you don't start your sequence until 5 readings have occured, or put:

waitfor(!isempty(counter[4]),1)

in the top of the sequence. This will cause the sequence to wait until counter[4] is not empty. It is the same as:

while(isempty(counter[4])
   delay(1)
endwhile

Link to comment
Share on other sites

Thanks again,

I changed the code to this (Speedleds):

waitfor(!isempty(counter[4]),1)
private speed = ((Counter[0]-Counter[4])*0.1659)
while (1)
   LRed = (speed >= 99) && (speed <= 101)
   LGreen = (speed >= 59) && (speed <= 61)
   delay(0.5)
endwhile

The last addition made the error message disappear, but the initial problem, that the sequence does not turn the led channels on/off when the speed reaches any of the defined ranges still remains.

The led channels (Dig out) are named to LRed and LGreen (do Timing and Offset values have any significance in this case?), and you can switch them on/off manually by either using the command line or a sequence (eg. LRed =1), but the above sequence does not seem to be able to do that.

If the Speedleds sequence is running in the background (leds off) and you then run another sequence, that just turns them on, the Speedleds sequence then turns both off, no matter what the speed is.

Would it be possible to try some other alternative approach to switching on the leds (they are quite important for this application)?

Jari V

Link to comment
Share on other sites

Actually, I think your problem is that the variable "speed" is not actually calculating to what you think it is and so the if statements are always out of range. I tested this exact code using simulated data and it worked fine. What I'd do is put a print statement in there so you can debug:

waitfor(!isempty(counter[4]),1)
private speed = ((Counter[0]-Counter[4])*0.1659)
while (1)
   ? speed
   LRed = (speed >= 99) && (speed <= 101)
   LGreen = (speed >= 59) && (speed <= 61)
   delay(0.5)
endwhile

or just use the integrated debugger. Anyhow, the "? speed" will print the value of speed to the command/alert window. I think you'll find that it never goes inside the right ranges and thus the reason the LEDs get turned off.

Link to comment
Share on other sites

Thanks,

You were correct. When running the sequence with "? speed" added, the command line displays a constant value, that does not change when the speed is changed. The value depends on the current speed at that moment, when the sequence is turned on.

I also have a virtual channel with the same code:

(Counter[0]-Counter[4])*0.1659

This shows the changing speed correctly.

Jari V

Link to comment
Share on other sites

OK, sorry, I think my brain stopped working there for a bit :) The calculation needs to be inside the while loop!

waitfor(!isempty(counter[4]),1)
private speed
while (1)
   speed = ((Counter[0]-Counter[4])*0.1659)
   LRed = (speed >= 99) && (speed <= 101)
   LGreen = (speed >= 59) && (speed <= 61)
   delay(0.5)
endwhile

Otherwise it only gets calced once at start of the sequence.

Link to comment
Share on other sites

  • 1 month later...

Hi again,

I've managed to get the system sort-of running. Now there is a sequence controlling one braking measurement event, and at the end of one braking measurement there is a window displaying a frozen decel/speed/brake force graph and calculated deceleration and other test values (placed in virtual channels by the sequence).

This is almost good enough for single measurements - after a test, user has to go to the laptop, and save the displayed window as a pdf-file using a manually entered name.

The challenge now is brake-fading tests. In these, the bike is accelerated to a given speed, then braked to halt, then accerated/braked again, alltogether 10 times, and all this should be done continuously.

I was wondering if it would be somehow possible to automatically create pdf-files (using a pdf-printer) after each test so, that they would be automatically named, for example as <v.CustomerName>_<Timestamp>.pdf?

Ideally this could be triggered using a switch in the remote control box attached in the handle.

Thanks in advance,

Jari V.

Link to comment
Share on other sites

Well, there is an undocumented function for generating PDFs in the latest releases of DAQFactory. If you are using 5.4, you can upgrade a regular version of DAQFactory from www.azeotech.com, or Express at www.daqexpress.com. Its not documented because it only works with some of the screen components, and hasn't really been polished up for release. It was created on customer request and since has no effect on the rest of DAQFactory, was left in so the customer could stay on the DF release path. The customer has been using it quite a while with great success. So, you are welcome to use it as long as you understand that it is not completely polished or tested so you may have to play with your pages to get it to print right, and that the function prototype / way it works may change as we improve the function for release. We also won't be able to provide any real support for it at this point other than what I describe here:

The function prototype is:

page.printpdf(string pagelist, string filename, xres, yres)

pagelist is a comma delimited list of pages to print. If you aren't overlaying pages, then just put a single page name in quotes. Filename is the full path to the output file. Make sure and include .pdf. xres and yres are not used, but you have to pass in a number or the function will fail. This function creates uncompressed pdf files and is known to work with the graph component, table component and text components. Any other components (such as gauges, symbols, etc) probably won't work, but we've never tried. Also, some graph elements might not work.

For your particular use, you also need to construct the filename. To create a filename based on date, use the formatdatetime() function:

page.printpdf("Page_1","myfile_"+formatdatetime("%y%m%d",systime()) + ".pdf",0,0)

See the help on formatdatetime() (in the expressions chapter, under expression reference) for the description of the qualifiers (i.e. %y, %m, etc).

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.