Jump to content
OMRON Forums

Virtual, Simulated, or Phantom Motor


bradp

Recommended Posts

To setup a phantom motor follow the instructions in the attached application note.

 

Running Simulated Motors on Power PMAC 2010-08.doc

 

Also, here is some code to directly paste into an IDE solution.

 

#define Mtr0DacOutReg Sys.Idata[1].a

 

Motor[0].Ctrl = Sys.PidCtrl // only need simple PID loop

Motor[0].ServoCtrl = 1

Motor[0].pDac = Mtr0DacOutReg // do not use Sys.pushm + 0 (Sys.Idata[0]) as it is used by default by many things

Motor[0].pAmpEnable = 0

Motor[0].pAmpFault = 0

Motor[0].pLimits = 0

Motor[0].CaptureMode = 1 // software capture

 

// Homing setup. Only needed if the phantom motor will use real IO for homing

// otherise skip this and use HMZ for home command

Motor[0].pCaptFlag = Acc24E2A[4].Chan[2].Status.a // use real IO from channel 3

Motor[0].pCaptPos = Acc24E2A[4].Chan[2].HomeCapt.a // Make this setting since Gate1[4].Chan[2].HomeCapt must be read to reset Gate1[4].Chan[2].PosCapt otherwise home is instant as captured flag is not cleared

Gate1[4].Chan[2].CaptFlagSel = 0 // use homeflag input

Gate1[4].Chan[2].CaptCtrl = 2 // capture on flag high

 

// needed gains

Motor[0].Servo.Kp = 1

Motor[0].Servo.Kvfb = 0

Motor[0].Servo.Kvff = 0

Motor[0].Servo.Kaff = 0

Motor[0].Servo.Ki = 0

 

// process Dac data

EncTable[0].type = 1

EncTable[0].ScaleFactor = 1/65536

EncTable[0].pEnc = Mtr0DacOutReg

EncTable[0].index4 = 1 // Integerate once

Link to comment
Share on other sites

  • 2 years later...
  • Replies 11
  • Created
  • Last Reply

Top Posters In This Topic

Is there an equivalent way to do the simulated motors using an ACC-24E3 board to take the simulated servo output and feed back the results since it does not have the TimeBetweenCts element. I can't seem to figure out how to do it without that variable and this is actually an important test for us as it simulated the backplane traffic before we get all of our motors. Is there somewhere else that I can point the pEnc1 so that the phantom joint actually moves?
Link to comment
Share on other sites

In this case the equivalent setup is described in the ACC24E3 hardware manual in the section about stepper motors. Below is a copy of the text.

 

 

Pulse-and-Direction Amplifiers

 

Pulse-and-direction outputs can be obtained either on the digital amplifier-interface mezzanine board using the Phase D outputs or on the digital feedback mezzanine board using the auxiliary flag (T, U, V, and W) lines. To enable output of these signals on the digital feedback mezzanine board, the element Gate3.Chan[j].OutFlagD must be set to 1. This is not a saved element, so it must be set to 1 after every power-on or reset – this is usually done in a “power-on PLC program”.

 

Pulse-and-direction outputs are typically used for traditional stepper motor drives where the motors operate open loop. These outputs can also be used for “stepper-replacement” servo drives, where the position loop is closed in the drive. In both cases, the Power PMAC motor commanding the pulse output will require a simulated feedback to close a loop and ensure that the correct number of pulses have been generated.

 

IC Hardware Setup

 

To obtain signals from the pulse-frequency modulation (PFM) circuitry on the Phase D outputs of the IC, bit 3 (value 8) of Gate3.Chan[j].OutputMode must be set to 1, making the value of the 4-bit element 8 or higher (depending on the desired mode – if any – for Phases A, B, and C). Gate3.Chan[j].PackOutData must be set to 0 (not the default) so that the Phase D output comes from the Phase D register Gate3.Chan[j].Pfm, and not the low 16 bits of the Phase B register. This permits the full use of the 24 active bits of the Pfm register (which appear in the high 24 bits of the 32-bit bus).

Gate3.Chan[j].PfmFormat must be set to the default value of 0 so that the PFM signals are output in pulse-and-direction (and not quadrature) format. Generally, bit 1 of Gate3.Chan[j].OutputPol is set to the default value of 0 for high-true pulses on the PULSE+ line. The polarity can be inverted either by using the PULSE- line or by setting this bit to 1. The single-bit element Gate3.Chan[j].PfmDirPol can be used to invert the sense of the direction output in software.

 

