Jump to content
OMRON Forums

meindert.norg

Members
  • Posts

    39
  • Joined

  • Last visited

Everything posted by meindert.norg

  1. LS, Summary: Observation: Motor runs fast in opposite direction after hitting Positive end-switch. Cause: Configuration of "Overtravel Limit Use Bit" for motor #2 servo, which was used in series with #1 servo. Solution: Ignore Overtravel Limit switches for #2. Technical nitty gritty: When a motor hits an EndSwitch, moves in that direction are forbidden. When using 2 filters in series (#1 and #2), the #2 filter receives the #1FilterOutput through the #2MasterPosition input into its #2FollowingError. Positive changes to the #1FilterOutput are forbidden and ignored... ... but Negative changes to the #1FilterOutput are forwarded to the #2 Filter. In the presence of noise in #1FilterOutput, the result is a (fast) changing input in the negative direction for the #2 Filter... ...resulting in a large negative force on the motor... ... resulting in the motor moving away from the EndSwitch in an unexpected fast manner. Details: While testing Limit Switches (MLIM and PLIM) I noticed that everything worked according to expectation when using only one PID filter, but when using a second filter in series with the first filter, the motor would 'shoot back when hitting a Limit-Switch'. It is noteworthy to mention that I used manual switches for this test. The consequence is that if the motor moves away from the switch (as explained), the switch is not released as it would be if the switch was actually operated by the motor. In that case, the problem stated below is still true, but 'solves itself' automatically after the motor moves away from the switch. Still, the motor would experience an undesired jump in the opposite direction after hitting an End-Switch. I placed the filter from a #2 (unused motor) filter in series with the filter from my #1 motor, using the procedure from page 168 in the Turbo PMAC User Manual. This gave me to option to use both a low pass filter and a notch filter for my servo. In step 5 the procedure tell you to copy the Motor xx Flag Mode Control settings from the original motor (in my case #1) to the servo that is to be placed in series with the first motor (in my case #2). I used I124 = $800001: $1 = PMAC2 style. $80000 = Fault bit polarity This setting responds to EndSwitches by: Stopping the motor Ignoring any further positive commands, untill switch is released. When jogging in positive direction, and hitting the Positive Endswitch, the motor would immediate start running very fast in the opposite direction, as indicated in the measurement below. When zooming in to the event of hitting the EndSwitch, we observe that only negative (allowed) changes in the #1FilterOutput are forwarded to the #2FollowingError. This causes the #2filter to output an increasingly large negative value, making the motor accelerate in the negative direction. This problems is solved by ignoring the Endswitch flags for the second motor: #224 = $820001. regards, Meindert
  2. Hi Charles, During our phone conversation you mentioned that what really happens when the Master Position is used to calculate the Following Error FE is that per servo sample, each Master Position CHANGE is used to calculate FE. What does not happen is that (as the schematics above might make one believe) the Master Position (scaled with I107) is added to the FE. The fact that only changes propagate now gives a perfect explanation for my problem: When I106 (Master Position Enable) is switched on... ...the initial Master Position value (from my ECT) is ignored... ... and only consecutive changes to the Master Position propagate to the Following Error. That is exactly what I measured and showed in the plot above. I found an implementation that gives me the result I was looking for: I'm making sure the ECT contents that is linked to the Master Position is zero when I switch Master Position following on (I106=1). Then, I link the analog input to the Exponential Filter that feeds into the Master Position, and make sure the max rate of change is low enough: Disable I106 = 0 Point first element of ECT entry 3 (which is an Exponential-Filter) to ‘0’ (e.g. I8003 = $D035C0). Make sure to use $D in order not to change the "method". Then slow down max . rate of change for exp. filter (I8004) from $91 (=145) to $1: I8004 = $1 Then enable I106 = 1 Then point ECT entry 3 (I8003) to ECT result of entry 2 ($D03503): I8003 = $D03503, which was the original address. After delay reset max rate of change: I8004 = $91 Voila! Please let me know if my understanding of how Master Position is used is incorrect or if you find an easier way to do this. regards, Meindert
  3. Hi Charles, To respond to a few of your questions: I don't think it is a resolution issue, because my motor follows the analog input properly, IF I106 is set to 1. It does not follow if I106 is set to 0, as expected. I have the same behavior. After I106 is set to 1, the motor properly follows the analog input, it just does not take the initial ADC value into account AT THE MOMENT I106 is switched to 1.... I'm using entry 2 to copy the ADC result (which resides in Y-memory) into the table, because the exp.-filter (entry3) can not access Y-memory. It can only access X-memory, or earlier ECT results. Please correct me here if I'm making things more complex than they should. To be continued next week. regards, Meindert
  4. I103=$3501;Motor 1 Position Address I104=$3501;Motor 1 'Velocity' Address I105=$3506;Motor 1 Master Position Address I106=0;Motor 1 Master Follow Enable I107=3072;Motor 1 Master Scale Factor I108=96;Motor 1 Position Scale Factor I109=96;Motor 1 Velocity Scale Factor I8000=$78000;ECT Entry 0 I8001=$278005;ECT Entry 1 I8002=$C00C;ECT Entry 2 I8003=$D03503;ECT Entry 3 I8004=$91;ECT Entry 4 I8005=$200000;ECT Entry 5 I8006=$78018;ECT Entry 6 Or with more info: Encoder Table Definitions. Executed - Fri Mar 18 16:05:58 2011 Entry Address Y-Word Conversion Method ---------------------------------------------------- 1 Y:$ 3501 $078000 1/T extension of location $78000 2 Y:$ 3502 $278005 Unfiltered parallel pos of location Y:$78005 Y:$ 3503 $00C00C Width and Offset 3 Y:$ 3504 $D03503 Exponential filter from conv. encoder 4 ($C00C) Y:$ 3505 $000091 Maximum change in cts/cycle Y:$ 3506 $200000 Filter gain 4 Y:$ 3507 $078018 1/T extension of location $78018 5 Y:$ 3508 $078100 1/T extension of location $78100 6 Y:$ 3509 $078108 1/T extension of location $78108 7 Y:$ 350A $078110 1/T extension of location $78110 8 Y:$ 350B $078118 1/T extension of location $78118 FYI: I have motor 2 filter in series with motor 1 filter.
  5. Charles, Yes, tried that too, but did not get the effect I wanted. During out phone-call you mentioned that I should actually get the desired effect when doing what I'm doing, and that I actually should get a position jump when enabling I106 to 1 with I107 set to 1000 (actually, now we're getting more into details, I must be more correct and say that I107 = 3072). Well, I attached a measurement showing that I do not. This measurement shows what I'm doing: These are the steps I performed: t=0 sec: I106 = 0, analog input voltage (Vin) = 0 V t=3 sec: I106 = 1 t=5-7 sec: change Vin from 0 -> 6 and back to 0 V again. Notice the position (b) change from 0 -> 1.4e8 -> 0. This is approx +100 degrees. t=8 sec: I106 = 0 t=12 - 14 sec: I change Vin from 0 -> 3 V. t=17 sec: I106 = 1. Notice how the actual position does NOT change! t=18-24 sec: change Vin from 3 -> 6 -> 0 and back to 3 V again. Notice how the position now changes through the same 110 degrees, but shifted down. Does this explain what I'm observing? Is that according to your expectations? regards, Meindert
  6. Charles, Thanks for your answer. I'm afraid I did not explain clearly enough what my issue is. i don't think the %0 -> %100 command will work, because my motor is not moving at a specific speed, but is mostly moving around 0 following the value as indicated by the Master Position. Hence I don't think the FeedRate override will help here, but correct me if I'm wrong. First of all, I have no coordinate system defined, because I don't think my application asks for that. I'm running one motor, and the majority of the time all that motor is doing is stand still, while continually 'listening' to the Master Position setpoint. If that value changes (representing a desired change in motor position), the motor needs to follow that setpoint. So, the Master Position is not a velocity, it is a position. The problem arises when switching on Ix06, or changing Ix06 (thanks for the block diagram). Lets assume the situation where: the trajectory command = 0 the actual load position = 0 Ix06 = 0 Ix07 = 1000 the FE is zero and the ECT contents pointed to by Ix05 is 5. This 5 would be the same as 5 * (Ix07 = 1000) = 5000 cts. This 5000 cts is my desired position, as indicated by the earlier mentioned Analog Input signal. Problem: when I set Ix06 = 1, the motor does not move instantly. This is probably because the 5000 cts is compensated for somewhere else, with the result that FE does not change (and hence does not result in a motor move). The note: "Can be changed on the fly" indicates this. Question: how do I enable the Master Position feature so that the motor will end up at the location indicated by the analog input (at HW)? thanks, Meindert
  7. LS, The Clipper manual suggests: for the DAC (=PWM) Outputs Power Supply. My question: Are these +/-12 or +/-15 V used directly for the PWM H-bridge (and thus determine the maximal and minimal output voltage, and ultimately the servo-loop-gain) or does the Clipper have a 10 V regulator on board that limits the actual PWM output voltage to +/- 10 V? Thank you, Regards, Meindert
  8. LS, I have a question about what happens to a motor's setpoint when the master position is engaged (e.g. I106 is changed from 0 to 1). This is my configuration: 1 motor (#1) with encoder feedback ADC input connected to #1 master-position Master Pos Following off (I106=0) During startup, one of the first things that happens is motor-homing. During this phase, the ADC value for the master-position can be changing, but is ignored. After homing is complete, and the motor is moved to zero, the motor must start following the 'master position'. The ADC voltage represents the absolute motor-position, lets say 1V = 1 degree (with e.g. "Master Scale Factor" I107 = 1000), so with an ADC range of +- 10 V I have a range of +- 10 degrees. Numbers are just an example. My plan was to: Set "Master Scale Factor" (I107) to 0 Enable "Position Following Enable" (I106 = 1) Slowly increase "Master Scale Factor" (I107) from 0 to 1000 over e.g. 1 second. This way I could slowly 'pull' the motor towards the position as indicated with by the ADC voltage, and the ADC voltage would be allowed to change while doing this. However, when changing the "Master Scale Factor" (I107) or "Position Following Enable" (I106) the actual motor setpoint does not change (which in general is nice, because otherwise that would generate an step in setpoint, which is normally undesired), but is somehow offset with the master position value. My questions: What exactly is done with setpoints / master position values / offsets when I set I106 to 1 after I set I107 to 1000? In other words, where is the change in "Master Position"-value compensated for? And most importantly: what can I do to implement the desired behavior? Regards, Meindert Norg
  9. John, Thanks for your answer. I will definitely give this a try. Good luck with your telescopes. regards, Meindert
  10. LS, I was able to read Gathered data into Matlab using the ActiveX COM interface (supplied through the "Pcomm Server Pro 2 Library", as suggested by Charles in http://forums.deltatau.com/showthread.php?tid=354). The simplest code showing how to get data into Matlab is: hPcommServer = actxserver('PcommServer.PMacDevice'); hPmacDevice = hPcommServer.invoke('IPmacDevice'); results1 = hPmacDevice.Open(0); DataString = hPmacDevice.GetResponseEx(0,'list gather',1); The attached Matlab code includes error checking and data conversion that is required to generate the original values. regards, Meindert Norg DT_GatherData_v2_1.zip
  11. Sina, Thanks. Actually, I found that both the Master Position and the Commanded Position will 'go through' the [i]PID Velocity Feedforward Gain[/i] (Ixx32). Setting this parameter to match the [i]PID Derivative Gain[/i] (Ixx31) should result in a measurement as if one was measuring a PID controller that has the servo-error as input. I have not tried this yet though, because for now, Charles' suggestion to inject signals into the SinOutputDACBias works fine for me. Thanks, Meindert Norg
  12. Dear Serkan, Thanks for your suggestion. I implemented the random noise generator described on http://en.wikipedia.org/wiki/Linear_congruential_generator as: P907_Random_Value = ((P905_Random_Multiplier*P907_Random_Value) + P906_Random_Increment) % P908_Random_Modulus As mentioned on the Wiki, the generator-outcome strongly depends on the values of Modulus, Multiplier and Increment. For example with Modulus = 2^32, I only found combinations for the other parameters that would make the generator repeat itself every 256 samples or faster. The "Apple CarbonLib" settings do not show any repetition within 30.000 samples (that's how much memory I had left for gathering). P908_Random_Modulus = 2^(32)-1 P905_Random_Multiplier = 16807 P906_Random_Increment = 0 On my system, the cost of this code is approx. 21 usec (system: 80 MHz UMAC, at 6 kHz Servo interrupt, PLC0 with random generator running every servo-interrupt (I8 = 0). Taking out P906_Random_Increment from the equation reduces this by 6 usec. regards, Meindert Norg
  13. LS, Threat http://forums.deltatau.com/showthread.php?tid=407&pid=1457 speaks of injecting a sine-signals for identification purposes. In that threat, a PLC0 is used to calculate this sine signal on the fly. Does anyone have a method to calculate and inject a random signal (noise) instead of a sine-signal? Thanks. Meindert
  14. Sina / Charles, Thanks for your examples. They gave me a good head-start to get going with my Swept-Sine analysis. For the method of injecting a position signal into the servo-loop I ran into a limitation: by using the master position as injection point, the injected signal does not 'go through' the differentiator. The result is that the Kd (I131) can not be measured/estimated. Do you have a similar suggestion to inject a position signal that will go through the differentiator? Preferably a method that does not force me to 'open and close' the servo loop (like reconfiguring the ECT). I'd like to make this method an 'add-on' to an already existing and running servo-loop. Thank you.
  15. Hi, I also found a way to connect to the ActiveX COM-interface from Matlab. This is a short Matlab-code example to request the value of I130 from the controller: [code] % First connect to the Delta Tau COM server, which is implemented in % C:\WINDOWS\system32\PcommServer.exe. On my system, this executable is % started automatically when I call actxserver: hPcommServer = actxserver('PcommServer.PMacDevice'); % Create a handle to the custom interface: % This handle "hPmacDevice" will be the actual interfaces that is used to % make calls to the Delta Tau controller. hPmacDevice = hPcommServer.invoke('IPmacDevice'); % Open the interface to device 0. % From "PEWIN32PRO2", menu -> Terminal -> Select PMAC % opens a window with PMAC Devices. My UMAC is listed as number 00. results1 = hPmacDevice.Open(0); % Send a string and display its response, using GetResponseEx method: GetResponseExString = hPmacDevice.GetResponseEx(0,'I130',1) % Clean up: hPmacDevice.Close(0) hPmacDevice.delete clear hPcommServer; [/code] I attached the 'published' result of Matlab code with more explanation. I've not been able to successfully use gather related methods. I might be making the wrong calls (the PcommServer.pdf manual is somewhat unclear on what means what, and the examples don't get me any further either), or Matlab just does not like the Delta Tau COM implementation for those specific methods. I will update this post if I find out more. regards, Meindert
  16. LS, Where in the control loop is the TCOMP (Torque Compensation Table) added to the PID output? In my specific application, the controller output is allowed to clip (as set by Ix69), but the TCOMP still needs to be active, even if the PID output is 'clipped'. It would be great if the TCOMP ADD location (and of other compensations) can be added to the graphs on page 152 and 159 in the Turbo PMAC User Manual. Thanks. Meindert
  17. Amin, I don't know of any PLC commands that log directly into a text-file on a PC, but if you have access to Matlab, the following discussion might help: [url=http://forums.deltatau.com/showthread.php?tid=354]Executing moves and traces (gather data) from Matlab [/url]. If you have no access to Matlab, you can still stream this data to a terminal (e.g. [url=http://ttssh2.sourceforge.jp/]Tera Term[/url]) using a serial cable between your controller and the PC. Regards, Meindert
  18. Dear Sina, Thanks for your reply. I was indeed experiencing a disturbance while moving 'through position zero'. After shifting the complete TCOMP table with the value of the last entry the disturbance disappeared. Am I correct though that the result would be the same if, instead of shifting, I'd set I30 to 1, and then download the original TCOMP (unshifted) table? Thanks, Meindert
  19. LS, The Turbo PMAC/PMAC2 Software Reference, page 289 says about "DEFINE TCOMP": It seems to me that the last sentence should be: or even better: Am I seeing this correctly? regards, Meindert
  20. Charles. Thanks for your suggestion. I implemented this method, but have the following issues / worries: [list=1] [*]The original method, using LIST GATHER does not require any pre-defined variables, as this Indirect Addressing method does. This is nice, because it can always be used after a gather is executed. [*]Using LIST GATHER method at baudrate 38400 bps I measured a transfer rate of 1100 samples per second. Using Indirect Addressing, that dropped to 63 samples per second. Here are the main differences: [list] [*] LIST GATHER: 6 characters per sample. [list] [*] Send one request for data, and result is streaming to PC without any further request: 6 characters per sample. [/list] [*] Indirect Addressing: approx. 18 characters per sample. To get one 12 HEX word (2 samples) one needs to: [list] [*] Send one change of address: 'M4005=xxxxx': 11 characters per 2 samples. [*] Request contents of memory M4004 is pointing to: 'M4004': 5 characters [*] Read result in signed int format: up to 16 characters per 2 samples [*] Every write also returns the 'ACK' value. [/list] [*] Although this is only 3 times more data, the reading and writing (instead of reading a stream) results in a 17 x slower transfer of data. [/list] [/list] Anyway, here is the code I used to test this method. Thanks. Meindert [code] function [DATA,Time] = GatherDataIndirectAddressing(port_name) % % GatherDataIndirectAddressing - Reads GATHER data from a Delta Tau % controller through a serial port using Indirect Memory Addressing. % % [DATA,Time] = GatherDataIndirectAddressing(COM1') connects to the Delta Tau % controller through COM1. % It returns a vector DATA containing as many columns as parameters that % were traced, and the Time vector containing timestamps. % % Assumptions: % I1 = 1 % When CS handshaking is not used (I1 is 1 or 3), Turbo PMAC % disregards the state of the CS input and always sends the character % immediately. This mode permits Turbo PMAC to “output” messages, % values, and acknowledgments over the serial port even when there is % nothing connected, which can be valuable in stand-alone and % PLC-based applications where there are SENDS and CMDS statements in % the program. If these strings cannot be sent out the serial port, % they can back up, stopping program execution. % I3 = 2 % Turbo PMAC acknowledges receipt of a: % - valid -terminated command with an ; % - invalid command with a character. % Messages are sent as DATA [ DATA ... ] . (The final % is the acknowledgment of the host command; it does not get % sent with a message initiated from a PMAC program [SEND or CMD]). % This is probably the best setting for fast communications with a % host program without terminal display. % I54 = 12 % I54 controls the baud rate for communications on the main serial % port. Turbo PMAC uses I54 only at power-up/reset to set up the % frequency of the clocking circuit for the serial port. To change % the baud rate, it is necessary to change the value of I54, store % this value to non-volatile flash memory with the SAVE command, and % reset the card. At this time, Turbo PMAC will establish the new % baud rate. % % The following M-variable definitions are required: % Note that one can choose other M-variables, but that the definition of % M4005 has to change to point to the 'new' M4004 variable. % Also, where these variables are used, matlab-code has to change to access % the proper variables. % % M4002->X:$003120,0,24 % Start of gather buffer. % M4003->Y:$003120,0,24 % End of gather buffer. % M4004->D:$117E6 % Possible start of Gather buffer. Exact value is not important % because it will later be changed by this Matlab function by means % of M4005 % M-variable address definitions are in fixed locations in Turbo PMAC % memory, starting at $004000 (for M0) and ending at $005FFF (for % M8191). The X-register at each of these addresses holds the code % that determines the format of the M-variable; the Y-register holds % the address of the register being pointed to. By changing the % contents of this Y-register, you can change the address of the % register that this Mvariable points to. % M4005->Y:$004FA5,0,16 % Memory location of M4004: % 4000_HEX + 4005_DEC = % 4000_HEX + FA5_HEX = 4FA5 % % When this program errors and ends without properly closing the serial % port, it might be impossible to re-connect to the port the next time. The % following line of code will release the port and clear the port-object. % newobjs = instrfind;fclose(newobjs);clear newobjs; % % file : GatherDataIndirectAddressing.m % last changes : February 8nd, 2011 % author : M.L.Norg % used functions : - % version : 1.0 % notes : Changed GatherData.m to use IndirectAddressing as % suggested by CharlesP in: % http://forums.deltatau.com/showthread.php?tid=354 % % Connect and configure RS232 port % BaudRate I54 % 9600 8 % 14400 9 % 19200 10 % 38400 12 % 57600 13 % 76800 14 % Not available in Matlab % 115200 15 s = serial(port_name); s.BaudRate = 38400; s.InputBufferSize = 4096; s.FlowControl = 'none'; s.Terminator = 'CR'; s.Timeout = 1; s.ReadAsyncMode = 'continuous'; s.DataTerminalReady = 'off'; % Open port fopen(s); % How many signals are gathered? I5050str = RequestVariable(s,'I5050'); NumberOfSignalsI5050 = length((strfind(dec2bin(hex2dec(I5050str(2:end))),'1'))); I5051str = RequestVariable(s,'I5051'); NumberOfSignalsI5051 = length((strfind(dec2bin(hex2dec(I5051str(2:end))),'1'))); NumberOfSignals = NumberOfSignalsI5050 + NumberOfSignalsI5051; % Get I10 - Servo Interrupt Time % This parameter tells Turbo PMAC how much time there is between servo % interrupts (which is controlled by hardware circuitry), so that the % interpolation software knows how much time to increment each servo % interrupt. I10str = RequestVariable(s,'I10'); ServoInterruptTimeI10 = str2double(I10str); ServoSampleTime = ServoInterruptTimeI10 / 8388608e3; % Get I5049 - Gathering Downsampling Factor I5049str = RequestVariable(s,'I5049'); GatherDownSampling = str2double(I5049str); GatherSampleTime = ServoSampleTime * GatherDownSampling; % In case of an odd number of signals, the time-clock (sample number) is % added to the back of the measurement. % Calculate the number of 8Hex words per sample. % NumberOfSignals: 1 2 3 4 5 6 7 8 9 10 % NumberOf16HexWords: 1 1 2 2 3 3 4 4 5 5 % NumberOf6HexWordsPerSample: 2 2 4 4 6 6 8 8 10 10 NumberOf6HexWordsPerSample = ceil(NumberOfSignals/2)*2; % Get M4002 - Get Gather Start Address M4002str = RequestVariable(s,'M4002'); GatherStartAddress = str2double(M4002str); % Get M4003 - Get Gather End Address M4003str = RequestVariable(s,'M4003'); GatherEndAddress = str2double(M4003str); NumberOfSamples = ceil((GatherEndAddress - GatherStartAddress) / (NumberOf6HexWordsPerSample/2)); DATA = zeros(NumberOfSamples,NumberOf6HexWordsPerSample); % clear DATA tstart = clock; % Calculate how long Xfer takes. Counter6HexWords = 0; % Reset sample counter for Address2Read = GatherStartAddress : GatherEndAddress-1 % Change value of M4005, by which the location M4004 points to is % changed. HandShStr = SendString(s,['M4005=',num2str(Address2Read)]); % Request value of memory where M4004 points to: DataStr = RequestVariable(s,'M4004'); % Convert to Decimal DataNum = str2double(DataStr); % If value is smaller than zero, add 2^48, making it an unsigned int. if DataNum < 0, DataNum = DataNum + 2^48; end % Convert to 48 bit Hexadecimal word, so it can be broken down in its % upper 24 bits and lower 24 bits Word12Hex = dec2hex(DataNum,12); % Example of Word12Hex % 05E7E50026A0 % \ / % -----+---- % | % V % Word12Hex % % 05E7E50026A0 % \ /\ / % -+-- --+- % | | % | V % | Word6Hex % V % Word6Hex % % Keep count of 6Hex words (6Hex word = 1 sample of 1 signal) Counter6HexWords = Counter6HexWords + 1; % Calculate which Row needs to be filled RowNr = ceil(Counter6HexWords/NumberOf6HexWordsPerSample); % Calculate which Column needs to be filled % NOTE: first evaluate the RIGHT part of Word12Hex. ColumnNr = rem(Counter6HexWords-1,NumberOf6HexWordsPerSample)+1; DATA(RowNr,ColumnNr) = hex2dec(Word12Hex(7:12)); % Keep count of 8Hex words (8Hex word = 1 sample of 1 signal) Counter6HexWords = Counter6HexWords + 1; % Calculate which Column needs to be filled % NOTE: Now evaluate the LEFT part of Word12Hex. ColumnNr = rem(Counter6HexWords-1,NumberOf6HexWordsPerSample)+1; DATA(RowNr,ColumnNr) = hex2dec(Word12Hex(1:6)); end disp(['Read ',num2str(Counter6HexWords),' 42 bit words (= ',... num2str(2*Counter6HexWords),' samples) in ',... num2str(etime(clock,tstart)),' seconds. ',... num2str((2*Counter6HexWords)/etime(clock,tstart)),' [samples/sec].' ]); % convert from unsigned int into signed integer: % Check which numbers are larger than 2^23 and subtract 2^24 iFlip = DATA>2^23; DATA(iFlip) = DATA(iFlip) - 2^24; Time = [1:size(DATA,1)]' * GatherSampleTime; % clean up serial object fclose(s);delete(s);clear s; function [HandshakeString] = SendString(s,VarString) % This function sends a string without expecting a response other than % an ACK. fprintf(s,VarString); HandshakeString = ReadHandshake(s); function [ReturnString,HandshakeString] = RequestVariable(s,VarString) % This function sends a string and expects a return string. fprintf(s,VarString); ReturnString = fgetl(s); HandshakeString = ReadHandshake(s); function HandShakeString = ReadHandshake(s) % This function is called to read the handshake string or . HandShakeString = ''; % Make sure something is available to be read, but error when wait is % longer than 5 seconds. tStartWait = clock; while ~s.BytesAvailable; if etime(clock,tStartWait) > 5 % clean up serial object fclose(s);delete(s);clear s; error('Waited longer than 5 seconds for Handshake value.'); end end if s.BytesAvailable, clear ReturnValueStr; ReturnValueStr = fread(s,s.BytesAvailable); if (single(ReturnValueStr(1))==6) HandShakeString = 'ACK'; elseif (single(ReturnValueStr(1))==7) HandShakeString = 'BELL'; else HandShakeString = ReturnValueStr; warning(['Read handshake string: ''',HandShakeString,''' while expecting ''ACK'' or ''BELL''.']); end end [/code]
  21. This code reads the contents of a Gather buffer on my UMAC controller through an RS232 COM port. Before running this code, make sure there is measurement data available in the buffer. Again, let me know if there are any problems with running this code. Enjoy. Meindert Norg Updates: [list] [*]V1.0 Original version [*]V1.1 2011-02-08[attachment=1438:name] [list] [*]Added help info on I54. [*]Added Time to file. [/list] [*]V2.0 2011-02-10[attachment=1439:name] [list] [*]Added 48 INT signals conversion. [*]Tested I5051 Data Gathering Selection Mask 2. [*]Split "Read+Conversion" loop into "Read" loop and "Conversion" loop. [*]Used start- and stop-buffer location without the use of pre-defined M-variables[/list] [*]V2.1 2011-02-10[attachment=1440:name] [list] [*]Fixed SignalType pre-definition. [*]Fixed notification on 'incorrect 12HexWord' length. [/list] [*]v2.2 2011-02-11 [list]Checked for empty GATHER buffer. [/list] [*]v2.3 2011-02-24[attachment=1447:name] [list] [*]Changed name from GatherData.m to DT_GatherData_Serial.m and used DT_GatherData.m to implement ActiveX gathering function, which is more than 12 times faster and more robust. [/list] [/list] [code]function [Data,Time] = DT_GatherData_Serial(port_name) % DT_GatherData_Serial - Reads GATHER data from a Delta Tau controller % through a serial port. % % [Data,Time] = DT_GatherData_Serial('COM1') connects to the Delta Tau % controller through COM1. It returns a vector Data containing as many % columns as parameters that were traced, and the Time vector starting at % t=0; % % Assumptions: % I1 = 1 % When CS handshaking is not used (I1 is 1 or 3), Turbo PMAC % disregards the state of the CS input and always sends the character % immediately. This mode permits Turbo PMAC to “output” messages, % values, and acknowledgments over the serial port even when there is % nothing connected, which can be valuable in stand-alone and % PLC-based applications where there are SENDS and CMDS statements in % the program. If these strings cannot be sent out the serial port, % they can back up, stopping program execution. % I3 = 2 % Turbo PMAC acknowledges receipt of a: % - valid -terminated command with an ; % - invalid command with a character. % Messages are sent as DATA [ DATA ... ] . (The final % is the acknowledgment of the host command; it does not get % sent with a message initiated from a PMAC program [SEND or CMD]). % This is probably the best setting for fast communications with a % host program without terminal display. % I54 = 12 % I54 controls the baud rate for communications on the main serial % port. Turbo PMAC uses I54 only at power-up/reset to set up the % frequency of the clocking circuit for the serial port. To change % the baud rate, it is necessary to change the value of I54, store % this value to non-volatile flash memory with the SAVE command, and % reset the card. At this time, Turbo PMAC will establish the new % baud rate. % % If this program errors and ends without properly closing the serial % port, it might be impossible to re-connect to the port the next time. The % following line of code will release the port and clear the port-object. % newobjs = instrfind;fclose(newobjs);clear newobjs; % The following definitions are used in this file: % Signal - A series of measurements from one source, e.g. motor 1 % actual position, or motor 2 filter output. % 12HexWord - Data is sent through the serial port in 48 bits chunks. 1 % 48 bits chunk is 12 Hexadecimal characters. This is one % 12HexWord % 6HexWord - Each 12HExWord consists of 2 6HexWords. % % file : DT_GatherData_Serial.m % last changes : February 8, 2011 % author : M.L.Norg % used functions : - % version : 2.0 % notes : V1.0 Original version % v1.1 Added help info on I54. % Added Time to file. % v2.0 2011-02-10 % Added 48 INT signals conversion. % Tested I5051 Data Gathering Selection Mask 2. % Split "Read+Conversion" loop into "Read" loop % and "Conversion" loop. % Used start- and stop-buffer location without the % use of pre-defined M-variables. % v2.1 2011-02-10 % Fixed SignalType pre-definition. % Fixed notification on 'incorrect 12HexWord' length. % Fixed Time calculation % v2.2 2011-02-11 % Checked for empty GATHER buffer. % v2.3 2011-02-24 % Changed name from GatherData.m to % DT_GatherData_Serial.m and used DT_GatherData.m to % implement ActiveX gathering function, which is more % than 12 times faster and more robust. % Connect and configure RS232 port % BaudRate I54 % 9600 8 % 14400 9 % 19200 10 % 38400 12 % Average of 1150 samples/sec. % 57600 13 % Average of 1786 samples/sec, but with increased % number of missed characters % 76800 14 % Not available in Matlab % 115200 15 s = serial(port_name); s.BaudRate = 38400; % Buffersize has no impact on duration of fopen(s) command, but an % increased bufer-size will help prevent loss of data during debugging. s.InputBufferSize = 1000000 * 12; s.FlowControl = 'none'; s.Terminator = 'CR'; s.Timeout = 1; s.ReadAsyncMode = 'continuous'; s.DataTerminalReady = 'off'; % Open port. Takes about 3.2 seconds fopen(s); % Keep track of how many 6HEX words are to be expected. A 24 bit integer % counts for 1, a 48 bit integer counts for 2. NrOf6HexWordsPerSample = 0; % Get I5050 String. % Example is given for measuring signals in address I5003 and I5004. % See page 150 of Turbo PMAC/PMAC2 Software Reference. % I5050str = 'C' I5050str = RequestIVariable(s,5050); % Convert into Binary. % I5050Bin = '1100' I5050Bin = dec2bin(hex2dec(I5050str(2:end))); % Find indexes that are one, starting to count from LSB (right). % Example: '1100' -> '0011'. % Find '1' indexes: 3 and 4. I5001MaskIsOne = strfind(I5050Bin(end:-1:1),'1'); NumberOfSignalsI5050 = length(I5001MaskIsOne); % Predefine SignalType with 50 spaces SignalType = char(ones(50,1)*32); % Add found indexes to 5000 to find the I-variable where the address is % stored of the signal that needs to be traced: % Example: 5000 + 3 = I5003, 5000 + 4 = I5004 % Also find out how what type the signals are. Get 2nd character. % 0: Y-register only (24 bits) % 4: X-register only (24 bits) % 8: X/Y double register (48 bits), Executive program interprets as % integer % C: X/Y double register (48 bits), Executive program interprets as % floating-point for NrSignal = 1 : length(I5001MaskIsOne) SignalDefinition = RequestIVariable(s,5000+I5001MaskIsOne(NrSignal)); SignalType(NrSignal) = SignalDefinition(2); end % Repeat for second half of gather definition. I5051str = RequestIVariable(s,5051); I5051Bin = dec2bin(hex2dec(I5051str(2:end))); I5025MaskIsOne = strfind(I5051Bin(end:-1:1),'1'); NumberOfSignalsI5051 = length(I5025MaskIsOne); for NrSignal = 1 : length(I5025MaskIsOne) SignalDefinition = RequestIVariable(s,5024+I5025MaskIsOne(NrSignal)); SignalType(NrSignal+NumberOfSignalsI5050) = SignalDefinition(2); end NumberOfSignals = NumberOfSignalsI5050 + NumberOfSignalsI5051; % Find out how what type the signals are, and how many 6HEX words we can % expect. for NrSignal = 1 : NumberOfSignals switch SignalType(NrSignal) case {'0','4'} NrOf6HexWordsPerSample = NrOf6HexWordsPerSample + 1; case {'8','C'} NrOf6HexWordsPerSample = NrOf6HexWordsPerSample + 2; otherwise error(['Unexpected signaltype: ''',SignalType(NrSignal),'''.']); end end % See page 421 of Turbo PMAC - User Manual: % If the data gathered for a sample leaves the last grouping with only six % characters, this last grouping is filled out with the contents of the % servo cycle counter register X:$000000. % % Check if NrOf6HexWordsPerSample is odd. If so, add one to make it even. if rem(NrOf6HexWordsPerSample,2), NrOf6HexWordsPerSample = NrOf6HexWordsPerSample + 1; % Use 'T' as indication for Timestamps NumberOfSignals = NumberOfSignals + 1; SignalType(NumberOfSignals) = 'T'; end % Get I10 - Servo Interrupt Time % This parameter tells Turbo PMAC how much time there is between servo % interrupts (which is controlled by hardware circuitry), so that the % interpolation software knows how much time to increment each servo % interrupt. I10str = RequestIVariable(s,10); ServoInterruptTimeI10 = str2double(I10str); ServoSampleTime = ServoInterruptTimeI10 / 8388608e3; % Get I5049 - Gathering Downsampling Factor I5049str = RequestIVariable(s,5049); GatherDownSampling = str2double(I5049str); GatherSampleTime = ServoSampleTime * GatherDownSampling; % Find out how large buffer is: % pg 478 of PMAC Software Reference Manual: % X:$003120 Data gather buffer start address % Y:$003120 Data gather buffer storage address % Get Gather Start Address GatherStartAddressStr = RequestVariable(s,'RX:$003120'); GatherStartAddress = str2double(GatherStartAddressStr); % Get Gather End Address GatherEndAddressStr = RequestVariable(s,'RY:$003120'); GatherEndAddress = str2double(GatherEndAddressStr); NumberOf12HexWords = (GatherEndAddress - GatherStartAddress); % Check if GATHER buffer is empty. if ~NumberOf12HexWords Data = []; Time = []; disp('GATHER Buffer is empty'); % clean up serial object fclose(s);delete(s);clear s; else % Predefine DataStr with X-es (char(88)). If an corrupt Word12Hex is found, % 12Xes will be used to indicate the corruption. This will eventually be % converted into NaNs. DataStr = char(88*ones(NumberOf12HexWords,12)); % Ask for data from buffer in 48 bits (12 HEX) size chunks. fprintf(s,'LIST GATHER') tstart = clock; % Calculate how long Xfer takes. LineHex = []; % Read data for Nr12HexWord = 1 : NumberOf12HexWords if isempty(LineHex) LineHex = fgetl(s); end % Find spaces in LineHex iSpaces = findstr(LineHex,' '); % If no spaces are found, only one Word12Hex is left in LineHex if isempty(iSpaces) Word12Hex = LineHex; LineHex = []; else Word12Hex = LineHex(1:iSpaces(1)-1); LineHex = LineHex(iSpaces(1)+1:end); end if (length(Word12Hex)==12) DataStr(Nr12HexWord,:) = Word12Hex; else disp(['Warning: "',Word12Hex,'" of incorrect length. Length is ',... num2str(length(Word12Hex)),' and should be 12.']); end end disp(['Read ',num2str(NumberOf12HexWords),' 42 bit words in ',... num2str(etime(clock,tstart)),' seconds. ',... num2str((NumberOf12HexWords*42)/etime(clock,tstart)),' [bps].' ]); % clean up serial object fclose(s);delete(s);clear s; NumberOfSamples = NumberOf12HexWords / (NrOf6HexWordsPerSample/2); % Change from Round Robin style into regular style: % Lets say we measured 1 24 bit (A), 1 42 bit(HL), plus time (T): % DataStr is now filled like: % LA % TH % LA % TH % % Change order into: % AL % HT % AL % HT % % And reshape into: % ALHT % ALHT % % When grabbing the parts for a 48 int, (LH) first grab High part H and % then Low part L. DataStrChangedOrder = [DataStr(:,7:12) DataStr(:,1:6)]; DataStrReshaped = reshape(DataStrChangedOrder',6*NrOf6HexWordsPerSample,NumberOfSamples)'; % Predefine Data as matrix with NaNs. Data = NaN*ones(NumberOfSamples,NumberOfSignals); % page 246 Turbo PMAC User Manual: % An M-variable may take one of the following types, as specified by the address prefix in the definition: % X: 1 to 24 bits fixed-point in X-memory % Y: 1 to 24 bits fixed-point in Y-memory % D: 48 bits fixed-point across both X- and Y-memory % L: 48 bits floating-point across both X- and Y-memory % DP: 32 bits fixed-point (low 16 bits of X and Y) (for use in dual-ported RAM) % F: 32 bits floating-point (low 16 bits of X and Y) (for use in dual-ported RAM) % TWD: Multiplexed BCD decoding from Thumbwheel port % TWB: Multiplexed binary decoding from Thumbwheel port % TWS: Multiplexed serial I/O decoding from Thumbwheel port % TWR: Multiplexed serial resolver decoding from Thumbwheel port % *: No address definition; for NrSample = 1 : NumberOfSamples, iDataStart = 1; for NrSignal = 1 : NumberOfSignals switch SignalType(NrSignal) case {'0','4','T'}, SampleValueStr = DataStrReshaped(NrSample,iDataStart+(0:5)); % Check for X contents. This means data was corrupted. if isempty(strfind(SampleValueStr,'X')), SampleValue = hex2dec(SampleValueStr); % Convert from 24 unsigned int to signed int SampleValue = SampleValue - 2^24 * (SampleValue > 2^23); Data(NrSample,NrSignal) = SampleValue; else % Fill with NaN if data was corrupted. Data(NrSample,NrSignal) = NaN; end iDataStart = iDataStart+6; case '8', SampleValueStr = DataStrReshaped(NrSample,iDataStart+[6 7 8 9 10 11 0 1 2 3 4 5]); % Check for X contents. This means data was corrupted. if isempty(strfind(SampleValueStr,'X')), SampleValue = hex2dec(SampleValueStr); % Convert from 48 unsigned int to signed int SampleValue = SampleValue - 2^48 * (SampleValue > 2^47); Data(NrSample,NrSignal) = SampleValue; % Fill with NaN if data was corrupted. else Data(NrSample,NrSignal) = NaN; end iDataStart = iDataStart+12; case 'C', error('Not implemented yet'); otherwise error(['Unexpected signaltype: ''',SignalType(NrSignal),'''.']); end end end Time = (0:NumberOfSamples-1) * GatherSampleTime; end function [ReturnString,HandshakeString] = RequestIVariable(s,IvarNumber) % This function sends an I variable value and processes the response. IVarString = ['I',num2str(IvarNumber)]; fprintf(s,IVarString); pause(0.1); ReturnString = fgetl(s); HandshakeString = ReadHandshake(s); function [ReturnString,HandshakeString] = RequestVariable(s,VarString) % This function sends a string and expects a return string. fprintf(s,VarString); ReturnString = fgetl(s); HandshakeString = ReadHandshake(s); function HandShakeString = ReadHandshake(s) % This function is called to read the handshake string or HandShakeString = ''; if s.BytesAvailable, clear ReturnValueStr; ReturnValueStr = fread(s,s.BytesAvailable); if (single(ReturnValueStr(1))==6) HandShakeString = 'ACK'; elseif (single(ReturnValueStr(1))==7) HandShakeString = 'BELL'; else HandShakeString = ReturnValueStr; end end [/code]
  22. Charles, I have been able to communicate with the controller from Matlab, using the main serial port of my UMAC controller. In this post I will list the pinning for the cable and an example program to read one I-variable. In a next post I will post the matlab code I used to read a Gather buffer. For the cable, I took a standard 1:1 serial extension cable, cut off the male connector and soldered the wires to a 26 pin connector that goes to J7 on page 19 in [url=http://www.deltatau.com/manuals/pdfs/UMAC%20TURBO%20HRM.pdf?id=634305159013787520]3U Turbo CPU Board - HRM[/url]. [b]Serial Cable[/b] SubD 9 pin female description Serial Port 26 pin (J7) description 1nc 2Rx5Send Data 3Tx3Receive Data 4DTR14Data Set Ready 5GND13GND 6DSR11Data Terminal Ready 7 RTS 7Clear To Send 8CTS9 Request To Send 9nc The following matlab code connects to serial port COM1, sends an "I10" string and retrieves the answer from the controller. [code]% ReadIVarExample; % % This script shows an example on how to read an I-variable using the main % serial Delta Tau controler port. See GatherData.m for more details. % % Assumptions: % I1 = 1 Serial Port Mode % I3 = 2 I/O Handshake Control % I54 = 12 (default) Baudrate = 38400 % % If this program errors and ends without properly closing the serial % port, it might be impossible to re-connect to the port the next time. The % following line of code will release the port and clear the port-object. % newobjs = instrfind,fclose(newobjs);clear newobjs; % % file : ReadIVarExample.m % last changes : February 3rd, 2011 % author : M.L.Norg % used functions : - % version : 1.0 % notes : % Connect to serial port object and set parameters. s = serial('COM1'); s.BaudRate = 38400; s.InputBufferSize = 4096; s.FlowControl = 'none'; s.Terminator = 'CR'; s.Timeout = 1; s.ReadAsyncMode = 'continuous'; s.DataTerminalReady = 'off'; % Open port fopen(s); IVariableString = 'I10'; % ServoInterruptTimeI10 fprintf(s,IVariableString); % Send string pause(0.1); % Give controller some time to respond. ReturnString = fgetl(s); % Read till next IVariableValue = str2num(ReturnString); % Convert to number ServoSampleTime = IVariableValue / 8388608e3; % Convert to seconds ServoFrequency = 1/ ServoSampleTime; % Convert to frequency disp([IVariableString,' = ',num2str(IVariableValue),'. ServoFrequency = ',num2str(ServoFrequency),' [Hz]']); % Every request is followed by a Handshake string ( or ). % If this string stays in serial buffer, an fgetl will not read anything % (because there are no characters. % Read handshake string: if s.BytesAvailable, AckStr = fread(s,s.BytesAvailable); if (single(AckStr(1))==6) HandShakeString = 'ACK'; % In case of success elseif (single(ReturnValueStr(1))==7) HandShakeString = 'BELL'; % In case of error else HandShakeString = AckStr; % otherwise end end disp(['HandShake String = ',HandShakeString]); % Properly clean up serial object fclose(s);delete(s);clear s; [/code] If anyone is going to experiment with this code, let me know if there are any problems. I'd be happy to assist. regards, Meindert Norg
  23. Hi, I've been experimenting with serial communication between my UMAC controller and Matlab, using the COM1 serial port on my PC and the main serial port on the controller. I3 defines the "I/O Handshake Control" method. I'd like to change it from 2 to 0, to see if not getting the < ACK > value at the end of the the returned strings from the controller makes parsing those strings a little easier. However, when I do the following: [list] [*]change I3 from 2 to 0 from the PEWIN32PRO2 Terminal [*]exit PEWIN32PRO2 [*]start PEWIN32PRO2 [*]check I3 value [/list] it seems as if PEWIN32PRO2 changes this value back to 2. Even when I just restart the terminal and watch window in PEWIN32PRO2 (which I need to do, because the watch-window does not show any results anymore after changing I3 from 2 to 0), the same happens. Do I need to do something special in order to change I3? Thanks, Meindert
  24. Hi Sina, Thanks for your response. My apologies if I was not completely clear in my original question. I'm not looking to [b]measure [/b]the controller frequency response, but want to [b]calculate [/b]the frequency response, using the PID I-variables. Do you have tools (for example in Matlab) that do that? regards, Meindert
×
×
  • Create New...