Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
documents:de4000:de4000script [2022/01/24 16:24]
rocky [1. ]
documents:de4000:de4000script [2022/01/25 16:22] (current)
twebster
Line 1: Line 1:
-Scripting Reference Manual +=====DE-4000 SCRIPTING REFERENCE MANUAL=====
-DE-4000 Series Configurable Safety Shutdown and Control System +
-Form DE-4000 SRM 06-20+
  
 +There is a delicate balance between providing a system that has capabilities that can be configured through a fixed set of options, and one that can be extended and expanded with custom programming. In designing the DE-4000 control system, the choice was made to provide a system where most applications can be met with simple configuration, but advanced functionality can be provided through custom programming using the "Lua" language.
  
-DE-4000 SCRIPTING REFERENCE MANUAL +Lua is often referred to as a scripting language. Scripting languages differ from compiled languages as they eliminate extra step of compiling the written program into machine code
- + 
-One overarching capability that allows bridge to gap the standard needs of everyday +
-systems and the customer needs of innovation is scripting. A scripting language+
-cleverly named Lua, is embedded into the DE-4000 systemIt operates as a script +
-mainly meaning that it does not need additional tools to convert the “code” into +
-machine languageIt also is looked at and corrected for errors every time the script +
-runs. Therefore it is an “interpreted” language and runs all of the time when you ask it.+
 Lua comes with a background of being robust, fast, and geared towards embedded Lua comes with a background of being robust, fast, and geared towards embedded
 applications, with a proven track record in the gaming industry. For the DE-4000 applications, with a proven track record in the gaming industry. For the DE-4000
Line 44: Line 37:
  
  
-===== - ===== +===== - Choose “Global” from menu on left side of screen ===== 
-Choose “Global” from menu on left side of screen+{{:documents:de4000:scripting_dashboard_2.jpg?400|}}
  
-===== - ===== 
-In the Sub-Menu on the Left side select “Scripts” 
  
-===== - ===== +===== - In the Sub-Menu on the Left side select “Scripts” ===== 
-Select one of the page icons under one of the 4 script options to open editor+{{:documents:de4000:scripting_dashboard_3.jpg?400|}}
  
-===== - ===== 
- Scripting can be entered into the editor. 
  
-<markdown>### DE4000 Lua Script API+===== - Select one of the page icons under one of the 4 script options to open editor ===== 
 +{{:documents:de4000:scripting_dashboard_4.jpg?400|}} 
 + 
 +===== -  Scripting can be entered into the editor ===== 
 +{{:documents:de4000:scripting_dashboard_5.jpg?400|}} 
 + 
 + 
 +**Scripting Windows and examples** 
 + 
 +**Master Script** 
 +{{:documents:de4000:scripting_dashboard_master_script.jpg?90|}}  The Master Script section is the Primary scripting environment. 
 +Primary scripting functions can be written in this section. 
 + 
 +**Example:** 
 +<code lua> 
 +local suction = get_channel_val(1,1) 
 +local discharge1 = get_channel_val(1,3) 
 +diff = discharge1 - suction 
 +set_sVirt(“Difference”, diff) 
 +</code> 
 + 
 +The first line gets the channel value from Terminal board 1 Input 1 and stores it 
 +in local variable named suction. 
 +The second line gets the channel value from Terminal board 1 Input 3 and stores 
 +it in local variable named discharge1. 
 +The third line takes the discharge1 pressure and subtracts the suction pressure 
 +and stores it in the global variable named diff (NOTE: Any value that you want to 
 +access from another scripting section must be stored in a global variable. This is 
 +used most in calling values into Modbus registers as explained below). 
 +The fourth line copies the value from diff and stores it into the Virtual status 
 +channel named “Difference” This channel can be displayed on the Dashboard. 
 + 
 +**Control Script** 
 +{{:documents:de4000:scripting_dashboard_control_script.jpg?90|}} 
 +The Control Script section is used to override the default control 
 +strategy found on the Global/Control page. A copy of the default 
 +control script (found in attached appendix) can be copied into this 
 +section and then modified to change the control functionality as well 
 +as add additional control loops beyond the default 2. 
 + 
 +{{:documents:de4000:scripting_dashboard_control_script_2.jpg?400|}} 
 + 
 +**Modbus Script** 
 +{{:documents:de4000:scripting_dashboard_modbus_script.jpg?90|}} 
 +The Modbus Script section is used to move data into and out of 
 +Modbus registers 
 + 
 +{{:documents:de4000:scripting_dashboard_modbus_script_2.jpg?400|}} 
 + 
 +<code lua> 
 +defaultModbus() 
 +set_modbus(300,diff) 
 +</code> 
 + 
 +The first line pulls in the factory set Modbus mapping 
 +The second line moves the value from the global variable named diff into the 
 +40300 Modbus Register 
 + 
 +==== - DE4000 Lua Script API ==== 
 +<markdown> 
 +**CUSTOM FUNCTIONS FOR SCRIPTING**
  
 --- ---