There are several possibilities for providing the feedback value for Power PMAC to close a position loop and ensure that the correct number of pulses have been output. In the preferred method, Gate3.Chan[j].TimerMode should be set to 3 to use the channel’s timer as a pulse counter for the generated pulse train. In this mode, the accumulated pulse count can be read in Gate3.Chan[j].TimerA.

Note that this setup leaves the channel’s encoder circuitry available to process a real encoder, which could be used for confirmation of position. It is not recommended to use real encoder feedback to close the loop in this mode of operation. In an alternate method, Gate3.Chan[j].EncCtrl is set to 8 and the pulse train is fed into the channel’s encoder counter. In this mode, Gate3.Chan[j].ServoCapt contains the accumulated pulse count in units of 1/256 count (8 bits of fractional count information). If Gate3.Chan[j].TimerMode is set to its default value of 0, the low 8 bits will contain a timer-based fractional count estimation, which can provide slightly smoother trajectories, but may lead to dithering at rest. If TimerMode is set to 2 or 3, there is no fractional count estimation (the fractional component is fixed at ½ count). Note that in this method, the encoder decode and count circuitry for the channel is not available for use with an external encoder.

 

Encoder Conversion Table Setup

 

To process the resulting position value in the preferred method for servo-loop feedback, a “Type 1” single-register-read conversion should be specified in the encoder conversion table. EncTable[n].pEnc, which specifies the address of this register, should be set to Gate3.Chan[j].TimerA.a. (EncTable[n].pEnc1, which specifies a second source, is not used in this mode; its setting does not matter.) In the alternate method, EncTable[n].pEnc should be set to Gate3.Chan[j].ServoCapt.a to use the latched encoder counter value Conversion parameters EncTable[n].index1, .index2, .index3, .index4, and .MaxDelta are generally all set to 0 to use this register. To get the output of the conversion table in units of pulses (most common) in the preferred method, EncTable[n].ScaleFactor should be set to 1.0. In the alternate method using the ServoCapt register, it should be set to 1/256 to get the output in units of counts.

 

Motor Addressing and Mode Setup

 

The motor element Motor[x].pDac should be set to Gate3.Chan[j].Pfm.a to specify the use of the channel’s Phase D PFM output. Motor[x].pEnc and Motor[x].pEnc2 should be set to EncTable[n].a, where “n” is the index of the table entry that processed the TimerA register used as a pulse counter. It is recommended that the following servo gain values be used to close a simulated loop:

 

Motor[x].Servo.Kp = 40

Motor[x].Servo.Kvfb = 0

Motor[x].Servo.Kvff = 40

Motor[x].Servo.Ki = 0.001

 

Many users will want to create a half count of deadband in the servo loop to prevent dithering between adjacent steps at rest if the command value stopped in between them. To do this, set Motor[x].BreakPosErr to 0.5 (if the motor units are equal to pulses), and Motor[x].Kbreak to 0.0.

Link to comment
Share on other sites

  • 1 year later...

If you need to have a virtual (simulated or phantom) motor without using any hardware channels, only as a software motor, you can use the following settings. Note that you can have multiple simulated motors with these settings by only changing the L0 value at the beginning of each copy and paste block. The servo tuning should be sufficient for most applications and servo frequencies.

 

// Virtual Motor Setup for Power PMAC

// Assign the desired motor number to L0
// If more than one virtual motor is needed, repeat the copy and paste process for the following code
// and only change the L0 value for each section

//***********************************************************************************//

L0=1

