Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - garysdickinson

Pages: 1 2 [3] 4 5 ... 34
31
Technical support / Re: Handling more than 1000 #Define entries
« on: March 06, 2021, 03:42:22 PM »
Nathanael,

You have figured out about the same solution to handling arrays of structures in TBASIC as I did.  So I may not be able to reduce the number of define table entries that you desire.

My approach is slightly different. This is an exert from the #Define table for a single structure. My application has an array of 8 of these structures


Code: [Select]
#   #Define Name        Value
45  FillerArrayBase     1
46  FillerArraySize     10
47  FillerStatus        DM32[y+0]
48  FillerCapacity      DM32[y+1]
49  FillerVolume        DM32[y+2]
50  FillerUllage        DM32[y+3]
51  FillerDvDt          DM32[y+4]
52  FillerTtlDvDt       DM32[y+5]
53  FillerBOL           DM32[y+6]
54  FillerDeliveryVol   DM32[y+7]
55  Delivered           DM32[y+8]
56  FillerReserved09    DM32[y+9]

FillerArrayBase is the index into DM32[] for the first entry of the first data structure.
FillerArraySize is the size of the data structure in 32-bit words.
There are 8 of these structures in the array. The maximum number of structures is defined as MaxFillerN. This allows me to change the size
of the array without having to change any of the CFs that act on the array of structures (there are no hard-coded values in my code for this sort of thing).
 
What I do differently that you is the computation of the index into DM32[] to access a individual member of a structure. I compute the index to the the first member
of the structure that I am interested in and assign this to the variable "y".  This keeps me from making simple mistakes in my coding that will be hard to find during debug.

The variable "y" is set to the starting address of of the "current" data structure once on each loop through the for..next structure.

Code: [Select]
' UpdateStatus - Now that all of the tank measurements have been made, 
'   this function will update the filler status information for each filler.
'
for FillerIndex = 0 to MaxFillerN       ' for each fill point
    ' The variable, "y", is the index into the array of data structures that
    '   represent the state of an individual filler.
    '
    y = FillerArrayBase + FillerIndex * FillerArraySize
   
    ' a mountain of code was deleted out of this function. The missing code
    '   assigned values to the XXXXTemp variables based on the state of 16
    '   fuel tanks that may be connected to the system. the XXXXTemp variables
    '   are defined as locations in DM32[] with the #Define mechanism.
    '
    FillerStatus    = StatusTemp
    FillerVolume    = VolumeTemp
    FillerUllage    = UllageTemp
    FillerDvDt      = DvDtTemp
    FillerTtlDvDt   = TotalizerDvDtTemp
    FillerCapacity  = CapacityTemp

next    ' FillerIndex (next filler)

OK. What might I suggest that you do to cut down on the number of #Define entries?  It sort of depends on how you have structured your program.

If you have 5 different recipes, do you save all five in the EEP?  As you appear to be using a Fx or Tile-based PLC you may have as much as 11K 16-bit words of EEP that you can store the recipes. If this is true, then you only need to access the current active recipe. You could copy the active recipe into a fixed location in DM32[] or you could access the EEP for the active recipe directly.  Load_EEP32[(y+n)] ... where y is that stating index into EEP32 for the active structure and n is the offset within the array.

Another thing that you could do to simplify your life is to store all of the data in the same place. I notice that you have some 32-bit float values and some 32-bit integer values. If you have only a few float values you could:

1. Convert them to scaled integers and save them in DM32[]. Lets say that the float value is 32.467 and your system only needs the number to be accurate to +/-0.1 then save the float      DM32[n] = round(32.467,1) * 10    This is a scaled integer. When you need to use it covert it to what ever units your system actually uses.
2. Save the float value DM32 as a bit pattern.  DM32[n] = Float2Bits(32.467).  When you need to use the value as a float convert it back   BitsFloat(DM32[n]).

By not having to split your recipes between DM32[] and FP[] might make your life a bit simpler(???).

Oh, and you can delete all uses of "THEN" from your if..else statements. "THEN" is purely optional and is purely useless.  Won't save you any execution time or reduce the number of #defines but it might make your .PC7 files a few bytes smaller.

Best regards,

Gary Dickinson

