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 ... 33
16
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





17
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


18
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



19
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.

20
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

21
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

22
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

23
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

24
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

25
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

26
Technical support / Re: Test Bit for greater than or Less than
« on: January 14, 2020, 02:37:08 PM »
Lorne,

Your ladder logic code is much better than my version.  It is much simpler and solves the problem very directly.  I am very impressed!

I will try and explain how my TBASIC program operates.  TBASIC supports three types of operators:
  • Arithmetic Operators: +, -, *,/ and MOD.  The first 4 show up on calculators. MOD is the remainder from integer division and is what was taught in elementary school (10 divided by 3 is 3 remainder 1).
  • Bitwise Boolean Operators: &, |, ^, and ~ ( bitwise AND, bitwise OR, bitwise Exclusive OR and bitwise NOT)
  • Relational Operators: =, <>, ... AND, OR

I will explain the use of Bitwise Boolean operators in my program line by line.
N = RELAY[1] & &h00ff   ' isolate bits 0..7

RELAY[1] is a 16-bit value that represents the the state of Relays 1..16.   If Relay #3 and Relay #16 is ON and the other 14 relays are OFF, then the value of RELAY[1] would have a decimal value of -32764 or &h8004.  But all arithmetic in TBASIC is done with 32-bit signed arithmetic the Value of RELAY[2] will be sign-extended to a 32-bit value.  I only care about the lower 8-bits of the value so I will use the bitwise Boolean & (and) operator to clear all but the least significant 8 bits of the value.

Look at the last two lines in the table to see the effect of the Bitwise Boolean & (AND) operator.

Comment                 Decimal    HexadecimalBinary
RELAY[1] as 16-bit-3276480041000 0000 0000 0100
RELAY[1] as 32-bit-32764FFFF80041111 1111 1111 1111 1000 0000 0000 0100
&h00ff value255000000FF0000 0000 0000 0000 0000 0000 1111 1111
RELAY[1] & &h00ff4000000040000 0000 0000 0000 0000 0000 0000 0100

This line of code is an assignment statement.  The variable, N, will be assigned the value that results from the Bitwise Boolean & (AND) operator.
N = RELAY[1] & &h00ff   ' isolate bits 0..7

The next line of code generates a map of all of the bits that are less than the single bit set in RELAY[1] and assigns this value to "L":

L = N - 1            ' low mask (bits less than single bit in N)

Comment                 Decimal    HexadecimalBinary
N400000040000 0000 0000 0000 0000 0000 0000 0100
N-13000000030000 0000 0000 0000 0000 0000 0000 0011

The line of code:
L = N - 1            ' low mask (bits less than single bit in N)
doesn't use any binary operators, just old school subtraction.  The reason that subtracting 1 from N gets a bit map is because of the fact that that only possible values of N are 1,2,4,8,16,32,64 and 128. Those values have only a single 1 set in their binary representations.  128 in binary is 10000000 subtracting 1 from 128 will get you 127 or 01111111 binary (lots of carries).

Table that shows the bit map off all of the bits less than N for all possible values of N:
Comment                 Decimal    HexadecimalBinary
N=1, L0000000000000 0000 0000 0000 0000 0000 0000 0000
N=2, L1000000010000 0000 0000 0000 0000 0000 0000 0001
N=4, L3000000030000 0000 0000 0000 0000 0000 0000 0011
N=8, L7000000070000 0000 0000 0000 0000 0000 0000 0111
N=16, L150000000F0000 0000 0000 0000 0000 0000 0000 1111
N=32, L310000001F0000 0000 0000 0000 0000 0000 0001 1111
N=64, L630000003F0000 0000 0000 0000 0000 0000 0011 1111
N=128, L1270000007F0000 0000 0000 0000 0000 0000 0111 1111

The next line of code is:
H = &hff ^ (L | N)      ' high mask (bits greater than single bit in N)
That line of code generates the mask for the bits that are greater than then single bit in N (RELaY[1]). This line of code uses 2 bitwise Boolean operators, "|" (XOR) and "^" (exclusive OR).

The Boolean OR operator looks at 2 bits and if either bit is a "1" the output will be a "1".  TBASIC's bitwise Boolean OR, "|", works with two 32-bit values and on a bit-by-bit basis to create a new 32-bit value.

Exclusive OR (XOR) is a Boolean operator that is used to compare two bits. If the bits have different values then the output is a "1". If the two bits have the same value (both 0s or 1s) then the outputs is a "0".

TBASIC supports a bitwise Boolean XOR, "^". Bitwise means that it works with two 32-bit input values and outputs a new 32-bit value based on a bit by bit comparison.

At this point in the program we have N and L.  L is a bit map of all of the bits less than the value of N. What we need to do is compute the bit map for all of the bits that are greater than N. 

This bit of code is evaluated first as it group in parenthesis:
(L | N)
The bitwise Boolean "|" create a new value that is a bit wise OR of L and N.  This value is the pattern of all of the bits that are less than N and equal to N. This is value is actually all the bits that we don't want.  The bitwise XOR comes to the rescue by allowing us to sort of subtract out the bits we don't want to generate the mask of bits greater than N.

H = &hff ^ (L | N)

&hff is a constant that represents all possible bits in an 8-bit value. The "^" operator will remove the result from the  (L | N) expression from the &hff constant. The result will be assigned to H as a map of all of the bits greater than N.