// Copy the following lines without modification
Ldata.Motor=L0
DKILL
Motor[L0].Ctrl=Sys.PidCtrl	// This can be set to Sys.ServoCtrl for using advanced filters. Sys.PidCtrl adds less CPU load in comparison.
Motor[L0].ServoCtrl=1
Motor[L0].pAmpEnable=0
Motor[L0].pAmpFault=0
Motor[L0].pLimits=0
Motor[L0].pEnc=EncTable[L0].a
Motor[L0].pEnc2=EncTable[L0].a
Motor[L0].pDac=Sys.Idata[L0].a
EncTable[L0].type=11
EncTable[L0].pEnc=Motor[L0].IqCmd.a
EncTable[L0].pEnc1=Sys.pushm
EncTable[L0].index1=0
EncTable[L0].index2=0
EncTable[L0].index3=0
EncTable[L0].index4=1
EncTable[L0].index5=255
EncTable[L0].ScaleFactor=1/(256*(EncTable[L0].index5+1))
Motor[L0].PosSf=360/(24*exp2(20))
Motor[L0].Pos2Sf=360/(24*exp2(20))
Motor[L0].Pos=0
Motor[L0].HomePos=0
Motor[L0].Ctrl=Sys.ServoCtrl
Motor[L0].FatalFeLimit=10
Motor[L0].WarnFeLimit=5

// Adjust the following values based upon the application

Motor[L0].MotorTa=-1.5E-6
Motor[L0].MotorTs=-1.5E-6
Motor[L0].MaxSpeed=0.172
Motor[L0].JogSpeed=0.005 
Motor[L0].InvAmax=1/5.471960662E-4 
Motor[L0].InvJmax=1/5.471960662E-4 
Motor[L0].InvDmax=1/5.471960662E-4 
Motor[L0].JogTa=0
Motor[L0].JogTs=250
Motor[L0].InPosBand=0.0005
Motor[L0].InPosTime=9

Motor[L0].Servo.Ke1=0
Motor[L0].Servo.Ke2=0
Motor[L0].Servo.Kf1=0
Motor[L0].Servo.Kf2=0
Motor[L0].Servo.Ka0=1
Motor[L0].Servo.Ka1=0
Motor[L0].Servo.Ka2=0
Motor[L0].Servo.Ka3=0
Motor[L0].Servo.Ka4=0
Motor[L0].Servo.Ka5=0
Motor[L0].Servo.Ka6=0
Motor[L0].Servo.Ka7=0
Motor[L0].Servo.Kb0=1
Motor[L0].Servo.Kb1=0
Motor[L0].Servo.Kb2=0
Motor[L0].Servo.Kb3=0
Motor[L0].Servo.Kb4=0
Motor[L0].Servo.Kb5=0
Motor[L0].Servo.Kb6=0
Motor[L0].Servo.Kb7=0
Motor[L0].Servo.Kc1=0
Motor[L0].Servo.Kc2=0
Motor[L0].Servo.Kc3=0
Motor[L0].Servo.Kc4=0
Motor[L0].Servo.Kc5=0
Motor[L0].Servo.Kc6=0
Motor[L0].Servo.Kc7=0
Motor[L0].Servo.Kd1=0
Motor[L0].Servo.Kd2=0
Motor[L0].Servo.Kd3=0
Motor[L0].Servo.Kd4=0
Motor[L0].Servo.Kd5=0
Motor[L0].Servo.Kd6=0
Motor[L0].Servo.Kd7=0
Motor[L0].Servo.Kp=8000
Motor[L0].Servo.Kvifb=0
Motor[L0].Servo.Kviff=0
Motor[L0].Servo.Kvfb=0
Motor[L0].Servo.Kvff=69905.055
Motor[L0].Servo.Kafb=0
Motor[L0].Servo.Kaff=69905.055
Motor[L0].Servo.Ki=9.9999997e-5
Motor[L0].Servo.Kfff=0
Motor[L0].Servo.MaxPosErr=10000
Motor[L0].Servo.MaxInt=28000
Motor[L0].Servo.BreakPosErr=0
Motor[L0].Servo.Kbreak=0
Motor[L0].Servo.OutDbOn=0
Motor[L0].Servo.OutDbOff=0
Motor[L0].Servo.OutDbSeed=0
Motor[L0].Servo.SwPoly7=0
Motor[L0].Servo.SwFffInt=0
Motor[L0].Servo.SwZvInt=0
Motor[L0].Servo.Kxpg=0
Motor[L0].Servo.Kxvg=0
Motor[L0].Servo.Kxig=0
Motor[L0].Servo.EstTime=0
Motor[L0].Servo.EstMinDac=0
Motor[L0].Servo.NominalGain=0
Motor[L0].Servo.MinGainFactor=1
Motor[L0].Servo.MaxGainFactor=1
Motor[L0].Servo.MaxW=0
Motor[L0].Servo.MaxDR=0
Motor[L0].Servo.MinW=0
Motor[L0].Servo.MinDR=0