32
Technical support / Re: Handling more than 1000 #Define entries
« on: March 06, 2021, 10:46:00 AM »
Nathanal,

I am not an expert on JSON, but I do have a method for making DMxx[] look like an array of data structures and not just a simple array of numeric values.

The approach that I have taken does use the #Define mechanism but does not need as many #Define entries as you are using.  I only use a #Define for each structure member, and the total size of the data structure.

If you are interested, I can post bits of my PLC code and #Define tables at some explanation for how I use the approach.  I have been using this approach for 10+ years, but have not posted it on the forum.

Best regards,

Gary Dickinson

33
Technical support / Re: Interfacing Thermistors to TRI PLCs
« on: October 14, 2020, 02:54:37 PM »
This message has the .zip version of my spreadsheet.

Gary Dickinson

34
Technical support / Interfacing Thermistors to TRI PLCs
« on: October 14, 2020, 02:50:25 PM »
I am working on a PLC project that needed to use Thermistors for temperature measurements.  This is not a new topic, but for my current application I decided to see if I could do this without the traditional lookup table and linear interpolation algorithms.

My application did not only required accuracy over a range or 30 or 40 degrees C. 

I was able to get the math for converting ADC counts to temperature to a single equation for my application:
 
      y# = x * 2.1095E-2 - 3.3485E+1         

No lookup tables.

So I am sharing how I got to this sort of solution. Perhaps, it would be useful to others.

I have attached the documentation to this message. I will post the Excel spreadsheet on the next message in this thread.

Gary Dickinson

35
Technical support / Re: Unwanted Stepper motor movement
« on: September 14, 2020, 11:48:27 AM »
Neal,

Glad that you found a simple solution.

I find that most of the documentation (if any) for devices is wrong. I reverse engineer the I/O circuitry of most devices. With Modbus devices, I have to run test software to figure out how stuff works.

I  have run into a few rare exceptions.  I have worked with Modbus devices from both a Finnish and Swiss company that were actually document correctly.  And they had technical support that could help with application issues!

Best regards,

Gary d

36
Technical support / Re: Unwanted Stepper motor movement
« on: September 13, 2020, 09:11:41 PM »
Neal,

The video answers a lot of questions that I was going to ask.  The dial test indicator answered the first 4 or 5 questions.

Your indicator moved a couple of marks. I am guessing about 0.002". I see a lead screw driving a carriage and assume that it is directly coupled to a stepper motor (no intermediate gear box). The most common steppers move 1.8 degrees per full step.  I don't know the pitch of your lead screw, but 5 mm per turn is common. Each full step for a 1.8 degree stepper would move the carriage about 0.025 mm (or about 0.001").  So I am guessing that your stepper is not getting too many step pulses.

My initial guess is that it is not noise on the output of the FMD8810. If you have a stray bit of wire that bridges the PLC outputs, then you can create a "wired-or" condition. If either adjacent output goes active then both will.  I'm done this both with intent and by mistake.  This might get you the behavior shown in the video.

You could put a red LED in series with the step signal heading to the stepper driver.  This is the poor man's alternative to the scope. If it flashes when the stepper shouldn't be moving then you have learned something without having to find the scope probes.

I would instrument the PLC code to generate an output that goes active when the PLC firmware issues a stepper movement command and goes inactive when the command completes. If this new OUTPUT goes active when the carriage jerks, then your firmware issued a stepper movement command. If the new OUTPUT is inactive when the carriage jerks then it is probably not firmware. Sync the scope to that signal and you can go hunting.

What are you using for a stepper driver? I have been using Chinese stepper drivers based on the TB6600 chip. They were inexpensive and I could find schematics to verify the input circuitry.  Most of these drivers were designed to be connected to small computers with 0..5V logic. I added an external resistor in series with each PLC OUTPUT to limit the current to 10 mA as I was working with 0..24V logic (PLC).

Gary





37
Technical support / Re: Unwanted Stepper motor movement
« on: September 12, 2020, 03:59:23 PM »
Neal,

I am running 2 stepper motors from an Fx series PLC.  I have not run into the problem that you are seeing.  The attached photo is my stepper controlled valve test bed. You can see the steppers, the belt driven cams, the limit switches, drivers and big 24 VDC supply for the steppers.  The rest of the test system is a couple meters distant.

