Pulsar的帮助文件中提供了基本的Eza使用方法:
Pulsar Help >> Chapter 6. EZFlow >> 6.5.3. Advanced EZFlow
messagePasser,直接输出Ezflow的打印信息
messagePasser("Run Profile #: " + (i+1).ToString() +" / " +profileRowTotal.ToString());
pulsarSystem,当前的子系统,可直接使用其子类
pulsarSystem.ShutActiveLimits.ClearAll();
pulsarSystem.TripActiveLimits.ClearAll();
pulsarSystem.IndicateActiveLimits.ClearAll();
objectCollection,Pulsar 中Object的集合,用于根据Name确定对象
SequencerModel FindSequencer (string name)
{
SequencerModel obj = objectCollection.SequencerModels[name];
if (obj== null)
{
throw new Exception( "Sequencer not found :"+ name);
}
return obj;
}
SignalGeneratorModel FindSiggen (string name)
{
SignalGeneratorModel obj = objectCollection.SignalGeneratorModels[name];
if (obj== null)
{
throw new Exception( "siggen not found :"+ name);
}
return obj;
}
// 设置Global Amplitude
#using Servotest.D2R.Multisystem
float newValue = 10f;
pulsarSystem.SystemWideProps.GlobalAmplitudeValue.FloatValue = newValue;
// 获取当前系统的DSP 迭代频率
float dspCodeIterationFrequency = (float) MultiSystemController.Instance.Dsp.DSPTimersCounters.DSPCodeIterationFrequency;
// 激活Signal Generator Enable
pulsarSystem.SystemWideProps.SignalGeneratorsEnabledValue.BoolValue = true;
通过切换PolarityMask的属性,当其与LogicalMask一致时,则输出True,可利用作差进行切换,需要保证第一次满足相加等于2,才能保证后续的持续工作的准确性。
$Pressure Switch X2$.PolarityMask=0x00000002-$Pressure Switch X2$.PolarityMask;
尤其是在耐久试验中,定期保存数据,记录日志,便于后续的反查分析。
string path= @"C:\PulsarData\BBK 4 Poster Demo with Socket\EZFlow\RecordLog"+ ".txt";
if (!File.Exists(path))
{
FileInfo myfile = new FileInfo(path);
FileStream fs = myfile.Create();
fs.Close();
}
DateTime dt = DateTime.Now;
StreamWriter sw = File.AppendText(path);
sw.WriteLine("_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ");
sw.WriteLine("TestDataTime: "+ dt);
String Tempstr;
Tempstr=(system.SystemWideProps.GlobalAmplitudeValue.FloatValue).ToString("0.00");
sw.WriteLine(Tempstr);
sw.Flush();
sw.Close();
return true;
#using Servotest.Foundation.Logging;
float fVelocity = $maxVel(m/s)$.Value;
float fAmp = $Amplitude(mm)$.Value;// to get from float variable
fAmp /= 1000;
TraceHelper.WriteLine(TraceCategory.Info,"Setting Frequency from Velocity v="+fVelocity+" fAmp="+fAmp);
// example prints to Pulsar.log
// protect against zero divide
if (fAmp <=0) { return false;} // exit with error
double Freq = fVelocity/(2*Math.PI*fAmp); // Maths results default to double
//check for invalid
if (Freq < .01) { return false;}
if (Freq > 100.0) { return false;}
$Primary Signal Generator$.Frequency=(float) Freq;
$Primary Signal Generator$.RunningState=RunningState.Running;
return true;
通过一次性平衡掉Preload的残值(压差力)
float Preload_Z1A_Compensation = ($DifferentialPress Z1_A$.EngineeringOutput+$Preload.Z1_A$.EngineeringOutput-$Preload Command Z1 Force_A$.EngineeringOutput)/100f; //Engineering to DSP float
float Preload_Z2A_Compensation = ($DifferentialPress Z2_A$.EngineeringOutput+$Preload.Z2_A$.EngineeringOutput-$Preload Command Z2 Force_A$.EngineeringOutput)/100f;
float Preload_Z3A_Compensation = ($DifferentialPress Z3_A$.EngineeringOutput+$Preload.Z3_A$.EngineeringOutput-$Preload Command Z3 Force_A$.EngineeringOutput)/100f;
float Preload_Z4A_Compensation = ($DifferentialPress Z4_A$.EngineeringOutput+$Preload.Z4_A$.EngineeringOutput-$Preload Command Z4 Force_A$.EngineeringOutput)/100f;
$Preload Autobalance Control Z1_A$.ProductScale+=Preload_Z1A_Compensation;
$Preload Autobalance Control Z2_A$.ProductScale+=Preload_Z2A_Compensation;
$Preload Autobalance Control Z3_A$.ProductScale+=Preload_Z3A_Compensation;
$Preload Autobalance Control Z4_A$.ProductScale+=Preload_Z4A_Compensation;
return true;
#using Servotest.D2R.Multisystem;
string systemName = "Table A";
ServotestSystem system = MultiSystemController.Instance.GetSystemNamed(systemName);
if (system==null) {return false;}
system.ShutActiveLimits.ClearAll();
system.TripActiveLimits.ClearAll();
system.IndicateActiveLimits.ClearAll();
return true;
也可以简化为:
pulsarSystem.ShutActiveLimits.ClearAll();
pulsarSystem.TripActiveLimits.ClearAll();
pulsarSystem.IndicateActiveLimits.ClearAll();
return true;
其中pulsarSystem为Pulsar的Advanced Eza工具中已提供的实例字段,表示当前ServotestSystem,而不需要再获取一次。
通过设定ServoController的Park位,通过Eza控制Meanlevel的命令为Park位数值,进行停机位操作,避免后续调试过程中修改微调停机位数据时不断的修改EzFlow文件。
$Displacement Controller X_A$.ScaledRampRate = 10f;
$Displacement Controller Y_A$.ScaledRampRate = 10f;
$Displacement Controller Z_A$.ScaledRampRate = 10f;
$Displacement Controller Roll_A$.ScaledRampRate = 0.2f;
$Displacement Controller Pitch_A$.ScaledRampRate = 0.2f;
$Displacement Controller Yaw_A$.ScaledRampRate = 0.2f;
$Displacement Controller Roll_A$.MeanLevelEngineeringValue = $Displacement Controller Roll_A$.ParkPosition;
$Displacement Controller Pitch_A$.MeanLevelEngineeringValue = $Displacement Controller Pitch_A$.ParkPosition;
$Displacement Controller Yaw_A$.MeanLevelEngineeringValue = $Displacement Controller Yaw_A$.ParkPosition;
$Displacement Controller X_A$.MeanLevelEngineeringValue = $Displacement Controller X_A$.ParkPosition;
$Displacement Controller Y_A$.MeanLevelEngineeringValue = $Displacement Controller Y_A$.ParkPosition;
$Displacement Controller Z_A$.MeanLevelEngineeringValue = $Displacement Controller Z_A$.ParkPosition;
LimitAction ActionI=LimitAction.Indicate;
LimitAction ActionT=LimitAction.Trip;
LimitAction ActionS=LimitAction.Trip;
$HPP Shutdown$.Action=ActionI;
$HPP Pressure Low$.Action=ActionI;
$HSM1 Low Supply Press$.Action=ActionI;
$System Displacement Limit X1_A$.Action=ActionI;
return true;
if(%P%==1)
{
$Acq_01_A$.Synchronization=Servotest.D2R.CoreTypes.DataLoggerSynchronization.Replayer;
}
else
{
$Acq_01_A$.Synchronization=Servotest.D2R.CoreTypes.DataLoggerSynchronization.Nothing;
}
return true;
bool PreloadTargetReach=true;
if (Math.Abs($Preload Z1 Target$.EngineeringOutput-$Preload.Z1$.EngineeringOutput)>10f) PreloadTargetReach=false;
if (Math.Abs($Preload Z2 Target$.EngineeringOutput-$Preload.Z2$.EngineeringOutput)>10f) PreloadTargetReach=false;
if (Math.Abs($Preload Z3 Target$.EngineeringOutput-$Preload.Z3$.EngineeringOutput)>10f) PreloadTargetReach=false;
if (Math.Abs($Preload Z4 Target$.EngineeringOutput-$Preload.Z4$.EngineeringOutput)>10f) PreloadTargetReach=false;
if (Math.Abs($Preload Z5 Target$.EngineeringOutput-$Preload.Z5$.EngineeringOutput)>10f) PreloadTargetReach=false;
if (Math.Abs($Preload Z6 Target$.EngineeringOutput-$Preload.Z6$.EngineeringOutput)>10f) PreloadTargetReach=false;
return PreloadTargetReach;
#using System.Threading;
$Acq03$.On=true;
$Signal Generator Z$.Waveform =Servotest.D2R.CoreTypes.Waveform.Square;
$Signal Generator Z$.RunningState=Servotest.D2R.CoreTypes.RunningState.Running;
$Signal Generator Z$.Frequency = 0.5f;
for (int i = 1;i<= 10;i++)
{
$Signal Generator Z$.Frequency =0.5f+ i/20f;
await Task.Delay(1000);
}
$Signal Generator Z$.RunningState=Servotest.D2R.CoreTypes.RunningState.Stopped;
$Acq03$.On=false;
return true;
用于上一个Ezflow完成后,自动触发第二个Ezflow,通常第二个Ezflow用于记录数据,比如AutoStart、Set for ICS 、Set for Sig Gen之后自动触发用于记录数据的E在flow,但不想第一个Ezflow一直运行。
该段Eza有两个入参,”Ezflow1",“Ezflow2"表示当前系统中的上一个EzFlowActionRunner和接下来要委托自动运行的EzFlowActionRunner,也可以设为”%Ezflow1%”,“%Ezflow2%”,进行通用化,加入到EzFlow时再具体设置。
#using System.Windows.Forms;
string firstActionRunnerName="Ezflow1";
foreach(var actionRunner in objectCollection.ActionRunnerModels)
{
if(actionRunner.DisplayName == firstActionRunnerName)
{
actionRunner.StoppingChanged += OnStopping;
actionRunner.Run();
break;
}
}
return true;
}
string secondActionRunnerName="Ezflow2";
private void OnStopping(object sender, EventArgs args)
{
var actionRunner = sender as ActionRunnerModel;
if(actionRunner != null){
actionRunner.StoppingChanged -= OnStopping;
foreach(var actionRunner2 in objectCollection.ActionRunnerModels)
{
if(actionRunner2.DisplayName == secondActionRunnerName)
{
actionRunner2.Run();
break;
}
}
}
messagePasser为AdvancedEza中提供的已有实例,可以在Eza中直接调用,该消息可以输出在Ezflow的调试时,当Ezflow生成了ActionRunner时,会在EzFlow Action Runner的面板的消息区。
messagePasser("Script start !");
该日志会输出Pulsar的log日志当中。
TraceHelper.WriteLine(TraceCategory.Info,"Script excuted completely , All limited are refreshed. ");
TraceCategory可以选择的有InitialisationErrors/Configuration/Exception/Error/ExecutionLog/Info/Logging,通常建议选Info即可。
需要引用Microsoft.Office.Interop.Excel.dll文件,放到指定路径后eza中进行引用即可。
#include C:\PulsarData\Extensions\Lib\Microsoft.Office.Interop.Excel.dll;
读取Excle文件
string xlsxPath = @"C:\PulsarData...\LoadTable.xlsx";
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook workbook = xlApp.Workbooks.Add(xlsxPath);
Worksheet wsLoadTable = (Worksheet)workbook.Worksheets[1];
if (wsLoadTable == null || wsProfile == null)
{
TraceHelper.WriteLine(TraceCategory.Info, " unable to open template worksheet");
return false;
}
// 定义起始的单元格坐标
var StartCell = "B1";
var EndCell = "I12";
// 获取表格数据
var LoadTable = getCellsValue(wsLoadTable, StartCell, EndCell);
// 操作完之后无比关闭该进程,否则任务管理器中会越来越多的Excel进程
workbook.Close ();
xlApp.Quit ();
读取指定sheet中指定区间的数据,并转换为float类型
float[,] getCellsValue(Worksheet ws, string StartCell, string EndCell)
{
float[,] arrValue = null;
var xlSheet = ws;
try
{
var xlRange = (Microsoft.Office.Interop.Excel.Range)xlSheet.get_Range(StartCell, EndCell);
arrValue = new float[xlRange.Rows.Count, xlRange.Columns.Count];
int rowStartIndex = ((Microsoft.Office.Interop.Excel.Range)xlSheet.get_Range(StartCell, StartCell)).Row; //起始行号
int columnStartIndex = ((Microsoft.Office.Interop.Excel.Range)xlSheet.get_Range(StartCell, StartCell)).Column; //起始列号
int rowNum = xlRange.Rows.Count; //行数目
int columnNum = xlRange.Columns.Count; //列数目
int index = 0;
for (int i = rowStartIndex; i < rowStartIndex + rowNum; i++)
{
for (int j = columnStartIndex; j < columnNum + columnStartIndex; j++)
{
arrValue[i - rowStartIndex, j - columnStartIndex] = (float)((double)((Microsoft.Office.Interop.Excel.Range)xlSheet.Cells[i, j]).Value2);
index++;
}
}
}
catch (Exception e)
{
throw new Exception(e.Message);
}
return arrValue;
}
#using Servotest.D2R.Multisystem;
#using Servotest.D2R.EntityData;
#using Servotest.Foundation.Exceptions;
#include Servotest.Database.dll;
string systemName = "Sim";
ServotestSystem system = MultiSystemController.Instance.GetSystemNamed(systemName);
if (system == null)
{
return false;
}
BasicErrorCollection warnings;
// 添加 UnderPeakLimit
// UnderPeakLimitData data = new UnderPeakLimitData();
// data.Name = "abcdefghisj";
// data.ReferenceSignalName = "Float Zero";
// data.ReferencePositiveTrigger = 1;
// data.ReferenceNegativeTrigger = -1;
// data.InputSignalName = "Float Zero";
// data.ExpectedAtPositiveTrigger = 1;
// data.ExpectedAtNegativeTrigger = -1;
// data.Action = LimitAction.Indicate;
// data.Protected = false;
// var limit = system.DynamicUnderPeakLimitModelCollection.Create(data, out warnings);
// 添加 AnalogueLimit
AnalogueLimitData data = new AnalogueLimitData();
data.Name = "abcdefghisj";
data.InputSignalName = "Float Zero";
data.PositiveLimit = 1;
data.NegativeLimit = -1;
data.PositiveAction = LimitAction.Indicate;
data.NegativeAction = LimitAction.Indicate;
data.Protected = false;
var limit = system.DynamicAnalogueLimitModelCollection.Create(data, out warnings);
// 删除Limit
system.DynamicAnalogueLimitModelCollection.Destroy("name")
return true;
添加引用
#using System.Windows.Forms;
显示 MessageBox
MessageBox.Show("弹出信息");
#using Servotest.D2R.Multisystem;
string systemName = "Sim";
ServotestSystem system = MultiSystemController.Instance.GetSystemNamed(systemName);
if (system == null)
{
return false;
}
var matrixModels = system.SystemObjectCollection.MatrixModels;
var signal = system.FindSignal("Force.Y.X1A"); // Change the signal name here.
var matrix = matrixModels["ForceMatrix.Pitch"]; // Change the name of matrix to be used here.
matrix.SignalsValue[0] = signal; // Change the index of signal to be replaced here.
return true;
// Use to create memory map of Pulsar Objects
// dumps to a csv file
// A bit hard coded based upon dsp object structure, may be subect to version issues
// current version compatible with 1.8 and 1.9 (2022)
// JGW
#using Servotest.D2R.Multisystem ;
#using Servotest.D2R.Dsp;
#using Servotest.D2R.DspUsb;
#using Servotest.D2R.MemoryManagement ;
#include Servotest.Dsp.dll;
ServotestSystem system = pulsarSystem; // Latest 1.8 onwards knows it’s system in eza
// create csv
string sPath = @"C:\PulsarData\Output";// names done this way to be cleverere in future
string sSep = ",";
string sKey = system.Name ;
string sFile=sPath+"\\"+sKey+"_memmap.csv";
string sMsd = system.MultiSystemController.MSDFilePath;
StreamWriter fWrite=null;
fWrite= new StreamWriter(sFile) ;
string sRow="Pulsar DSP Object Map"+sSep+"for System"+ sSep + system.Name + sSep + sMsd ;
fWrite.WriteLine(sRow);
sRow=DateTime.Now.ToString("dd/MM/yyyy") + sSep + DateTime.Now.ToString("hh:mm");
fWrite.WriteLine(sRow);
float dspCodeIterationFrequency = (float) MultiSystemController.Instance.Dsp.DSPTimersCounters.DSPCodeIterationFrequency;
sRow="Iteration frequency (Hz)"+ sSep+dspCodeIterationFrequency.ToString();
fWrite.WriteLine(sRow);
sRow = "Object" + sSep + "Type" + sSep+ "Address" + sSep + "Size (hex)" + sSep + "Size (dec)" +sSep+sSep
+"BufferList"+sSep + "Size (hex)" + sSep + "Size (dec)"
+ sSep + "Buffer " + sSep + "Size (hex)" + "Size (dec)" ;
fWrite.WriteLine(sRow);
//
IDSP Dsp = MultiSystemController.Instance.Dsp;
var memory = ((MultiSystemController.Instance.Dsp as IDSPObjectSupport).DriverMemory as DSPDriver);
IDSPObject oRamper=null;
foreach (IDSPObject o in Dsp.DSPObjects) {
string sName= o.Name;
string sType=o.GetType().ToString();
if (sType.StartsWith("Servotest.D2R.DspUsb.")) { // which it does
sType=sType.Substring(21);
}
Address aAddress = 0;
int nSize= 0;
IMemoryBlock block=o.Block;
if (block!=null) {
aAddress=block.Address;
nSize=block.SizeInWords;
}
uint iAddress= 0;
Word wBuffer;
uint iBuffer;
iAddress=aAddress;
nSize *=4 ;
sRow = sName+ sSep+ sType + sSep + "0x" +iAddress.ToString("X8") + sSep + "0x"+ nSize.ToString("X") + sSep + nSize.ToString();
if (sType == "Scope") {
wBuffer = block[15]; //?
iBuffer = wBuffer.UIntValue;
//iAddress += (15 * 4 ) ; // buffer address
// this is hard coded in scope
uint size = 2048 * 4 ;
sRow += sSep +sSep + sSep + sSep +sSep + sSep + "0x" +iBuffer.ToString("X8") +sSep + "0x"+ size.ToString("X") + sSep + size.ToString(); ;
}
if (sType == "DataLogger") {
sRow += sSep;
int highestBuffer= block[7].IntValue;
uint BufferList = block[8].UIntValue;
TraceHelper.WriteLine(TraceCategory.Info, "logger high buffer"+ highestBuffer.ToString() + " List:"+BufferList.ToString("X") );
Address aBuffPrev=0 ;
uint uStart=0;
int size=0;
int nBuffers = highestBuffer+1;
int nBufferSize = nBuffers * 4;
for (int jBuffer =0 ; jBuffer <= highestBuffer ; jBuffer ++) {
Address aBuffer= new Address(BufferList);
uint iABuffer = (uint) aBuffer.IntValue;
Word wBuffa = memory.Read(aBuffer);
uint uBuffa= wBuffa.UIntValue;
// only print non contiguous
if (jBuffer==0) {
sRow += sSep + "0x"+ iABuffer.ToString("X8") + sSep+ "0x" + nBufferSize.ToString("X") + sSep +nBufferSize.ToString()+ sSep + sSep + "0x" +uBuffa.ToString("X8");
uStart =uBuffa;
}
else {
if (uBuffa != uStart+size * 4 ) {
// not contiguous // these may be messy
sRow += sSep + "0x" +size.ToString("X8") + sSep + size.ToString() +sSep + sSep +uBuffa.ToString("X8");
uStart = uBuffa;
size=0;
}
}
TraceHelper.WriteLine (TraceCategory.Info, aBuffer.ToString()+" "+ uBuffa.ToString("X8"));
BufferList+=4;
size+=512 ; // words
}
sRow += sSep + "0x" +size.ToString("X") + sSep + size.ToString(); ;// final size
}
if (sType == "EnduranceDataLogger") {
sRow += sSep;
int highestBuffer= block[6].IntValue;
uint BufferList = block[7].UIntValue;
TraceHelper.WriteLine(TraceCategory.Info, "logger high buffer"+ highestBuffer.ToString() + " List:"+BufferList.ToString("X") );
Address aBuffPrev=0 ;
uint uStart=0;
int size=0;
int nBuffers = highestBuffer+1;
int nBufferSize = nBuffers * 4;
for (int jBuffer =0 ; jBuffer <= highestBuffer ; jBuffer ++) {
Address aBuffer= new Address(BufferList);
uint iABuffer = (uint) aBuffer.IntValue;
Word wBuffa = memory.Read(aBuffer);
uint uBuffa= wBuffa.UIntValue;
// only print non contiguous
if (jBuffer==0) {
sRow += sSep + "0x"+ iABuffer.ToString("X8") + sSep+ "0x" + nBufferSize.ToString("X") + sSep +nBufferSize.ToString()+ sSep + sSep + "0x" +uBuffa.ToString("X8");
uStart =uBuffa;
}
else {
if (uBuffa != uStart+size * 4 ) {
// not contiguous // these may be messy
sRow += sSep + "0x" +size.ToString("X8") + sSep + size.ToString() +sSep + sSep +uBuffa.ToString("X8");
uStart = uBuffa;
size=0;
}
}
TraceHelper.WriteLine (TraceCategory.Info, aBuffer.ToString()+" "+ uBuffa.ToString("X8"));
BufferList+=4;
size+=512 ; // words
}
sRow += sSep + "0x" +size.ToString("X") + sSep + size.ToString(); ;// final size
}
if (sType == "Replayer") {
uint iABuffer = block[4].UIntValue;
uint nSamplesInBuffer = block[12].UIntValue; // floats
uint nBytes= nSamplesInBuffer * 4;
sRow += sSep+sSep+sSep+sSep+sSep +sSep + "0x"+iABuffer.ToString("X8") +sSep + "0x" +nBytes.ToString("X") +sSep + nBytes.ToString();
}
fWrite.WriteLine(sRow);
}
if (fWrite!=null) fWrite.Close();
return true;