//***********************************************************************************//

Link to comment
Share on other sites

  • 4 years later...

Does this method work for Power Clipper only?

 

Yes this is a virtual (simulated or phantom) motor without using any hardware channels, only as a software motor usable on any Power PMAC platform.

 

As quoted in the document, there are two methods:

1. Pulse-and-Direction Stepper-Motor

2. Virtual Motor with No ASIC Hardware

 

I have tried both on a Clipper. Only the Virtual Motor with No ASIC Hardware is working. The PFM method doesn't work. I assume that it lacks some hardware to run PFM. Am I right and what do I need more to run PFM?

Link to comment
Share on other sites

  • 8 months later...

If you need to have a virtual (simulated or phantom) motor without using any hardware channels, only as a software motor, you can use the following settings. Note that you can have multiple simulated motors with these settings by only changing the L0 value at the beginning of each copy and paste block. The servo tuning should be sufficient for most applications and servo frequencies.

 

// Virtual Motor Setup for Power PMAC

// Assign the desired motor number to L0
// If more than one virtual motor is needed, repeat the copy and paste process for the following code
// and only change the L0 value for each section

//***********************************************************************************//

L0=1

// Copy the following lines without modification
Ldata.Motor=L0
DKILL
Motor[L0].Ctrl=Sys.PidCtrl	// This can be set to Sys.ServoCtrl for using advanced filters. Sys.PidCtrl adds less CPU load in comparison.
Motor[L0].ServoCtrl=1
Motor[L0].pAmpEnable=0
Motor[L0].pAmpFault=0
Motor[L0].pLimits=0
Motor[L0].pEnc=EncTable[L0].a
Motor[L0].pEnc2=EncTable[L0].a
Motor[L0].pDac=Sys.Idata[L0].a
EncTable[L0].type=11
EncTable[L0].pEnc=Motor[L0].IqCmd.a
EncTable[L0].pEnc1=Sys.pushm
EncTable[L0].index1=0
EncTable[L0].index2=0
EncTable[L0].index3=0
EncTable[L0].index4=1
EncTable[L0].index5=255
EncTable[L0].ScaleFactor=1/(256*(EncTable[L0].index5+1))
Motor[L0].PosSf=360/(24*exp2(20))
Motor[L0].Pos2Sf=360/(24*exp2(20))
Motor[L0].Pos=0
Motor[L0].HomePos=0
Motor[L0].Ctrl=Sys.ServoCtrl
Motor[L0].FatalFeLimit=10
Motor[L0].WarnFeLimit=5

// Adjust the following values based upon the application

Motor[L0].MotorTa=-1.5E-6
Motor[L0].MotorTs=-1.5E-6
Motor[L0].MaxSpeed=0.172
Motor[L0].JogSpeed=0.005 
Motor[L0].InvAmax=1/5.471960662E-4 
Motor[L0].InvJmax=1/5.471960662E-4 
Motor[L0].InvDmax=1/5.471960662E-4 
Motor[L0].JogTa=0
Motor[L0].JogTs=250
Motor[L0].InPosBand=0.0005
Motor[L0].InPosTime=9