Stepper systems are not as easy as they appear.  The bis issues are torque and inertia.  If your stepper doesn’t have enough torque to accelerate the load, you will lose steps on acceleration.  You may gain steps on the de-cel if the inertia of your system is so great that it overrides the holding torque of the stepper. I had a client that when the stepper coasted past the last step that the high voltage generated by the stepper (acting as an alternator) would destroy the driver circuitry.  I destroyed both of his prototypes in less than one minute.  I was unable to convince him that his prototypes would need a bit more development before they were ready to ship..

Most SSRs are optically isolated.  The PLC's view of an SSR is an LED with a series resistor (to limit current) connected to +24 VDC.  There is nothing inductive about the SSR's input structure. There is no need for additional circuitry.  I don’t think this is your problem.

If you have access to a modern oscilloscope, it is probably time to get it out.  If you can modify your PLC firmware to set an OUTPUT bit when your firmware issues a stepper move command and then clears this OUTPUT on completion of the move command. Look carefully at what this output does.  It is very possible that your firmware is buggy and actually responsible for the unwanted stepper movement.

Now that you have a way to trigger the 'scope you can study the PLC stepper signals on the 2nd channel.

Stepper systems are not as easy as they appear.  The bis issues are torque and inertia.  If your stepper doesn’t have enough torque to accelerate the load, you will lose steps on acceleration.  You may gain steps on the de-cel if the inertia of your system is so great that it overrides the holding torque of the stepper. I had a client that when the stepper coasted past the last step that the high voltage generated by the stepper (acting as an alternator) would destroy the driver circuitry.  I destroyed both of his prototypes in less than one minute.  I was unable to convince him that his prototypes would need a bit more development before they were ready to ship.

If the problem is not firmware and not physics (torque and inertia) then I would look carefully at how you have handled power and ground wiring.  I would worry about how you have wired both the SSRs and the stepper driver to ensure that they are all correctly referenced to the PLC +24VDC supply.

I am happy to help you sort this stuff.  You can contact me via my email address in my profile.  I am sure that your problem is simple.  I am sure that I can can help you stare at it just differently enough to figure out the problem.

Gary d


38
Technical support / Re: Integer Stack Overflow
« on: August 19, 2020, 09:22:05 PM »
Nathanael,

I can’t answer your main question with any authority.  I think that if breaking the calculation into multiple statements gets you the correct answer without crashing TBasic you are pointing at a problemS ( or limitations) with the arithmetic expression parsing.

My guess is that the run time arithmetic expression evaluation is coded  using a recursive descent algorithm.  Most of these algorithms are stack based.  Intermittent values and return addresses get pushed onto a stack.  The use of parentheses to force evaluation order will result in things being pushed onto a stack. You may have written code that exceeds size of this stack structure.  I have broken tBASIC many times, however, your issue is new to me.

The TRI people will get you the correct answer.

I can answer your question about runtime exceptions. The short answer is No.  There is no documented way to access any information about a runtime error. The information is only available if you have a LCD plugged into the PLC and you are staring at the PLC OR if you are running online monitoring when the error occurs.

The error messages are stored in a buffer on the PLC and are accessible via the TRI host link protocol.  However, the host link commands are not documented.  The buffer is not accessible from tBASIC.

Runtime errors, normally halt the execution of the ladder logic.  You can set up a CF to act as an exception handler. If this is done the designated CF is called rather than halting execution.

Because you can’t access the LCD buffer memory in the CF, it is not possible for a user written exception handler to "know" what exception was caught.  I use the run time exception handler to reboot the PLC as there is nothing else that it can do.  It allows the PLC to restart without having to physically cycle the power.

I use the PLC watch dog timer in the same manner as the exception handler.  I just reboot the PLC.

I have explained these issues with TRI and suggested ideas on how and why to provide access to the runtime errors, but have been unsuccessful in persuading them to add this capability.  Perhaps you will be more persuasive.

Best regards,

Gary Dickinson



39
Technical support / Re: RS485 Baud Rate Between Nano-10 and Fx1616-BA
« on: June 06, 2020, 12:07:09 PM »
If you are using serial ports or Ethernet to interconnect PLCs you will find that the latencies from on PLC to another are partly do to data transfer rates.  Your measurement latencies at 3 different BAUD rates gives you a big hint.