All of the possible values of H:
Comment                 Decimal    HexadecimalBinary
N=1, H254000000FE0000 0000 0000 0000 0000 0000 1111 1110
N=2, H252000000FC0000 0000 0000 0000 0000 0000 1111 1100
N=4, H248000000F80000 0000 0000 0000 0000 0000 1111 1000
N=8, H240000000F00000 0000 0000 0000 0000 0000 1111 0000
N=16, HE0000000E00000 0000 0000 0000 0000 0000 1110 0000
N=32, HC0000000C00000 0000 0000 0000 0000 0000 1100 0000
N=64, H128000000800000 0000 0000 0000 0000 0000 1000 0000
N=128, H0000000000000 0000 0000 0000 0000 0000 0000 0000

Now that the high and low bit maps have been calculated, it is pretty easy to look for bits in RELAY[2] that are less than and greater than the value in N.

if RELAY[2] & L
   SetIO LowFlg
else
   ClrIO LowFlg
endif

The bitwise Boolean operator "&" (AND) is used to determine if any bits in RELAY[2] are set at the bit positions determined by L. The result of the & operation will be either 0 or something non-zero. If any bits are set in RELAY[2] that correspond to bits in the L map the result will be non-zero and the SetIO LowFlag statement will execute.

I'm sorry that the length of the explanation.

Gary D

27
Technical support / Re: Test Bit for greater than or Less than
« on: January 13, 2020, 07:50:11 PM »
Lorne,

I thought about the ladder logic implementation.  I wrote 1/2 of the code that checks for bits in RELAY[2] that are less than the single bit in RELAY[1].

Why?  Just to see how hard it was to write.  I did manage to write more code on a single rung that the ladder logic can support so I broke the problem across two rungs.

I attached the code to this email.  The 1/2 that I wrote took 2 lines of ladder logic and a total of 50 ladder diagram words. Double that to get the complete program.

If your application requires this bit testing code to checked on every scan of the ladder logic, then I'd use the ladder logic rung rather than calling the CF solution.

Best regards,

Gary Dickinson

28
Technical support / Re: Test Bit for greater than or Less than
« on: January 10, 2020, 10:59:36 AM »
Thanks Lorne,

I like algorithms. Before I sent the reply I came up with some rather complicated ideas, also. I got balled up with numeric values and the idea of comparing values.

But the easier algorithm was to just figure out how to build bit maps base on the single bit in RELAY[1]. TBASIC supports a good set of Boolean operators which makes bit twiddling easy. 

The trick was that the less than map just needed a subtraction.  The bit map for greater than is easier, it's all the other bits that aren't in the less than map and the bit in RELAY[1] and this is just a bit of Boolean bit twiddling.

Gary d

29
Technical support / Re: Test Bit for greater than or Less than
« on: January 09, 2020, 10:39:35 PM »
    Lorne,

    This is not too difficult to do in TBASIC. It is a bit more complicated do do in ladder logic.

    This is the sort of code that I would suggest:

' SetFlgs - CF to test lower 8-bits or RELAY[1] against RELAY[2]
'
N = RELAY[1] & &h00ff   ' isolate bits 0..7
L = N - 1            ' low mask (bits less than single bit in N)
H = &hff ^ (L | N)      ' high mask (bits greater than single bit in N)

if RELAY[2] & L
   SetIO LowFlg
else
   ClrIO LowFlg
endif

if RELAY[2] & H
   SetIO HighFlg
else
   ClrIO HighFlg
endif


Comments on code:
  • L is map of the bits less that the single bit set in RELAY[1]
  • N is map of the bits greater than the single bit set in RELAY[1]
  • LoFlg is a RELAY that is set when there are bits in RELAY[2] that are less than the single bit in RELAY[1]
  • HighFlg is a RELAY that is set when there are bits in RELAY[2] that are set at positions greater than the single bit in RELAY[1]
Concerns about RELAY[1]
  • This code works if there is exactly one bit set in RELAY[1] bit positions 0..7
  • This code fails miserably if there are no bits set in RELAY[1] bit positions 0..7
  • This code fails in interesting ways if there is more than one bit set in RELAY[1] bit positions 0..7
  • If there is any chance that your rules about RELAY[1] may not be held sacred, then you need to add some code to test and verify that RELAY[1] meets the rules before you get to the code that sets/clears flags.

Best Regards,

Gary Dickinson[/list]

30
Technical support / Demo Program that uses the Stack
« on: January 07, 2020, 04:57:08 PM »
I attached a simple program that uses the stack mechanism.

The code shows a method to generate a string representation of a 32-bit signed value.  My version allows you to specify a field width and will right justify the value in a column width that you specify.

The demo code is similar in behavior to the TRI Str$(n,d) function.  The TRI version pads the converted value with leading zeros which are not very useful for my purposes.

The demo code is just that.  If I really want to right justify a 32-bit integer value in a fixed-width column I use code like this:

a$ = Str$(n) : a$ = mid$("                  ",1,d-len(a$)) + a$


I apologize for the fact that this code is 100% unreadable, it's just the best you can do in TBASIC.
 
Best regards,

Gary Dickinson

Pages: 1 [2] 3 4 ... 33