Motor[L0].Servo.Ke1=0
Motor[L0].Servo.Ke2=0
Motor[L0].Servo.Kf1=0
Motor[L0].Servo.Kf2=0
Motor[L0].Servo.Ka0=1
Motor[L0].Servo.Ka1=0
Motor[L0].Servo.Ka2=0
Motor[L0].Servo.Ka3=0
Motor[L0].Servo.Ka4=0
Motor[L0].Servo.Ka5=0
Motor[L0].Servo.Ka6=0
Motor[L0].Servo.Ka7=0
Motor[L0].Servo.Kb0=1
Motor[L0].Servo.Kb1=0
Motor[L0].Servo.Kb2=0
Motor[L0].Servo.Kb3=0
Motor[L0].Servo.Kb4=0
Motor[L0].Servo.Kb5=0
Motor[L0].Servo.Kb6=0
Motor[L0].Servo.Kb7=0
Motor[L0].Servo.Kc1=0
Motor[L0].Servo.Kc2=0
Motor[L0].Servo.Kc3=0
Motor[L0].Servo.Kc4=0
Motor[L0].Servo.Kc5=0
Motor[L0].Servo.Kc6=0
Motor[L0].Servo.Kc7=0
Motor[L0].Servo.Kd1=0
Motor[L0].Servo.Kd2=0
Motor[L0].Servo.Kd3=0
Motor[L0].Servo.Kd4=0
Motor[L0].Servo.Kd5=0
Motor[L0].Servo.Kd6=0
Motor[L0].Servo.Kd7=0
Motor[L0].Servo.Kp=8000
Motor[L0].Servo.Kvifb=0
Motor[L0].Servo.Kviff=0
Motor[L0].Servo.Kvfb=0
Motor[L0].Servo.Kvff=69905.055
Motor[L0].Servo.Kafb=0
Motor[L0].Servo.Kaff=69905.055
Motor[L0].Servo.Ki=9.9999997e-5
Motor[L0].Servo.Kfff=0
Motor[L0].Servo.MaxPosErr=10000
Motor[L0].Servo.MaxInt=28000
Motor[L0].Servo.BreakPosErr=0
Motor[L0].Servo.Kbreak=0
Motor[L0].Servo.OutDbOn=0
Motor[L0].Servo.OutDbOff=0
Motor[L0].Servo.OutDbSeed=0
Motor[L0].Servo.SwPoly7=0
Motor[L0].Servo.SwFffInt=0
Motor[L0].Servo.SwZvInt=0
Motor[L0].Servo.Kxpg=0
Motor[L0].Servo.Kxvg=0
Motor[L0].Servo.Kxig=0
Motor[L0].Servo.EstTime=0
Motor[L0].Servo.EstMinDac=0
Motor[L0].Servo.NominalGain=0
Motor[L0].Servo.MinGainFactor=1
Motor[L0].Servo.MaxGainFactor=1
Motor[L0].Servo.MaxW=0
Motor[L0].Servo.MaxDR=0
Motor[L0].Servo.MinW=0
Motor[L0].Servo.MinDR=0

//***********************************************************************************//

 

Hi

I used this code to simulate 26 virtual motors in my application.

I want to do some software testing before implementing the code to the real thing.

 

I found that I can trigger Motor[x].FeFetal by setting motor[x].FatalFeLimit to zero.

is there any way to trigger other faults like Motor[x].AmpFault, I2TFault or EncLoss, by changing some software variables?

Link to comment
Share on other sites

"Is there any way to trigger other faults like Motor[x].AmpFault, I2TFault or EncLoss, by changing some software variables?"

 

If the status register pointed to by Motor[x].pAmpFault, pEncLoss, etc. provides consistent readings even if nothing is wired into them, then you can trigger faults by changing Motor[x].AmpFaultLevel, EncLossLevel, etc.

 

A more flexible approach is to set the address variables to a user buffer register (e.g. Motor[x].pAmpFault=Sys.Udata[100].a). Then you can write to individual bits in the register to trigger faults.

Link to comment
Share on other sites

I found that I can trigger Motor[x].FeFetal by setting motor[x].FatalFeLimit to zero.

 

This is a little funny, 0 should disable amp faults entirely, you should need to set this to a small non-zero value.

 

is there any way to trigger other faults like Motor[x].AmpFault, I2TFault or EncLoss, by changing some software variables?

 

Status bits that pull their information from pointers can be set manually by pointing at Sys.UData addresses, here are a couple examples:

 

// Amp Fault
Motor[1].pAmpFault=Sys.Udata[10].a
Motor[1].AmpFaultBit=0
Motor[1].AmpFaultLevel=1
// Fault Sys.Udata[10]=1
// Recover Sys.Udata[10]=0

// Enc Loss
Motor[1].pEncLoss=Sys.Udata[11].a
Motor[1].EncLossBit=0
// Fault Sys.Udata[11]=0
// Recover Sys.Udata[11]=1

// Limits
Motor[1].pLimits=Sys.Udata[12].a
Motor[1].LimitBits=0
// Plus Fault Sys.Udata[12]=1
// Minus Fault Sys.Udata[12]=2
// Recover Sys.Udata[12]=0

 

For an I2T fault, you would probably want to set I2tSet and I2tTrip low enough that any current will cause a fault.

Motor[x].I2TSet=1

Motor[x].I2TTrip=1

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.

×
×
  • Create New...