Your BAUD rate range is roughly 1:3 but your measured latencies are only about 1:1.4.  Most of your latency is NOT due to communication speed.

Ok.  Where does the rest of the time get eaten up?
  • The TRI low level firmware handling of Modbus.  This code is actually pretty fast.  There are a few things that you can change that affects the RS485 driver turnaround delay.
  • Ladder logic scan rate. If you are setting an OUTPUT on the slave PLC, that OUTPUT will not change until the end of the ladder logic scan.

To minimize latencies you will need to to ensure that your ladder logic scan rate is FAST. These are settings that you can change to maximize the scan rate:
  • SetSystem 3,0  RS485 communications are 1/2 duplex.  The default behavior of the PLC when responding to an communication from a RS485 port is to delay for 10 ms to allow the master device to quit driving the communication bus before the PLC turns on its drivers and responds as a Modbus slave.
     
    This behavior fixes a problem with dumb USB to RS485 dongles and RS232 to RS485 gizmos.  Those devices have no knowledge of the communication protocol. As a result those devices just will keep driving the RS485 bus after the end of the Modbus query and no new characters arrive to be transmitted.  This can be many ms.

    You are not using these sorts of dumb devices.  The SetSystem 3,0 statement cuts the turn around delay from 10 ms to as close to 0 as possible add this SetSystem statement to every PLC that is on the RS485 cabling.
  • SetSysetm 16,1  for Nano-10s. This statement "tells" the PLC how many digital I/O lines are active.  Your Nano-10s only have 4 sets of I/O lines, but the PLC firmware will still scan 128 inputs at the start of the ladder logic scan and then update 128 outputs at the end of the ladder logic.  Using this SetSystem statement will save measurable time on the Nano-10s.
  • SetSystem 16,n. Fx series PLCs.  If you are only using 16 digital I/Os use SetSystem 16,1.  If you are using 32 or less digital I/Os then SetSystem 16,2 is the right answer.

Rerun your latency tests at a single BAUD rate. Add the SetSystem statements one by one and rerun the tests.  You will see reductions in latencies.  And it’s good science...

Gary Dickinson

p.s.  I attached a PDF of a bit of PLC code that you should add to your test PLCs. This code will allow you to directly measure the PLC scan rate with the test equipment that you already have.

40
Technical support / Re: How to communicate with server (Nano10)
« on: April 03, 2020, 12:36:00 PM »
The Nano-10 has built in support as a slave device via Modbus TCP/IP.  This is an industry standard communication protocol.  A server can access the PLCs, INPUTs, OUTPUTS, RELAYS, DM[], DM32[] and several other PLC internals.

This is how most HMI devices interact with PLCs.  This is how remote data logging is done with PLCs.

Modbus TCP/IP requires little or no software support in the .pc6 program for the Nano. If your server can act as a Modbus TCP/IP server then most of the programming is on the server end.

This is not the only approach that you can use, but it is my favorite. 

Gary Dickinson

41
Technical support / Re: People Counter
« on: March 16, 2020, 10:40:15 PM »
Lorne,

In trying to explain how the counting mechanism worked, I realized that my algorithm was not as robust as it could be.

So I modified the code and attached it to this post as V3.

Please look at the state machine diagram in an earlier post: http://triplc.com/smf/index.php?action=dlattach;topic=2429.0;attach=235  as reference.


The idea of the new code is to ensure that the state machine went through all 4 states before updating the count of "people".  I used the #define mechanism to carve out two 32 bit variables:
  • TicCnt - count of the number of states from state 0. This value increments when going clockwise else it decrements
  • TotalCnt - running count of "people"

This is the the "new V3" version of the NextSate CF:
Code: [Select]
' NextState - This CF is called on each new state that is to the "right" of
' The previous state. Think of this as going clockwise through the states.
'
' 0-->1-->2-->3-->0-->1-->2-->3-->0 ...
'
'
' On entry: StateCntr has been updated and represents the current state
'
' On exit:
'
' RELAY[2] is updated the patterns for the next legal states
'
' TicCnt will be updated
' TotalCnt may be incremented
'
RELAY[2] = DM[StateTableBase + CtrPV[StateCntr]]
TicCnt = TicCnt + 1 ' we have advanced clockwise one state