Line 306: Line 355:
  
 </markdown> </markdown>
 +==== - Master Control Script ====
 +
 +{{ :documents:de4000:control.jpg?nolink&600 |}}
 +
 +When you enter a control setup under the Global Control page the code that runs is called MasterControl.
 +
 +If you wish to modify this functionality you can copy this code into the Control Script editor and{{ :documents:de4000:scripting_dashboard_control_script.jpg?nolink|}} make your changes to the standard configuration.
 +
 +
 +<file lua [enable_line_numbers="true"] mastercontrol.lua>
 +  local rampRate1 = get_gbl("rampRate1",0.8)
 +  local rampRate2 = get_gbl("rampRate2",0.8)
 +  local dischTerm = tonumber_def(get_gbl("spDischTerm",0),0)
 +  local dischChan = tonumber_def(get_gbl("spDischChan",0),0)
 +  local suctTerm = tonumber_def(get_gbl("spSuctTerm",0),0)
 +  local suctChan = tonumber_def(get_gbl("spSuctChan",0),0)
 +  local suctMin = tonumber_def(get_gbl("suctMin",0),0)
 +  local recycleMin = tonumber_def(get_gbl("recycleMin",0),0)
 +  local recycleMax = tonumber_def(get_gbl("recycleMax",0),0)
 +  local suctSp = tonumber_def(get_gbl("suctSp",0),0)
 +  local dischMax = tonumber_def(get_gbl("dischMax",0),0)
 +  local dischSp = tonumber_def(get_gbl("dischSp",0),0)
 +  local outputTerm = tonumber_def(get_gbl("outputTerm",0),0)
 +  local outputChan = tonumber_def(get_gbl("outputChan",0),0)
 +  local recycleTerm = tonumber_def(get_gbl("outputTerm2",0),0)
 +  local recycleChan = tonumber_def(get_gbl("outputChan2",0),0)
 +  local speedRevAct = tonumber_def(get_gbl("speedRevAct",0),0)
 +  local recycleRevAct = tonumber_def(get_gbl("recycleRevAct",0),0)
 +  local outputLow = tonumber_def(get_gbl("outputLow",0),0)
 +  local outputLow2 = tonumber_def(get_gbl("outputLow2",0),0)
 +  local outputHigh = tonumber_def(get_gbl("outputHigh",0),0)
 +  local outputHigh2 = tonumber_def(get_gbl("outputHigh2",0),0)
 +  local spSuctType = get_gbl("spSuctType","linear")
 +  local spDischType = get_gbl("spDischType","linear")
 +  local suctPIDPFactor = tonumber_def(get_gbl("suctPIDPFactor",0),0)
 +  local suctPIDIFactor = tonumber_def(get_gbl("suctPIDIFactor",0),0)
 +  local suctPIDDFactor = tonumber_def(get_gbl("suctPIDDFactor",0),0)
 +  local dischPIDPFactor = tonumber_def(get_gbl("dischPIDPFactor",0),0)
 +  local dischPIDIFactor = tonumber_def(get_gbl("dischPIDIFactor",0),0)
 +  local dischPIDDFactor = tonumber_def(get_gbl("dischPIDDFactor",0),0)
 +  local recycleCtrl = false
 +  local recycleSuctionRev = false
 +  local recycleDischargeRev = false
 +  if recycleChan > 0 and recycleTerm > 0 then
 +    recycleCtrl = true
 +  end
 + 
 +  local dischPct = 100
 +  local suctPct = 100
 +
 +
 +  local dischOutput = 0
 +  local suctOutput = 0
 +  local rSuctOutput = 0
 +  local rDischOutput = 0
 +  local minLoad = 0
 +  local maxLoad = 100
 +  local minRecycle = 0
 +  local maxRecycle = 100
 +  local speedTarget = get_sGbl("speedTarget",0)
 +  local recycleTarget = get_sGbl("recycleTarget",0)
 +
 +  function map_range(rangeLow,rangeHigh,input)
 +    if input <= rangeLow and input <= rangeHigh then
 +      return 0
 +    end
 +    if input >= rangeLow and input >= rangeHigh then
 +      return 100
 +    end
 +    local rangeDiff = math.abs(rangeLow - rangeHigh)
 +    local min = math.min(rangeLow,rangeHigh)
 +    local retval = math.abs(input - min) / rangeDiff * 100
 +    if retval > 100 then retval = 100 end
 +    if retval < 0 then retval = 0 end
 +    return retval
 +  end
 +
 +  local suct = false
 +  local suctVal = 0
 +  if tonumber_def(get_gbl("spSuctEn",0),0) == 1 then
 +    if suctTerm > 0 and suctChan > 0 then
 +      suctVal = get_channel_val(suctTerm,suctChan)
 +      suct = true
 +    end
 +  end
 +
 +
 +  if suct then
 +    if spSuctType == "linear" then
 +      local suctDiff = suctSp - suctMin
 +      if suctDiff == 0 then suctDiff = 1 end
 +      if suctVal < suctSp then
 +        local suctErr = suctSp - suctVal
 +        suctPct = suctErr / suctDiff
 +        if suctPct > 1 then suctPct = 1 end
 +        if suctPct < 0 then suctPct = 0 end
 +        suctOutput = (1 - suctPct) * 100
 +      else
 +        suctOutput = 100
 +      end
 +    else
 +      set_gbl("PIDsuctEnable",1)
 +      set_gbl("PIDsuctPFactor",suctPIDPFactor)
 +      set_gbl("PIDsuctIFactor",suctPIDIFactor)
 +      set_gbl("PIDsuctDFactor",suctPIDDFactor)
 +      set_gbl("PIDsuctSp",suctSp)
 +      set_gbl("PIDsuctDeadband",0.2)
 +      local suctPidOutput = doPid("suct",suctVal)
 +      suctOutput = suctPidOutput
 +    end
 +  else
 +    suctOutput = 100
 +  end
 +
 +
 +  local disch = false
 +  local dischVal = 0
 +  if tonumber_def(get_gbl("spDischEn",0),0) == 1 then
 +    if dischTerm > 0 and dischChan > 0 then
 +        dischVal = get_channel_val(dischTerm,dischChan)
 +        disch = true
 +    end
 +  end
 +  if disch then
 +    if spDischType == "linear" then
 +      local dischDiff = dischMax - dischSp
 +      if dischDiff == 0 then dischDiff = 1 end
 +      if dischVal > dischSp then
 +        local dischErr = dischVal - dischSp
 +        dischPct = dischErr / dischDiff
 +        if dischPct > 1 then dischPct = 1 end
 +        if dischPct < 0 then dischPct = 0 end
 +        dischOutput = (1 - dischPct) * 100
 +      else
 +        dischOutput = 100
 +      end
 +    else
 +      set_gbl("PIDdischEnable",1)
 +      set_gbl("PIDdischPFactor",dischPIDPFactor)
 +      set_gbl("PIDdischIFactor",dischPIDIFactor)
 +      set_gbl("PIDdischDFactor",dischPIDDFactor)
 +      set_gbl("PIDdischSp",dischSp)
 +      set_gbl("PIDdischRevAct",1)
 +      set_gbl("PIDdischDeadband",0.2)
 +      local dischPidOutput = doPid("disch",dischVal)
 +      dischOutput = dischPidOutput
 +    end
 +  else
 +    dischOutput = 100
 +  end
 +
 +  
 +  local minOutput = 100
 +  local winning = 0
 +  if suctOutput < minOutput then
 +    minOutput = suctOutput
 +    winning = 1
 +  end
 +  if dischOutput < minOutput then
 +    minOutput = dischOutput
 +    winning = 2
 +  end
 +
 +  if suctOutput == dischOutput then
 +    winning = 0
 +  end
 +
 +  if winning == 0 then
 +    set_gbl("PIDsuctMax",100)
 +    set_gbl("PIDdischMax",100)
 +  end
 +
 +  if winning == 1 then
 +    set_gbl("PIDdischMax",math.min(suctOutput + 2,100))
 +    set_gbl("integraldisch",0)
 +    set_gbl("lastErrdisch",0)
 +    set_gbl("outputSumdisch",0)
 +    set_gbl("PIDsuctMax",100)
 +  end
 +  if winning == 2 then
 +    set_gbl("PIDsuctMax",math.min(dischOutput + 2,100))
 +    set_gbl("integralsuct",0)
 +    set_gbl("lastErrsuct",0)
 +    set_gbl("outputSumsuct",0)
 +    set_gbl("PIDdischMax",100)
 +  end
 +
 +  local recycleMinOutput = minOutput
 +
 +  local manOutput = 0
 +  --********************************************************************
 +  local manMode = 0
 +  local manTerm = tonumber_def(get_gbl("manTerm",0),0)
 +  local manChan = tonumber_def(get_gbl("manChan",0),0)
 +  if manTerm > 0 and manChan > 0 then
 +    local manInput = get_channel_val(manTerm,manChan)
 +    if manInput > 0.5 then
 +      manMode = 0
 +      set_sVirt("SpeedControl","Auto")
 +    else
 +      manMode = 1
 +      set_sVirt("SpeedControl","Manual")
 +    end
 +  else
 +    if get_sVirt("SpeedControl","Auto") == "Auto" then
 +      manMode = 0
 +    else
 +      manMode = 1
 +    end
 +  end
 +
 +  --if manMode == 1 and get_state() == 8 then
 +  local manSpeed = get_sVirt("ManualSpeed",0)
 +  local idleSpeed = get_gbl("idleSpeed",0)
 +  local lowSpeed = get_gbl("lowSpeed",0)
 +  local highSpeed = get_gbl("highSpeed",0)
 +  local maxSpeed = get_gbl("maxSpeed",0)
 +  local diff = highSpeed - lowSpeed
 +  if diff < 0 then diff = 0 end
 +  local maxDiff = maxSpeed - idleSpeed
 +  if maxDiff < 0 then maxDiff = 0 end
 +
 +  if get_sVirt("speedBump",0) ~= 0 then
 +    local si = get_gbl("SpeedIncrement",0)
 +    local sip = get_param("SpeedIncrement",0)
 +    if sip ~= 0 then si = sip end
 +    manSpeed = manSpeed + (si * get_sVirt("speedBump",0))
 +    set_sVirt("speedBump",0)
 +  end
 +
 +  if get_sVirt("AutoManBump",0) > 0 then
 +    set_sVirt("SpeedControl","Auto")
 +    set_sVirt("AutoManBump",0)
 +  end
 +
 +  if get_sVirt("AutoManBump",0) < 0 then
 +    set_sVirt("SpeedControl","Manual")
 +    set_sVirt("AutoManBump",0)
 +  end
 +
 +  if manMode == 1 then
 +    local manSpeedTerm = tonumber_def(get_gbl("manSpeedTerm",0),0)
 +    local manSpeedChan = tonumber_def(get_gbl("manSpeedChan",0),0)
 +    if manSpeedTerm > 0 and manSpeedChan > 0 then --*** USE SPEED POT TO SET SPEED
 +      local speedInput = tonumber(get_channel_val(manSpeedTerm,manSpeedChan))
 +      local speedPct = (speedInput / 5) * 100
 +      if speedPct > 100 then speedPct = 100 end
 +      if speedPct < 0 then speedPct = 0 end
 +      manOutput = speedPct
 +      manSpeed = math.floor((speedPct / 100) * diff + lowSpeed + 0.5)
 +    else -- Use ManualSpeed to set speed
 +      manOutput = ((manSpeed - lowSpeed) / diff) * 100.0
 +      if manOutput < 0 then manOutput = 0 end
 +      if manOutput > 100 then manOutput = 100 end
 +    end
 +    minOutput = manOutput
 +  else
 +    --speedTarget =
 +    local stRpm = (speedTarget/100) * maxDiff + idleSpeed
 +    if stRpm < lowSpeed then stRpm = lowSpeed end
 +    if stRpm > highSpeed then stRpm = highSpeed end
 +    manSpeed = math.floor(stRpm)
 +  end
 +
 +  if manSpeed < lowSpeed then
 +    manSpeed = lowSpeed
 +  end
 +  if manSpeed > highSpeed then
 +    manSpeed = highSpeed
 +  end
 +
 +  set_sVirt("ManualSpeed",manSpeed)
 +
 +
 +
 +  --********************************************************************
 +
 +
 +  local output1 = 0
 +  local output2 = 0
 +  if spSuctType == "pid" or spDischType == "pid" then
 +    output1 = map_range(outputLow,outputHigh,minOutput)
 +    set_sVirt("out1",output1)
 +    output2 = map_range(outputLow2,outputHigh2,recycleMinOutput)
 +    set_sVirt("out2",output2)
 +    local hasRPM = idleSpeed > 0 and lowSpeed > 0 and highSpeed > 0 and maxSpeed > 0
 +    if outputTerm and outputChan then
 +      if hasRPM then
 +        local speedRpm = output1 / 100  * (highSpeed - lowSpeed) + lowSpeed
 +        speedTarget = (speedRpm - idleSpeed) / (maxSpeed - idleSpeed) * 100
 +      else
 +        speedTarget = output1
 +      end
 +    end
 +    if recycleTerm and recycleChan then
 +      set_ao_val(recycleTerm,recycleChan,output2)
 +    end
 +
 +    if get_state() == 9 then
 +      speedTarget = get_sGbl("speedTarget",0)
 +      if speedTarget > 0 then speedTarget = speedTarget - rampRate1 end
 +      if speedTarget < 0 then speedTarget = 0 end
 +    end
 +    if get_state() < 8 then speedTarget = 0 end
 +    set_sGbl("speedTarget",speedTarget)
 +    set_ao_val(outputTerm,outputChan,speedTarget)
 +    set_sVirt("spTarget",speedTarget)
 +
 +    if hasRPM then
 +      local sRpm = (speedTarget/100) * maxDiff + idleSpeed
 +      set_sVirt("Speed Target",math.floor(sRpm + 0.5))
 +    end
 +
 +
 +
 +  else
 +
 +    -- Remember that minOutput is 0 - 100 pct of lowSpeed <-> highSpeed
 +    -- We need to convert this to 0 - 100 pct of idleSpeed <-> maxSpeed
 +    local suctPct = map_range(outputLow,outputHigh,minOutput)
 +    local speedRpm = suctPct / 100  * (highSpeed - lowSpeed) + lowSpeed
 +    minOutput = (speedRpm - idleSpeed) / (maxSpeed - idleSpeed) * 100
 +
 +
 +
 +    if minOutput <= speedTarget then
 +      speedTarget = speedTarget - rampRate1
 +      if speedTarget < minOutput then speedTarget = minOutput end
 +    else
 +        speedTarget = speedTarget + rampRate1
 +        if speedTarget > minOutput then speedTarget = minOutput end
 +        if speedTarget > maxLoad then speedTarget = maxLoad end
 +    end
 +    if speedTarget > maxLoad then speedTarget = maxLoad end
 +    if speedTarget < minLoad then speedTarget = minLoad end
 +
 +    if recycleCtrl then
 +      local recyclePct = map_range(outputLow2,outputHigh2,recycleMinOutput)
 +      if recyclePct <= recycleTarget then
 +        recycleTarget = recycleTarget - rampRate2
 +        if recycleTarget < recyclePct then recycleTarget = recyclePct end
 +      else
 +        recycleTarget = recycleTarget + rampRate2
 +        if recycleTarget > recyclePct then recycleTarget = recyclePct end
 +      end
 +      if recycleTarget > maxRecycle then recycleTarget = maxRecycle end
 +      if recycleTarget < minRecycle then recycleTarget = minRecycle end
 +      local recycleOutput = recycleTarget
 +      if get_state() < 8 then
 +        recycleTarget = 0
 +      end
 +      if recycleRevAct == 1 then
 +        recycleOutput = 100 - recycleOutput
 +      end
 +      set_ao_val(recycleTerm,recycleChan,recycleOutput)
 +      set_sGbl("recycleTarget",recycleTarget)
 +      set_sVirt("recycleTarget",recycleTarget)
 +    end
 +
 +    if get_state() == 9 then
 +      speedTarget = get_sGbl("speedTarget",0)
 +      if speedTarget > 0 then speedTarget = speedTarget - rampRate1 end
 +      if speedTarget < 0 then speedTarget = 0 end
 +    end
 +    if get_state() < 8 then speedTarget = 0 end
 +    set_sGbl("speedTarget",speedTarget)
 +    set_ao_val(outputTerm,outputChan,speedTarget)
 +    set_sVirt("spTarget",speedTarget)
 +    local sRpm = (speedTarget/100) * maxDiff + idleSpeed
 +    set_sVirt("Speed Target",math.floor(sRpm + 0.5))
 +
 +
 +  end
 +
 +</file>