' If the current state is 0. Check to see it we should increment
' the TotalCnt value.
'
If CtrPV[StateCntr] = 0

if TicCnt = 4
TotalCnt = TotalCnt + 1 ' We have gone one full turn
endif

' The TicCnt is reset on transitions to state #0
'
' This makes it easy to "know" when to increment the TotalCnt value.
'
' The other issue is that the PLC scan rate must be significantly faster than
' the objects being counted. As there are 4 states the scan ran has to be
' about 8x faster in order to keep up.
'
TicCnt = 0

endif

The PreviousState CF is substantially similar and deals with the counter-clockwise case.

This is a 1x decoder that only counts once each time the state machine goes full circle.  There are 2x and 4x encoders that count 2x or 4x for complete loops through the state machine.

Best regards,

Gary Dickinson

42
Technical support / Re: ADC not being read
« on: February 29, 2020, 09:54:36 PM »
This is a screen shot showing the on-line debugger running in i-TRiLOGI Version 6.6 build 04.  The PLC is a Nano-10.

ADC(1) and ADC(2) are being accessed, periodically, as part of the PLC program. The ADC inputs are about 3.71 and 4.07 VDC relative to the analog ground reference. 

Note the non-zero values for ADC 1 and 2 on the screen shot. 

I suggest that you disconnect anything that you may have connected connected to your PLC (ADC) inputs. Now jumper the +5V analog reference voltage to one of the ADC inputs. This is the reference voltage used by the PLC ADCs and this voltage should result in the ADC measuring the full scale value of 4095 counts.

As noted by TRI support the PLC must be executing a PLC program that periodically "reads" the ADC values.  Otherwise, the registers accessed by the on-line debugger will return a value of zero.

Another reason that you may get a zero reading is that voltage measurement is relative to the AGND input.  If you try to measure the voltage of a D cell battery, connecting only the + end of the battery to ADC 1 will get you a zero reading.  You must connect the - end of the D cell to the AGND, also.


Gary D

43
Technical support / Re: People Counter
« on: February 18, 2020, 01:58:20 PM »
Lorne,

I couldn't sleep the other night and kept thinking that a quadrature decoder could be done with even less code. I got it down to 3 rungs of ladder logic and 3 tiny custom functions.

This is a state machine based approach.  There are no edge triggered events. I use a ladder logic COUNTER to manage the state tracking and a table of data in DM[] that is used to determine when to change state.

Lorne found a bug in the state transition table.  I have corrected this mistake and attached a new version of the .pc6 file.

Best regards,

Gary Dickinson

44
Technical support / Re: People Counter
« on: February 14, 2020, 09:44:55 PM »
Lorne,

Nice post. It made me have to do some thinking.

I decided to simplify your code a bit and demo how to use PLC COUNTERs to keep track of the running count. It isn't that hard, but it doesn't handle negative numbers.

The high-speed counter mechanism is probably a better approach than ladder logic for most applications. The biggest limitation is the PLC ladder logic scan rate needs to be significantly faster the rate that the A and B inputs change state.

Best Regards,

Gary Dickinosn

45
Technical support / Re: 16 BIT TO 32 BIT
« on: January 23, 2020, 03:10:14 PM »
Lorne,

I can think of 3 reasonable approaches:
  • Use the SetHigh statement to build a 32 bit variable in A:
    A = RELAY[2]
    SETHIGH16 A,RELAY[1]
  • Build a 32 bit variable in A
    A=RELAY[1] * &h10000            ‘ shift left 16 bits
    A=A | (RELAY[2] | &h0000ffff)   ‘ OR in least significant 16 bits
  • Take advantage of the fact that the DM memory can be accessed as both 16 bit and 32 bit values.  In "C-like" programming languages this is an example of a "union" data structure. This code will build a 32-bit value in DM32[1]:
    DM[1]=RELAY[1]
    DM[2]=RELAY[2]
Try them in the simulator. Pay close attention to where the bits from RELAY[1] and RELAY[2] end up in the 32 bit value.  Set the most significant bit of each group of relays and verify that you get the correct pattern in the 32-bit variable.

Gary Dickinson

Pages: 1 2 [3] 4 5 ... 34