Files
saomad-kairos-mk3/Saomad-KAIROS-MK3.mlse
2026-03-18 15:32:13 +01:00

2370 lines
99 KiB
Plaintext

-- Special Operations macchina Saomad-KAIROS by EgalWare s.r.l. 2023/12/01
-- Intestazioni
require( 'EmtGenerator')
EgtEnableDebug( false)
-- Carico i dati globali
local sBaseDir = EgtGetCurrMachineDir()
local BD = dofile( sBaseDir .. '\\Beam\\BeamData.lua')
---------------------------------------------------------------------
-- *** Generic Machinings ***
---------------------------------------------------------------------
pcall( require, 'EmtGenMachining') -- si fa una require con PCALL perchè la libreria è opzionale
---------------------------------------------------------------------
-- *** Special Link moves ***
---------------------------------------------------------------------
-----------------------------------------------------------------------------------------
function OnSpecialLink()
-- se fresa su testa 1
if EMC.HEAD == 'H1' then
-- se inizio lavorazione con prelievo utensile
if EMC.LINKTYPE == 1 then
-- se fine lavorazione con deposito utensile
elseif EMC.LINKTYPE == 2 then
-- altrimenti collegamento tra due lavorazioni (3)
else
end
-- se motosega
elseif EMC.HEAD == 'H3' then
end
EMC.ERR = 0
end
---------- OnSpecialApplyDisposition & OnPostApplyMachining ---------
----------------------- Costanti ------------------------------------
local AGG_LOAD = 0
local MaxLenSmT = 1500 -- massima lunghezza pezzo scaricato con nastri verdi
----------------------- Variabili -----------------------------------
local Test = false
---------------------------------------------------------------------
local function PrepareClGroup( nParentId)
local nClId = EgtGetFirstNameInGroup( nParentId, 'CL')
-- se non c'è, lo aggiunge
if not nClId then
nClId = EgtGroup( EMC.DISPID)
if not nClId then
return nil
end
EgtSetName( nClId, 'CL')
-- altrimenti lo svuoto
else
EgtEmptyGroup( nClId)
end
return nClId
end
---------------------------------------------------------------------
local function IsStartPhase( nPhase)
local sVal = EgtGetInfo( EgtGetPhaseDisposition( nPhase) or GDB_ID.NULL, 'TYPE')
return ( sVal == 'START')
end
---------------------------------------------------------------------
local function IsStartOrRestPhase( nPhase)
local sVal = EgtGetInfo( EgtGetPhaseDisposition( nPhase) or GDB_ID.NULL, 'TYPE')
return ( sVal == 'START' or sVal == 'REST')
end
---------------------------------------------------------------------
local function IsMidPhase( nPhase)
local sVal = EgtGetInfo( EgtGetPhaseDisposition( nPhase) or GDB_ID.NULL, 'TYPE')
return ( sVal == 'MID')
end
---------------------------------------------------------------------
local function IsEndPhase( nPhase)
local sVal = EgtGetInfo( EgtGetPhaseDisposition( nPhase) or GDB_ID.NULL, 'TYPE')
return ( sVal == 'END')
end
---------------------------------------------------------------------
local function IsMid2Phase( nPhase)
local sVal = EgtGetInfo( EgtGetPhaseDisposition( nPhase) or GDB_ID.NULL, 'TYPE')
return ( sVal == 'MID2')
end
---------------------------------------------------------------------
local function IsEnd2Phase( nPhase)
local sVal = EgtGetInfo( EgtGetPhaseDisposition( nPhase) or GDB_ID.NULL, 'TYPE')
return ( sVal == 'END2')
end
---------------------------------------------------------------------
local function GetNextStartOrRestPhase( nPhase)
local nNextPhase = nPhase + 1
while nNextPhase <= EgtGetPhaseCount() do
if IsStartOrRestPhase( nNextPhase) then
break ;
end
nNextPhase = nNextPhase + 1
end
return nNextPhase
end
---------------------------------------------------------------------
local function GetPhaseRot( nPhase)
return ( EgtGetInfo( EgtGetPhaseDisposition( nPhase) or GDB_ID.NULL, 'ROT', 'i') or 0)
end
---------------------------------------------------------------------
local function IsLastOperationBeforeRotation( nOperId)
-- se ultima fase o ultima fase del pezzo, ritorno risultato negativo
if EMC.PHASE == EgtGetPhaseCount() or IsEndPhase( EMC.PHASE) or IsEnd2Phase( EMC.PHASE) then
return false
end
-- recupero la successiva operazione attiva
local nNextOperId = EgtGetNextActiveOperation( nOperId)
-- se non esiste o non è una disposizione, ritorno risultato negativo
if not nNextOperId or EgtGetOperationType( nNextOperId) ~= MCH_OY.DISP then
return false
end
-- recupero le rotazioni della fase corrente e della prossima fase
local nRot = GetPhaseRot( EMC.PHASE)
local nNextRot = GetPhaseRot( EMC.PHASE + 1)
-- ritorno se sono diverse
return ( nRot ~= nNextRot)
end
---------------------------------------------------------------------
local function IsFirstMachiningAfterRotation( nMchId)
-- se prima fase o prima fase del pezzo, ritorno risultato negativo
if EMC.PHASE == 1 or IsStartOrRestPhase( EMC.PHASE) then
return false
end
-- recupero la precedente operazione attiva
local nPrevOperId = EgtGetPrevActiveOperation( nMchId)
-- se non esiste o non è una disposizione, ritorno risultato negativo
if not nPrevOperId or EgtGetOperationType( nPrevOperId) ~= MCH_OY.DISP then
return false
end
-- recupero le rotazioni della fase corrente e della fase precedente
local nRot = GetPhaseRot( EMC.PHASE)
local nPrevRot = GetPhaseRot( EMC.PHASE - 1)
-- ritorno se sono diverse
return ( nRot ~= nPrevRot)
end
---------------------------------------------------------------------
local function GetCUTID()
-- recupero CUTID del pezzo in lavoro
local nOrd = GetPhaseOrd( EMC.PHASE)
local nPartRawId
local nRawId = EgtGetFirstRawPart()
while nRawId do
local nRawOrd = EgtGetInfo( nRawId, 'ORD', 'i')
if nRawOrd == nOrd then
nPartRawId = nRawId
break
end
nRawId = EgtGetNextRawPart( nRawId)
end
local CutID = EgtGetInfo( EgtGetFirstPartInRawPart( nPartRawId or GDB_ID.NULL) or GDB_ID.NULL, 'CUTID', 'i') or 0
return CutID
end
---------------------------------------------------------------------
local function AddZmaxMove( vCmd)
table.insert( vCmd, { 1, 'Z', EgtGetAxisHomePos( 'Z')})
return vCmd
end
---------------------------------------------------------------------
local function EmitComment( vCmd, sOut)
EgtOutLog( ' ' .. sOut, 1)
if Test then
table.insert( vCmd, { 0, sOut})
end
end
---------------------------------------------------------------------
function OnSpecialApplyDisposition()
EgtOutLog( ' *** Fase : ' .. EgtNumToString( EMC.PHASE, 0) .. ' ***', 1)
-- Inizializzo codice di errore
EMC.ERR = 0
-- Campi obbligatori ma non usati
EMC.HEAD = ""
EMC.EXIT = 1
EMC.TCPOS = ""
EMC.SHIFTS = 0
EMC.SBH = false
-- Se disposizione da saltare non devo fare alcunché
if EgtExistsInfo( EMC.DISPID, 'SKIP') then return end
-- Assegno flag di pezzo separato dal resto del grezzo
local bSplit = IsEndPhase( EMC.PHASE) or IsMid2Phase( EMC.PHASE) or IsEnd2Phase( EMC.PHASE)
-- Recupero il tipo dell'operazione successiva
local nNextOpeType = EgtGetOperationType( EgtGetNextActiveOperation( EMC.DISPID) or GDB_ID.NULL)
-- Se ci sono lavorazioni successive non devo fare alcunché
if nNextOpeType ~= MCH_OY.NONE and nNextOpeType ~= MCH_OY.DISP then return end
-- Imposto gruppo e path di movimento
local nClId = PrepareClGroup( EMC.DISPID)
if not nClId then
EMC.ERR = 3
return
end
local nPathId = EgtGroup( nClId)
if not nPathId then
EMC.ERR = 6
return
end
EgtSetName( nPathId, 'Empty')
EMC.PATHID = nPathId
EMC.SHIFTS = -1
-- Se l'operazione successiva è una disposizione con rotazione, devo preparare il pezzo alla rotazione
if IsLastOperationBeforeRotation( EMC.DISPID) then
-- aggiornamento posizioni
if IsStartPhase( EMC.PHASE) then
-- carico le posizioni
local dPosT = EgtGetInfo( EMC.DISPID, 'TPOS', 'd')
local dPosX1 = EgtGetInfo( EMC.DISPID, 'X1POS', 'd')
EMC.TPOS = dPosT
EMC.X1DELTA = dPosX1 - dPosT
EMC.X2DELTA = nil
else
local nPrevOpeId = EgtGetPrevActiveOperation( EMC.DISPID)
local nLastPathId = EgtGetLastInGroup( EgtGetFirstNameInGroup( nPrevOpeId, 'CL') or GDB_ID.NULL)
local nLastEntId = EgtGetLastInGroup( nLastPathId)
local vAxes = EmtGetAxesPos( nLastEntId)
if #vAxes > 0 then EMC.TPOS = vAxes[1] end
EMC.X1DELTA = EgtGetInfo( nLastPathId, 'X1DELTA', 'd')
EMC.X2DELTA = EgtGetInfo( nLastPathId, 'X2DELTA', 'd')
EMC.DISTFRONT = EgtGetInfo( nLastPathId, 'DISTFRONT', 'd') or 0
EMC.DISTBACK = EgtGetInfo( nLastPathId, 'DISTBACK', 'd') or 0
end
-- Determinazione delle dimensioni del grezzo in lavoro
local b3Raw = BBox3d()
local nRawId = EgtGetFirstRawPart()
while nRawId do
if EgtVerifyRawPartPhase( nRawId, EMC.PHASE) then
b3Raw = EgtGetRawPartBBox( nRawId)
break
end
nRawId = EgtGetNextRawPart( nRawId)
end
EMC.LENGTHBEAM = b3Raw:getDimX() + 10 * GEO.EPS_SMALL
-- Assegno sovramateriale di testa e ingombro tagli di testa e di coda
EMC.HOVM = EgtGetInfo( nRawId, 'HOVM', 'd') or 0
EMC.HCING = 0
EMC.TCING = EgtGetInfo( nRawId, 'TCING', 'd') or 0
-- Eseguo preparazione alla rotazione
local vCmd = SpecCalcPreRot()
SpecOutputCmds( vCmd, true)
return
end
-- Se l'operazione successiva è ancora una disposizione, devo scaricare il pezzo
if nNextOpeType == MCH_OY.DISP and bSplit and not IsEnd2Phase( EMC.PHASE) then
-- aggiornamento posizioni
local nPrevOpeId = EgtGetPrevActiveOperation( EMC.DISPID)
local nLastPathId = EgtGetLastInGroup( EgtGetFirstNameInGroup( nPrevOpeId, 'CL') or GDB_ID.NULL)
local nLastEntId = EgtGetLastInGroup( nLastPathId)
local vAxes = EmtGetAxesPos( nLastEntId)
if #vAxes > 0 then EMC.TPOS = vAxes[1] end
EMC.X1DELTA = EgtGetInfo( nLastPathId, 'X1DELTA', 'd')
EMC.X2DELTA = EgtGetInfo( nLastPathId, 'X2DELTA', 'd')
EMC.DISTFRONT = EgtGetInfo( nLastPathId, 'DISTFRONT', 'd') or 0
EMC.DISTBACK = EgtGetInfo( nLastPathId, 'DISTBACK', 'd') or 0
-- Determinazione delle dimensioni del grezzo in lavoro
local b3Raw = BBox3d()
local nRawId = EgtGetFirstRawPart()
while nRawId do
if EgtVerifyRawPartPhase( nRawId, EMC.PHASE) and not EgtVerifyRawPartPhase( nRawId, EMC.PHASE + 1) then
b3Raw = EgtGetRawPartBBox( nRawId)
break
end
nRawId = EgtGetNextRawPart( nRawId)
end
EMC.LENGTHBEAM = b3Raw:getDimX() + 10 * GEO.EPS_SMALL
EMC.HOVM = EgtGetInfo( nRawId or GDB_ID.NULL, 'HOVM', 'd') or 0
-- Eseguo scarico
local vCmd = SpecCalcUnload()
SpecOutputCmds( vCmd, true)
return
end
-- Verifico ci sia un solo grezzo nella fase corrente
local nRawCount = 0
local nCurrRawId = GDB_ID.NULL
local nRawId = EgtGetFirstRawPart()
while nRawId do
if EgtVerifyRawPartPhase( nRawId, EMC.PHASE) then
nRawCount = nRawCount + 1
nCurrRawId = nRawId
end
nRawId = EgtGetNextRawPart( nRawId)
end
-- Determinazione delle sue dimensioni
local b3Raw = EgtGetRawPartBBox( nCurrRawId)
if not b3Raw or b3Raw:isEmpty() then
EMC.ERR = 11
return
end
EMC.LENGTHBEAM = b3Raw:getDimX() + 10 * GEO.EPS_SMALL
EMC.WIDTHBEAM = b3Raw:getDimY()
EMC.HEIGHTBEAM = b3Raw:getDimZ()
EMC.ZMIN = b3Raw:getMin():getZ()
-- Aggiorno limiti di presa e tolleranza
UpdateMinJoinDeltaTol( EMC.WIDTHBEAM, EMC.HEIGHTBEAM, EMC.LENGTHBEAM)
-- TODO per il momento si ha solo area proibita in testa e coda, ma servirebbe dinamico che cambi ad ogni lavorazione eseguita.
-- Assegno sovramateriale di testa e ingombro tagli di testa e di coda
EMC.HOVM = EgtGetInfo( nCurrRawId, 'HOVM', 'd') or 0
EMC.HCING = EgtGetInfo( nCurrRawId, 'HCING', 'd') or 0
EMC.TCING = EgtGetInfo( nCurrRawId, 'TCING', 'd') or 0
-- Devo scaricare il grezzo rimasto (deve essere unico)
-- Posizione trave
local dPosT
-- Se fase 1 o dopo rotazione eseguo carico con carrello X1
local vCmd = {}
if EMC.PHASE == 1 or IsEnd2Phase( EMC.PHASE) then
dPosT = LoadT
if IsEnd2Phase( EMC.PHASE) then dPosT = dPosT + TurnerOffs end
vCmd = GetLoadCmd( dPosT, 0, min( EMC.LENGTHBEAM - MinOther - AGG_LOAD, MaxX1 - dPosT))
-- se altrimenti fase successiva alla prima di tipo inizio o rimanenza
elseif IsStartOrRestPhase( EMC.PHASE) then
-- recupero posizione trave e quota di aggancio carrello
dPosT = EgtGetInfo( EMC.DISPID, 'TPOS', 'd')
local dPosX1 = EgtGetInfo( EMC.DISPID, 'X1POS', 'd')
-- se carrello agganciato
if dPosX1 then
-- confermo i nuovi parametri di aggancio
table.insert( vCmd, { 21, dPosX1 - dPosT, 0})
-- recupero CNT
local nPrevOpeId = EgtGetPrevActiveOperation( EMC.DISPID)
if EgtGetOperationType( nPrevOpeId) == MCH_OY.DISP and EgtExistsInfo( nPrevOpeId, 'SKIP') then
nPrevOpeId = EgtGetPrevActiveOperation( nPrevOpeId)
end
local nLastPathId = EgtGetLastInGroup( EgtGetFirstNameInGroup( nPrevOpeId, 'CL') or GDB_ID.NULL)
-- altrimenti è grezzo scaricato al carico e devo ricaricarlo
else
vCmd = GetLoadCmd( dPosT, 0, min( EMC.LENGTHBEAM - MinOther - AGG_LOAD, MaxX1 - dPosT))
end
-- altrimenti fase successiva pari
else
local dPosX2 = EgtGetInfo( EMC.DISPID, 'X2POS', 'd')
EMC.X2DELTA = dPosX2
end
-- Se fase inizio o rimanenza, eseguo scambio per avere solo pinza X2
local vCmd2 = {}
if IsStartOrRestPhase( EMC.PHASE) or IsEnd2Phase( EMC.PHASE) then
EMC.TPOS = dPosT
SpecSetCarrPosFromCmds( vCmd)
local CurrUnloadT = EgtIf( EMC.LENGTHBEAM < MaxLenSmT, UnloadSmT, UnloadT)
local dDistFront = EgtIf( EMC.LENGTHBEAM < abs( MinX2 - CurrUnloadT), MinJoin, EMC.LENGTHBEAM - abs( MinX2 - CurrUnloadT) + MinJoin + DeltaTol)
local dDistBack = 0
vCmd2 = GetCarriagesCmdFromMachEncumbrance( dDistFront, dDistBack)
if vCmd and #vCmd > 1 and vCmd2 and #vCmd2 > 1 then
table.insert( vCmd, { 0, 'CARR_MOVE'})
end
end
-- eseguo scarico
SpecSetCarrPosFromCmds( vCmd2)
local vCmd3 = SpecCalcUnload()
-- unisco ed emetto i comandi
vCmd = EgtJoinTables( vCmd, vCmd2)
vCmd = EgtJoinTables( vCmd, vCmd3)
SpecOutputCmds( vCmd, true)
end
---------------------------------------------------------------------
function OnPostApplyMachining()
-- Inizializzo codice di errore
EMC.ERR = 0
-- Verifico se ultima lavorazione della fase
local nNextOpeId = EgtGetNextActiveOperation( EMC.MCHID)
local bMchLast = ( not nNextOpeId or EgtGetOperationPhase( nNextOpeId) ~= EMC.PHASE) -- Agisco sui diversi percorsi della lavorazione
local nPathId = EgtGetFirstInGroup( EgtGetFirstNameInGroup( EMC.MCHID, 'CL') or GDB_ID.NULL)
while nPathId do
-- recupero id del successivo
nPathId = EgtGetNext( nPathId)
-- verifico se ultimo percorso di ultima lavorazione della fase
local bLast = ( bMchLast and ( not nPathId))
-- se ultimo, elimino ritorno in home
if bLast then EgtRemoveOperationHome( EMC.MCHID) end
end
end
---------------------------------------------------------------------
function OnSpecialApplyMachining()
EgtOutLog( ' Lavorazione : ' .. EgtGetName( EMC.MCHID), 1)
-- Inizializzo codice di errore
EMC.ERR = 0
-- Recupero la posizione della trave e dei carrelli al termine della precedente operazione
local nPrevOpeId = EgtGetPrevActiveOperation( EMC.MCHID)
-- se precedente operazione non esiste, errore
if not nPrevOpeId then
EMC.ERR = 1
return
-- se precedente operazione è disposizione
elseif EgtGetOperationType( nPrevOpeId) == MCH_OY.DISP then
if EMC.PHASE == 1 or IsFirstMachiningAfterRotation( EMC.MCHID) then
-- posizioni home
EMC.TPOS = nil
EMC.X1DELTA = nil
EMC.X2DELTA = nil
EMC.HCING_IGNORE = true
elseif IsStartOrRestPhase( EMC.PHASE) then
-- carico le posizioni
local dPosT = EgtGetInfo( nPrevOpeId, 'TPOS', 'd')
local dPosX1 = EgtGetInfo( nPrevOpeId, 'X1POS', 'd')
-- se carrello agganciato
if dPosX1 then
EMC.TPOS = dPosT
EMC.X1DELTA = dPosX1 - dPosT
EMC.X2DELTA = nil
-- altrimenti è grezzo scaricato al carico e devo ricaricarlo
else
EMC.TPOS = nil
EMC.X1DELTA = nil
EMC.X2DELTA = nil
end
EMC.HCING_IGNORE = true
else
-- aggiornamento posizioni (da lavorazione precedente a disposizione)
local nPrev2OpeId = EgtGetPrevActiveOperation( nPrevOpeId)
if not nPrev2OpeId then
EMC.ERR = 2
return
end
local nLastPathId = EgtGetLastInGroup( EgtGetFirstNameInGroup( nPrev2OpeId, 'CL') or GDB_ID.NULL)
local nLastEntId = EgtGetLastInGroup( nLastPathId)
local vAxes = EmtGetAxesPos( nLastEntId or GDB_ID.NULL)
if not vAxes then
EMC.ERR = 3
return
end
if #vAxes > 0 then EMC.TPOS = vAxes[1] end
EMC.X1DELTA = EgtGetInfo( nLastPathId, 'X1DELTA', 'd')
EMC.X2DELTA = EgtGetInfo( nLastPathId, 'X2DELTA', 'd')
EMC.DISTFRONT = EgtGetInfo( nLastPathId, 'DISTFRONT', 'd') or 0
EMC.DISTBACK = EgtGetInfo( nLastPathId, 'DISTBACK', 'd') or 0
end
-- altrimenti precedente operazione è lavorazione
else
-- aggiornamento posizioni
local nLastPathId = EgtGetLastInGroup( EgtGetFirstNameInGroup( nPrevOpeId, 'CL') or GDB_ID.NULL)
local nLastEntId = EgtGetLastInGroup( nLastPathId)
local vAxes = EmtGetAxesPos( nLastEntId or GDB_ID.NULL)
if not vAxes then
EMC.ERR = 4
return
end
if #vAxes > 0 then EMC.TPOS = vAxes[1] end
EMC.X1DELTA = EgtGetInfo( nLastPathId, 'X1DELTA', 'd')
EMC.X2DELTA = EgtGetInfo( nLastPathId, 'X2DELTA', 'd')
EMC.DISTFRONT = EgtGetInfo( nLastPathId, 'DISTFRONT', 'd') or 0
EMC.DISTBACK = EgtGetInfo( nLastPathId, 'DISTBACK', 'd') or 0
end
-- Verifico se ultima lavorazione della fase
local nNextOpeId = EgtGetNextActiveOperation( EMC.MCHID)
local bMchLast = ( not nNextOpeId or EgtGetOperationPhase( nNextOpeId) ~= EMC.PHASE)
-- Verifico se ultima lavorazione prima di una rotazione
local bPreRotMch = IsLastOperationBeforeRotation( EMC.MCHID)
-- Verifico flag di separazione e fase di scarico
local sNotes = EgtGetMachiningParam( MCH_MP.USERNOTES)
local bPreSplit = ( sNotes:find( 'Presplit') ~= nil)
local bSplitting = ( sNotes:find( 'Split') ~= nil)
local bPreCut = ( sNotes:find( 'Precut') ~= nil)
local bCutting = ( sNotes:find( 'Cut') ~= nil)
local bUnload = IsEndPhase( EMC.PHASE) or IsEnd2Phase( EMC.PHASE)
if bPreSplit or bPreCut then
EgtSetInfo( EMC.MCHID, 'IS_PRE', '1')
else
EgtRemoveInfo( EMC.MCHID, 'IS_PRE')
end
-- Agisco sui diversi percorsi della lavorazione
local nPathId = EgtGetFirstInGroup( EgtGetFirstNameInGroup( EMC.MCHID, 'CL') or GDB_ID.NULL)
while nPathId do
-- assegno id percorso da elaborare
EMC.PATHID = nPathId
-- recupero id del successivo
nPathId = EgtGetNext( nPathId)
-- verifico se ultimo percorso di ultima lavorazione della fase
local bLast = ( bMchLast and ( not nPathId))
-- se ultimo, elimino ritorno in home
if bLast then EgtRemoveOperationHome( EMC.MCHID) end
-- salvo lo stato di trave e carrelli
local OriTPos = EMC.TPOS
local OriX1Delta = EMC.X1DELTA
local OriX2Delta = EMC.X2DELTA
-- eseguo le elaborazioni
SpecApplyPath( bPreSplit, bSplitting, bPreCut, bCutting, bLast and bUnload, bLast and bPreRotMch)
-- se separazione, verifico il risultato
if bSplitting then
-- recupero CUTID del pezzo in lavoro
local CutID = GetCUTID()
-- in caso di errore mancato pinzaggio uscita riprovo dopo aver disabilitato le lavorazioni finali
if EMC.ERR == 18 then
-- segnalazione warning
EMC.ERR = -101
EMC.MSG = 'Warning : skipped final processes (WRN=101,CUTID='..tostring( CutID)..')'
-- ripristino lo stato originale di trave e carrelli
EMC.TPOS = OriTPos
EMC.X1DELTA = OriX1Delta
EMC.X2DELTA = OriX2Delta
-- eseguo le elaborazioni
SpecApplyPath( bPreSplit, bSplitting, bPreCut, bCutting, bLast and bUnload, bLast and bPreRotMch)
-- pinzaggio ancora impossibile, pezzo a caduta
if EMC.ERR == 18 then
-- segnalazione warning
EMC.ERR = -102
EMC.MSG = 'Warning : skipped final processes and unload by fall (WRN=102,CUTID='..tostring( CutID)..')'
end
-- scarico standard
elseif EMC.ERR == 0 then
-- segnalazione warning
EMC.ERR = -100
EMC.MSG = 'Warning : standard unload (WRN=100,CUTID='..tostring( CutID)..')'
end
-- se taglio del residuo finale, scarico standard
elseif bCutting then
-- recupero CUTID del pezzo in lavoro
local CutID = GetCUTID()
-- se non ci sono errori, segnalazione warning
if EMC.ERR == 0 then
EMC.ERR = -100
EMC.MSG = 'Warning : standard unload (WRN=100,CUTID='..tostring( CutID)..')'
end
end
if EMC.ERR > 0 then return end
-- determino la posizione finale della trave
local nLastEntId = EgtGetLastInGroup( EMC.PATHID)
local vAxes = EmtGetAxesPos( nLastEntId)
if #vAxes > 0 then EMC.TPOS = vAxes[1] end
end
end
---------------------------------------------------------------------
function SpecApplyPath( bPreSplit, bSplitting, bPreCut, bCutting, bUnload, bPreRotMch)
-- Assegno flag di pezzo separato dal resto del grezzo
local bSplit = IsEndPhase( EMC.PHASE) or IsMid2Phase( EMC.PHASE) or IsEnd2Phase( EMC.PHASE)
-- Determinazione delle dimensioni totali dei grezzi e del grezzo in lavoro
local b3Tot = BBox3d()
local b3Raw = BBox3d()
local nNextOddPhase = GetNextStartOrRestPhase( EMC.PHASE)
local nRawId = EgtGetFirstRawPart()
local nCurrRawId = GDB_ID.NULL
while nRawId do
if EgtVerifyRawPartPhase( nRawId, EMC.PHASE) then
local b3Tmp = EgtGetRawPartBBox( nRawId)
b3Tot:Add( b3Tmp)
if EgtGetPartInRawPartCount( nRawId) > 0 and not EgtVerifyRawPartPhase( nRawId, nNextOddPhase) then
b3Raw = b3Tmp
nCurrRawId = nRawId
end
end
nRawId = EgtGetNextRawPart( nRawId)
end
if b3Tot:isEmpty() then
EMC.ERR = 11
return
end
EMC.LENGTHBEAM = EgtIf( bSplit, b3Raw:getDimX(), b3Tot:getDimX()) + 10 * GEO.EPS_SMALL
EMC.WIDTHBEAM = b3Tot:getDimY()
EMC.HEIGHTBEAM = b3Tot:getDimZ()
EMC.LENGTHRAW = b3Raw:getDimX() + 10 * GEO.EPS_SMALL
EMC.YMIN = b3Raw:getMin():getY()
EMC.ZMIN = b3Raw:getMin():getZ()
-- Aggiorno limiti di presa e tolleranza
UpdateMinJoinDeltaTol( EMC.WIDTHBEAM, EMC.HEIGHTBEAM, EMC.LENGTHBEAM)
-- Recupero sovramateriale di testa e ingombro tagli di testa e di coda dal pezzo
EMC.HOVM = EgtGetInfo( nCurrRawId, 'HOVM', 'd') or 0 -- head over material
EMC.HCING = EgtGetInfo( nCurrRawId, 'HCING', 'd') or 0 -- head cutting
EMC.TCING = EgtGetInfo( nCurrRawId, 'TCING', 'd') or 0 -- tail cutting
EMC.XMAX = b3Raw:getMax():getX() - EMC.HOVM
local idDisp = EgtGetPhaseDisposition( EMC.PHASE)
local dHCING = EgtGetInfo( idDisp, 'HCING', 'd') or 0
if dHCING then
EMC.HCING = dHCING
end
local dTCING = EgtGetInfo( idDisp, 'TCING', 'd') or 0
if dTCING then
EMC.TCING = dTCING
end
local dDistFront, dDistBack
local bClampsSamePosition = EgtGetInfo( EMC.MCHID, 'ClampFIX', 'd') == 1 or false
-- se la posizione è già stata calcolata a partire da una lavorazione precedente
if bClampsSamePosition and EMC.DISTFRONT and EMC.DISTBACK then
dDistFront = EMC.DISTFRONT
dDistBack = EMC.DISTBACK
-- altrimenti si ricalcola la posizione a partire dalla lavorazione attuale
else
-- se sono stati calcolati gli ingombri
local bEntirePhaseCalculated = false
-- ingombro lavorazione attuale
dDistFront, dDistBack = GetMachiningEncumbrance( EMC.MCHID, bPreCut)
if not dDistFront or not dDistBack then return end
if bPreSplit or bSplitting then
local dDistF, dDistB = GetPhaseEncumbrance( EMC.PHASE + 1)
dDistFront = min( dDistFront, dDistF)
local dNextHOVM = EgtGetInfo( EgtGetNextRawPart( nCurrRawId) or GDB_ID.NULL, 'HOVM', 'd') or 0
local dBackOther = b3Tot:getDimX() - b3Raw:getDimX() - MinOther - dNextHOVM
local dDistBackStartPhase = GetStartPhaseEncumbrance( EMC.PHASE + 2)
if dDistBackStartPhase then
dDistBack = min( dDistBack, dDistBackStartPhase)
end
EgtOutLog( 'DistBack='..EgtNumToString( dDistBack)..' OtherBack='..EgtNumToString( dBackOther), 3)
dDistBack = min( dDistBack, dBackOther)
bEntirePhaseCalculated = true
elseif bPreCut or bCutting then
local dDistF = GetPhaseEncumbrance( EMC.PHASE + 1)
dDistFront = min( dDistFront, dDistF)
dDistBack = 0.0
bEntirePhaseCalculated = true
end
-- Verifico lunghezza pezzo
if not bSplit and not VerifyPartLength() then
return
end
-- posizione pinze in base a ingombro lavorazione attuale
local _, dX1DeltaCurrMach, dX2DeltaCurrMach = CalcCarriagesNewPositions( dDistFront, dDistBack)
-- se è già stato calcolata per tutta la fase successiva, si controlla che il pinzaggio sia valido
if bEntirePhaseCalculated then
if dX1DeltaCurrMach or dX2DeltaCurrMach then
-- se la posizione è calcolata sull'intera fase successiva, si setta nota su tutte le lavorazioni di quella fase
local nNextMchId = EgtGetNextActiveOperation( EMC.MCHID)
while nNextMchId and EgtGetOperationPhase( nNextMchId) <= EMC.PHASE + 1 do
if EgtGetOperationType( nNextMchId) ~= MCH_OY.DISP then
EgtSetInfo( nNextMchId, 'ClampFIX', 1)
end
-- prossima lavorazione
nNextMchId = EgtGetNextActiveOperation( nNextMchId)
end
end
-- altrimenti significa che è solo una lavorazione normale, si prende ingombro lavorazioni successive
else
-- controllo se schema cambia lo schema di pinzaggio
local function IsConsistentClamping( dPrev, dNext)
return ( dPrev == nil and dNext == nil) or ( dPrev ~= nil and dNext ~= nil)
end
-- se sono in una fase di start e X1DELTA è già calcolato e è più lontano del corrente, dico che X1DELTA è il corrente
-- si entra in questo caso quando la separazione precedente occupa di più delle lavorazioni di testa del pezzo successivo
if IsStartPhase( EMC.PHASE) and EMC.X1DELTA and dX1DeltaCurrMach and not EMC.X2DELTA then
if EMC.X1DELTA > dX1DeltaCurrMach then
dX1DeltaCurrMach = EMC.X1DELTA
end
end
-- in caso di pinzaggio singolo, mi salvo intervallo minimo e massimo
local dX1DeltaMin, dX1DeltaMax = dX1DeltaCurrMach, dX1DeltaCurrMach
local dX2DeltaMin, dX2DeltaMax = dX2DeltaCurrMach, dX2DeltaCurrMach
local nNextMchId = EgtGetNextActiveOperation( EMC.MCHID)
local bUseSameClampingConfig = true
while nNextMchId and EgtGetOperationType( nNextMchId) ~= MCH_OY.DISP and bUseSameClampingConfig do
local dNextDistFront, dNextDistBack, InfoUserNotes = GetMaxEncumbranceOtherMachining( nNextMchId)
if dNextDistFront and dNextDistBack then
-- se la lavorazione che sto controllando è una di separazione, allora si controlla tutta la fase successiva
if InfoUserNotes.bPreSplit or InfoUserNotes.bSplitting then
local dDistF, dDistB = GetPhaseEncumbrance( EMC.PHASE + 1)
dNextDistFront = min( dNextDistFront, dDistF)
local dNextHOVM = EgtGetInfo( EgtGetNextRawPart( nCurrRawId) or GDB_ID.NULL, 'HOVM', 'd') or 0
local dBackOther = b3Tot:getDimX() - b3Raw:getDimX() - MinOther - dNextHOVM
local dDistBackStartPhase = GetStartPhaseEncumbrance( EMC.PHASE + 2)
if dDistBackStartPhase then
dNextDistBack = min( dNextDistBack, dDistBackStartPhase)
end
EgtOutLog( 'DistBack='..EgtNumToString( dNextDistBack)..' OtherBack='..EgtNumToString( dBackOther), 3)
dNextDistBack = min( dNextDistBack, dBackOther)
bEntirePhaseCalculated = true
elseif InfoUserNotes.bPreCut or InfoUserNotes.bCutting then
-- possono esserci altri tagli di precut, scorro tutte fino a fine fase
local nLastMchId = EgtGetNextActiveOperation( nNextMchId)
while nLastMchId and EgtGetOperationType( nLastMchId) ~= MCH_OY.DISP do
local dLastDistFront = GetMaxEncumbranceOtherMachining( nLastMchId)
dNextDistFront = min( dNextDistFront, dLastDistFront)
nLastMchId = EgtGetNextActiveOperation( nLastMchId)
end
local dDistF = GetPhaseEncumbrance( EMC.PHASE + 1)
dNextDistFront = min( dNextDistFront, dDistF)
dNextDistBack = 0.0
bEntirePhaseCalculated = true
end
end
local _, dNextNewX1Delta, dNextNewX2Delta = CalcCarriagesNewPositions( dNextDistFront, dNextDistBack)
local bUnloadIsOk = true
if dNextNewX2Delta and dX2DeltaCurrMach and ( InfoUserNotes.bPreSplit or InfoUserNotes.bSplitting) then
local dLastX2Delta = min( dX2DeltaCurrMach, dNextNewX2Delta)
-- controllo che si riesca a scaricare restando nelle corse
if ( b3Raw:getDimX() - dLastX2Delta - UnloadT) + MinX2 > -100 then
bUseSameClampingConfig = false
bUnloadIsOk = false
end
end
if IsConsistentClamping( dX1DeltaCurrMach, dNextNewX1Delta) and IsConsistentClamping( dX2DeltaCurrMach, dNextNewX2Delta) and bUnloadIsOk then
-- se entrambe le morse in presa
if dX1DeltaCurrMach and dX2DeltaCurrMach then
if ( ( max( dX1DeltaCurrMach, dNextNewX1Delta) - min( dX2DeltaCurrMach, dNextNewX2Delta)) < CLAMP_MAXDIST_2CLAMP) then
if dNextNewX1Delta > dX1DeltaCurrMach then dX1DeltaCurrMach = dNextNewX1Delta end
if dNextNewX2Delta < dX2DeltaCurrMach then dX2DeltaCurrMach = dNextNewX2Delta end
dDistFront = min( dDistFront, dNextDistFront)
dDistBack = min( dDistBack, dNextDistBack)
bUseSameClampingConfig = true
else
bUseSameClampingConfig = false
end
-- se in presa solo pinza 1
elseif dX1DeltaCurrMach then
-- se la posizione richiesta della pinza non è oltre la posizione attuale e non sono troppo distante, prendo valori vecchi
if ( dX1DeltaMax - dNextNewX1Delta) < CLAMP_MAXDIST_1CLAMP and ( dNextNewX1Delta - dX1DeltaMin) < CLAMP_MAXDIST_1CLAMP then
dX1DeltaMax = max( dX1DeltaMax, dNextNewX1Delta)
dX1DeltaMin = min( dX1DeltaMin, dNextNewX1Delta)
dDistBack = min( dDistBack, dNextDistBack)
bUseSameClampingConfig = true
else
bUseSameClampingConfig = false
end
-- se in presa solo pinza 2
elseif dX2DeltaCurrMach then
-- se la posizione richiesta della pinza non è oltre la posizione attuale e non sono troppo distante, prendo valori vecchi
if ( dX2DeltaMax - dNextNewX2Delta) < CLAMP_MAXDIST_1CLAMP and ( dNextNewX2Delta - dX2DeltaMin) < CLAMP_MAXDIST_1CLAMP then
dX2DeltaMax = max( dX2DeltaMax, dNextNewX2Delta)
dX2DeltaMin = min( dX2DeltaMin, dNextNewX2Delta)
dDistFront = min( dDistFront, dNextDistFront)
bUseSameClampingConfig = true
else
bUseSameClampingConfig = false
end
end
else
bUseSameClampingConfig = false
end
-- se posso usare la stessa configurazione, allora si setta che la posizione è già calcolata
if bUseSameClampingConfig then
EgtSetInfo( nNextMchId, 'ClampFIX', 1)
-- se la posizione è calcolata sull'intera fase successiva, si setta nota su tutte le lavorazioni di quella fase
if bEntirePhaseCalculated then
-- prossima lavorazione
nNextMchId = EgtGetNextActiveOperation( nNextMchId)
while nNextMchId and EgtGetOperationPhase( nNextMchId) <= EMC.PHASE + 1 do
if EgtGetOperationType( nNextMchId) ~= MCH_OY.DISP then
EgtSetInfo( nNextMchId, 'ClampFIX', 1)
end
-- prossima lavorazione
nNextMchId = EgtGetNextActiveOperation( nNextMchId)
end
end
-- altrimenti si rimuove info in caso fosse stata settata in un calolo precedente
else
EgtRemoveInfo( nNextMchId, 'ClampFIX')
end
-- se non è già all'ultima lavorazione, chiedo la successiva
if nNextMchId and EgtGetOperationPhase( nNextMchId) <= EMC.PHASE + 1 then
nNextMchId = EgtGetNextActiveOperation( nNextMchId)
end
end
end
end
-- si salvano i valori
EMC.DISTFRONT = dDistFront
EMC.DISTBACK = dDistBack
-- Se inizio o appena dopo rotazione, eseguo il carico
if not EMC.TPOS then
local dPosT = LoadT
if IsFirstMachiningAfterRotation( EMC.MCHID) then dPosT = dPosT + TurnerOffs end
local vCmd = GetLoadCmd( dPosT, dDistFront, max( dDistBack, MinJoin))
local vCmd2 = GetCarriagesCmdFromMachEncumbrance( dDistFront, dDistBack)
if vCmd2 and #vCmd2 > 1 then
table.insert( vCmd, { 0, 'CARR_MOVE'})
end
EgtJoinTables( vCmd, vCmd2)
table.insert( vCmd, { 0, 'Move_End'})
SpecOutputCmds( vCmd)
-- Se altrimenti carri entrambi diponibili, eseguo calcoli per carrelli
elseif not IsEndPhase( EMC.PHASE) then
local vCmd = GetCarriagesCmdFromMachEncumbrance( dDistFront, dDistBack)
-- Se non ci sono spostamenti, confermo i parametri di aggancio
if SpecTestOnlyRemarkInCmds( vCmd) then
table.insert( vCmd, { 21, EgtIf( EMC.X1DELTA, EMC.X1DELTA, 0), EgtIf( EMC.X2DELTA, EMC.X2DELTA, 0)})
end
SpecOutputCmds( vCmd)
-- Altrimenti, non muovo i carrelli rispetto alla trave
else
local vCmd = {}
SpecOutputCmds( vCmd)
end
EMC.HCING_IGNORE = nil
-- Se taglio di separazione
local vCmd = {}
if bSplitting then
-- rimuovo eventuale vecchia info di Skip
local NextDispId = EgtGetPhaseDisposition( EMC.PHASE + 1) or GDB_ID.NULL
EgtRemoveInfo( NextDispId, 'SKIP')
EMC.MAXLENLEFT = EgtGetInfo( idDisp, 'MAXLENLEFT', 'd')
-- verifico se separazione con caduta
if not EMC.X2DELTA then
EgtOutLog( ' Warning SPLITTING -> separazione con caduta pezzo')
if IsEndPhase( EMC.PHASE + 1) then
EgtSetInfo( NextDispId, 'SKIP', '1')
local NextOpeId = EgtGetNextOperation( NextDispId)
while NextOpeId and EgtGetOperationPhase( NextOpeId) == EMC.PHASE + 1 do
EgtSetOperationMode( NextOpeId, false)
NextOpeId = EgtGetNextOperation( NextOpeId)
end
end
EMC.ERR = 18
-- verifico che la barra sia agganciata ad entrambi i carrelli
elseif not EMC.X1DELTA or not EMC.X2DELTA then
EMC.ERR = 19
EMC.MSG = ' Error SPLIT : X1 or X2 not clamped'
return false
end
if not IsMid2Phase( EMC.PHASE + 1) then
vCmd = SpecCalcSplit( b3Raw:getDimX())
else
vCmd = SpecCalcSplitRot( b3Raw:getDimX())
EMC.DISTBACK = nil
end
end
-- Se taglio finale di grezzo a perdere
if bCutting then
-- salvo distanza carrello X2 da inizio grezzo rimasto nella disposizione della prossima fase
local NextDispId = EgtGetPhaseDisposition( EMC.PHASE + 1)
if NextDispId then
EgtSetInfo( NextDispId, 'X2POS', EMC.X2DELTA)
end
end
-- Se previsto scarico, lo eseguo
if bUnload then
EMC.LENGTHBEAM = b3Raw:getDimX() + 10 * GEO.EPS_SMALL
local vCmdTmp = SpecCalcUnload()
vCmd = EgtJoinTables( vCmd, vCmdTmp)
end
-- Se ritorno al carico per rotazione
if bPreRotMch then
-- determino posizione testa trave
local nLastEntId = EgtGetLastInGroup( EMC.PATHID)
local vAxes = EmtGetAxesPos( nLastEntId)
if #vAxes > 0 then EMC.TPOS = vAxes[1] end
-- eseguo movimento prima di rotazione
local vCmdTmp = SpecCalcPreRot()
vCmd = EgtJoinTables( vCmd, vCmdTmp)
end
-- Emetto eventuali comandi di separazione e/o scarico
if #vCmd > 0 then
SpecOutputCmds( vCmd, true)
end
end --SpecApplyPath( bLast)
---------------------------------------------------------------------
function GetMachiningEncumbrance( nMchId, bPreCut)
-- gruppi della lavorazione
local nClId = EgtGetFirstNameInGroup( nMchId, 'CL')
local nPathId = EgtGetFirstInGroup( nClId or GDB_ID.NULL)
if not nPathId then
EMC.ERR = 12
return
end
-- recupero ptMin ptMax della lavorazione
local ptMin = EgtGetInfo( nClId, 'MMIN', 'p')
local ptMax = EgtGetInfo( nClId, 'MMAX', 'p')
if not ptMin or not ptMax then
EMC.ERR = 13
return
end
-- se pre-taglio, aggiorno ptMax con quello del taglio finale
if bPreCut then
local ptFinMax = GetFinalCutPmax( nMchId)
if ptFinMax then
ptMax = ptFinMax
end
end
-- Recupero del vettore estrusione (coincide con il vettore utensile)
local vtTool = EgtGetInfo( nPathId, 'EXTR', 'v')
if not vtTool then
EMC.ERR = 14
return
end
-- Recupero testa
local sHead = EgtTdbGetCurrToolParam( MCH_TP.HEAD)
-- Calcolo del vettore ausiliario
local vAxes = EmtGetAxesPos( EgtGetFirstInGroup( nPathId))
if not vAxes or #vAxes < 5 or ( sHead == 'H3' and #vAxes < 6) then
EMC.ERR = 15
return
end
local vtAux = EgtGetCalcAuxDirFromAngles( vAxes[4], vAxes[5], vAxes[6])
if not vtAux then
EMC.ERR = 16
return
end
local vtArm = vtAux
-- Recupero dei dati dell'utensile
local nToolType = EgtTdbGetCurrToolParam( MCH_TP.TYPE)
local bSaw = ( nToolType == MCH_TY.SAW_STD or nToolType == MCH_TY.SAW_FLAT)
local bChain = ( nToolType == MCH_TY.MORTISE_STD)
local dTLen = EgtTdbGetCurrToolParam( MCH_TP.LEN)
local dTDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM)
local dTDist = EgtIf( EgtTdbGetCurrToolParam( MCH_TP.DIST) > 1, EgtTdbGetCurrToolParam( MCH_TP.DIST), ChSawLen)
-- Se sega a catena, devo correggere il versore Aux per farlo coincidere con la direzione del braccio C
if bChain then
if abs( vAxes[6] or 0) < 1 then
vtArm = vtTool
else
vtArm = vtTool ^ vtAux
end
end
-- Calcolo limiti derivanti dalla lavorazione
local dDistFront, dDistBack = SpecCalcEncumbrance( vtTool, vtArm, vtAux, ptMin, ptMax, bSaw, bChain, dTLen, dTDiam, dTDist)
return dDistFront, dDistBack
end
---------------------------------------------------------------------
function GetMaxEncumbranceOtherMachining( nMchId)
-- Salvo lavorazione e utensile correnti, per ripristinarli alla fine
local nOrigMchId = EgtGetCurrMachining()
local sOrigTool = EgtTdbGetCurrToolParam( MCH_TP.NAME)
local sOrigHead = EgtTdbGetCurrToolParam( MCH_TP.HEAD)
local nOrigExit = EgtTdbGetCurrToolParam( MCH_TP.EXIT)
-- imposto lavorazione e utensile correnti
EgtSetCurrMachining( nMchId)
local sTool = EgtGetMachiningParam( MCH_MP.TOOL)
if not EgtTdbSetCurrTool( sTool) then
local sTuuid = EgtGetMachiningParam( MCH_MP.TUUID)
sTool = EgtTdbGetToolFromUUID( sTuuid)
EgtTdbSetCurrTool( sTool)
end
local sHead = EgtTdbGetCurrToolParam( MCH_TP.HEAD)
local nExit = EgtTdbGetCurrToolParam( MCH_TP.EXIT)
if sTool and sHead and nExit then EgtSetCalcTool( sTool, sHead, nExit) end
-- calcolo ingombri
local dDistF, dDistB = GetMachiningEncumbrance( nMchId)
local InfoNotes = {}
-- Verifico flag di separazione e fase di scarico
InfoNotes.sNotes = EgtGetMachiningParam( MCH_MP.USERNOTES)
InfoNotes.bPreSplit = ( InfoNotes.sNotes:find( 'Presplit') ~= nil)
InfoNotes.bSplitting = ( InfoNotes.sNotes:find( 'Split') ~= nil)
InfoNotes.bPreCut = ( InfoNotes.sNotes:find( 'Precut') ~= nil)
InfoNotes.bCutting = ( InfoNotes.sNotes:find( 'Cut') ~= nil)
-- Ripristino lavorazione e utensile correnti
if nOrigMchId then EgtSetCurrMachining( nOrigMchId) end
if sOrigTool then EgtTdbSetCurrTool( sOrigTool) end
if sOrigTool and sOrigHead and nOrigExit then EgtSetCalcTool( sOrigTool, sOrigHead, nOrigExit) end
-- Restituisco gli ingombri trovati
return dDistF, dDistB, InfoNotes
end
---------------------------------------------------------------------
function GetStartPhaseEncumbrance( nPhase)
-- si pre-calcola solo se è una fase di start dopo uno split
if not IsStartPhase( nPhase) then
return nil
end
local dDistBack = nil
local dX1DeltaStartPhaseMin = nil
local dX1DeltaStartPhaseMax = nil
local nMchId = EgtGetNextActiveOperation( EgtGetPhaseDisposition( nPhase) or GDB_ID.NULL)
if nMchId then
local bGetNext = true
while bGetNext do
local dDistFrontStartPhase, dDistBackStartPhase = GetMachiningEncumbrance( nMchId, false)
local _, dX1DeltaStartPhaseCurr, dX2DeltaStartPhaseCurr = CalcCarriagesNewPositions( dDistFrontStartPhase, dDistBackStartPhase)
-- se in presa anche pinza 2, esco subito, non sarà possibile posizionamento diretto
if not dX1DeltaStartPhaseCurr or dX2DeltaStartPhaseCurr then
break
else
-- se non ancora settato, minimo e massimo assumono il valore attuale
if not dX1DeltaStartPhaseMin and not dX1DeltaStartPhaseMax then
dX1DeltaStartPhaseMin = dX1DeltaStartPhaseCurr
dX1DeltaStartPhaseMax = dX1DeltaStartPhaseCurr
dDistBack = dDistBackStartPhase
else
-- se la posizione richiesta della pinza non è oltre la posizione attuale e non sono troppo distante, prendo valori vecchi
if ( dX1DeltaStartPhaseMax - dX1DeltaStartPhaseCurr) < CLAMP_MAXDIST_1CLAMP and ( dX1DeltaStartPhaseCurr - dX1DeltaStartPhaseMin) < CLAMP_MAXDIST_1CLAMP then
dX1DeltaStartPhaseMax = max( dX1DeltaStartPhaseMax, dX1DeltaStartPhaseCurr)
dX1DeltaStartPhaseMin = min( dX1DeltaStartPhaseMin, dX1DeltaStartPhaseCurr)
dDistBack = min( dDistBack, dDistBackStartPhase)
else
break
end
end
end
nMchId = EgtGetNextActiveOperation( nMchId)
if EgtGetOperationPhase( nMchId) ~= nPhase then
bGetNext = false
end
end
-- se ho trovato un valore, allora si corregge con lunghezza del pezzo attuale perchè sto guardando al pezzo successivo,
-- ma le misure ecc sono calcolate con pezzo attuale ancora presente
if dDistBack then
dDistBack = dDistBack - EMC.LENGTHRAW
end
end
return dDistBack
end
---------------------------------------------------------------------
function GetPhaseEncumbrance( nPhase)
-- Deve essere la fase finale di lavorazione di un pezzo (già staccato dal resto della trave)
local dDistFront = EMC.LENGTHBEAM
local dDistBack = EMC.LENGTHBEAM
-- Salvo lavorazione e utensile correnti, per ripristinarli alla fine
local nOrigMchId = EgtGetCurrMachining()
local sOrigTool = EgtTdbGetCurrToolParam( MCH_TP.NAME)
local sOrigHead = EgtTdbGetCurrToolParam( MCH_TP.HEAD)
local nOrigExit = EgtTdbGetCurrToolParam( MCH_TP.EXIT)
-- Ciclo sulle lavorazioni
local nMchId = EgtGetNextActiveOperation( EgtGetPhaseDisposition( nPhase) or GDB_ID.NULL)
while nMchId and EgtGetOperationPhase( nMchId) == nPhase do
-- imposto lavorazione e utensile correnti
EgtSetCurrMachining( nMchId)
local sTool = EgtGetMachiningParam( MCH_MP.TOOL)
if not EgtTdbSetCurrTool( sTool) then
local sTuuid = EgtGetMachiningParam( MCH_MP.TUUID)
sTool = EgtTdbGetToolFromUUID( sTuuid)
EgtTdbSetCurrTool( sTool)
end
local sHead = EgtTdbGetCurrToolParam( MCH_TP.HEAD)
local nExit = EgtTdbGetCurrToolParam( MCH_TP.EXIT)
if sTool and sHead and nExit then EgtSetCalcTool( sTool, sHead, nExit) end
-- calcolo ingombri
local dDistF, dDistB = GetMachiningEncumbrance( nMchId)
if dDistF and dDistB then
dDistFront = min( dDistFront, dDistF)
dDistBack = min( dDistBack, dDistB)
end
nMchId = EgtGetNextActiveOperation( nMchId)
end
-- Ripristino lavorazione e utensile correnti
if nOrigMchId then EgtSetCurrMachining( nOrigMchId) end
if sOrigTool then EgtTdbSetCurrTool( sOrigTool) end
if sOrigTool and sOrigHead and nOrigExit then EgtSetCalcTool( sOrigTool, sOrigHead, nOrigExit) end
-- Restituisco gli ingombri trovati
return dDistFront, dDistBack
end
---------------------------------------------------------------------
function GetFinalCutPmax( nMchId)
local nFinalCutId
local nId = EgtGetNextActiveOperation( nMchId)
while nId and EgtGetOperationPhase( nId) == EMC.PHASE do
nFinalCutId = nId
nId = EgtGetNextActiveOperation( nId)
end
if not nFinalCutId then return end
local nCLId = EgtGetFirstNameInGroup( nFinalCutId, 'CL')
if not nCLId then return end
return EgtGetInfo( nCLId, 'MMAX', 'p')
end
---------------------------------------------------------------------
-- TODO FUNZIONE DA RIVEDERE
-- il calcolo ingombro non deve essere a casi, ma calcolato preciso con intersezione di solidi
function SpecCalcEncumbrance( vtTool, vtArm, vtAux, ptMin, ptMax, bSaw, bChain, dTLen, dTDiam, dTDist)
-- Quota in Z dal punto di inclinazione dei carrelli
local dCompZ = sqrt( 1 - vtTool:getZ() * vtTool:getZ())
local dZup = ptMin:getZ() - 0.5 * dCompZ * dTDiam - ( EMC.ZMIN + 130)
-- Posizione min e max del naso mandrino (rispetto a testa pezzo in X e riferimento pezzo in Y e Z)
local ptHeadMin = ptMin + vtTool * dTLen - Vector3d( EMC.XMAX, EMC.YMIN + EMC.WIDTHBEAM, EMC.ZMIN)
local ptHeadMax = ptMax + vtTool * dTLen - Vector3d( EMC.XMAX, EMC.YMIN + EMC.WIDTHBEAM, EMC.ZMIN)
-- Ingombro a sinistra
local dDistBack = EMC.LENGTHBEAM + ptMin:getX() + LoadT
local dHeadBack = 350
if bSaw then
if vtTool:getX() > 0 and abs( vtTool:getY()) < 0.088 and abs( vtTool:getZ()) < 0.088 then
dHeadBack = 50 + 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX())
elseif abs( vtTool:getZ()) < 0.26 and abs( vtTool:getX()) < 0.35 then
dHeadBack = EgtIf( vtArm:getX() < 0, 540, 350)
elseif abs( vtTool:getZ()) < 0.26 and abs( vtTool:getX()) < 0.71 then
if vtArm:getX() < 0 then
dHeadBack = 460
else
dHeadBack = EgtIf( vtTool:getX() > 0, 50, 90) + 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX())
end
elseif ( vtTool:getX() > 0.7 and abs( vtTool:getY()) < 0.2 and ptMax:getZ() > EMC.ZMIN + 0.9 * EMC.HEIGHTBEAM) then
if vtTool:getZ() > 0 then
dHeadBack = max( 50, 90 - 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX()))
else
dHeadBack = max( 50, 40 + 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX()))
end
if ptMax:getZ() < EMC.ZMIN + BD.VICE_MINH then
dHeadBack = dHeadBack + BD.VICE_MINH
end
elseif ( vtTool:getX() > 0.2 and abs( vtTool:getZ()) < 0.5) then
dHeadBack = max( 90, 40 + 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX()))
elseif abs( vtTool:getZ()) < 0.93 then
if vtTool:getX() > 0 and abs( vtTool:getY()) < 0.2 and ptMax:getZ() > EMC.ZMIN + BD.VICE_MINH then
dHeadBack = 180
elseif vtTool:getX() > -0.05 then
dHeadBack = 50 + 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX())
elseif vtTool:getX() > -0.3 then
dHeadBack = 250
elseif vtTool:getX() > -0.707 then
dHeadBack = 350
elseif vtTool:getX() > -0.8667 then
dHeadBack = 400
else
dHeadBack = 520
end
else
dHeadBack = 50 + 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX())
end
-- per limiti corsa asse X1
dHeadBack = max( dHeadBack, MinX1 + 1 - vtTool:getX() * ( MillOffs + dTLen))
else
if ( vtTool:getX() > -0.1 and vtArm:getX() > -0.1) or
( abs( vtTool:getX()) < 0.1 and abs( vtTool:getZ()) < 0.1) then
dHeadBack = 130
elseif ( vtTool:getX() > -0.1 and vtArm:getX() > -0.95) then
dHeadBack = 180
elseif ( vtTool:getX() < -0.8) then
dHeadBack = 375
elseif ( vtTool:getX() < -0.75) then
dHeadBack = 350
elseif ( vtTool:getX() < -0.5) then
dHeadBack = 350
end
if vtTool:getX() < -0.25 then
dHeadBack = dHeadBack + max( dTLen - 130, 0) * abs( vtTool:getX())
elseif vtTool:getX() < 0 then
dHeadBack = dHeadBack + ( dTLen + 180) * abs( vtTool:getX())
end
if vtTool:getX() > 0.866 then
dHeadBack = 50
elseif vtTool:getX() >= 0 and dZup > 0 then
dHeadBack = max( 130, dHeadBack - dZup)
end
if abs( vtTool:getX()) < 0.5 and abs( vtTool:getZ()) > 0.259 and dZup < 0 then
if vtArm:getX() < -0.259 then
dHeadBack = 410
else
dHeadBack = EgtIf( vtTool:getZ() > 0.966, 160, 280)
end
end
-- per fresature longitudinali con utensile di fianco
if abs( vtTool:getX()) < 0.1 and vtTool:getZ() < 0.707 and vtArm:getX() < -0.5 then
dHeadBack = 400
end
-- per sega a catena di fianco
if bChain and vtTool:getX() < 0.5 and vtTool:getZ() < 0.5 and vtArm:getX() < -0.5 then
dHeadBack = max( dHeadBack, 510)
end
-- per fresa diretta quasi esattamente come X1+/- e con la testa non troppo nel pezzo
if not bChain and abs( vtTool:getX()) < 0.017 and abs( vtTool:getZ()) < 0.017 and
(( vtTool:getY() > 0 and ptHeadMin:getY() > 80) or ( vtTool:getY() < 0 and ptHeadMax:getY() < -EMC.WIDTHBEAM - 80)) then
dHeadBack = 130
end
-- per limiti corsa asse X1
if not bChain then
dHeadBack = max( dHeadBack, MinX1 + 1 - vtTool:getX() * ( MillOffs + dTLen))
else
dHeadBack = max( dHeadBack, MinX1 + 1 - vtAux:getX() * ( MillOffs + dTDist) - vtTool:getX() * dTLen)
end
end
-- Ingombro a destra
local dDistFront = - ptMax:getX() - LoadT
local dHeadFront = 350
if bSaw then
if vtTool:getX() < 0 and abs( vtTool:getY()) < 0.088 and abs( vtTool:getZ()) < 0.088 then
dHeadFront = 50 + 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX())
elseif abs( vtTool:getZ()) < 0.26 and abs( vtTool:getX()) < 0.35 then
dHeadFront = EgtIf( vtArm:getX() > 0, 540, 350)
elseif abs( vtTool:getZ()) < 0.26 and abs( vtTool:getX()) < 0.71 then
if vtArm:getX() > 0 then
dHeadFront = 350
else
dHeadFront = EgtIf( vtTool:getX() < 0, 50, 90) + 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX())
end
elseif ( vtTool:getX() < - 0.7 and abs( vtTool:getY()) < 0.2 and ptMax:getZ() > EMC.ZMIN + 0.9 * EMC.HEIGHTBEAM) then
if vtTool:getZ() > 0 then
dHeadFront = max( 50, 90 - 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX()))
else
dHeadFront = max( 50, 40 + 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX()))
end
if ptMax:getZ() < EMC.ZMIN + BD.VICE_MINH then
dHeadFront = dHeadFront + BD.VICE_MINH
end
elseif ( vtTool:getX() < -0.2 and abs( vtTool:getZ()) < 0.5) then
dHeadFront = max( 90, 40 + 0.5 * dTDiam * sqrt( vtTool:getY() * vtTool:getY() + vtTool:getZ() * vtTool:getZ()))
elseif abs( vtTool:getZ()) < 0.93 then
if vtTool:getX() < 0 and abs( vtTool:getY()) < 0.2 and ptMax:getZ() > EMC.ZMIN + BD.VICE_MINH then
dHeadFront = 180
elseif vtTool:getX() < 0.05 then
dHeadFront = 50 + 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX())
elseif vtTool:getX() < 0.3 then
dHeadFront = 250
elseif vtTool:getX() < 0.707 then
dHeadFront = 350
elseif vtTool:getX() < 0.8667 then
dHeadFront = 450
else
dHeadFront = 480
end
else
dHeadFront = 50 + 0.5 * dTDiam * sqrt( 1 - vtTool:getX() * vtTool:getX())
end
-- per limiti corsa asse X2
dHeadFront = max( dHeadFront, -MaxX2 + 1 + vtTool:getX() * ( MillOffs + dTLen))
else
if ( vtTool:getX() < -0.5 and vtArm:getX() < 0.1) then
dHeadFront = max( 50, dTDiam / 2 * abs( vtTool:getZ()) + 20)
elseif ( vtTool:getX() < 0.1 and vtArm:getX() < 0.1) or
( abs( vtTool:getX()) < 0.1 and abs( vtTool:getZ()) < 0.1) then
dHeadFront = 130
elseif ( vtTool:getX() < 0.1 and vtArm:getX() < 0.95) then
dHeadFront = 180
elseif ( vtTool:getX() > 0.5) then
dHeadFront = 450
end
if vtTool:getX() > 0.25 then
dHeadFront = dHeadFront + max( dTLen - 130, 0) * vtTool:getX()
elseif vtTool:getX() > 0 then
dHeadFront = dHeadFront + ( dTLen + 180) * vtTool:getX()
end
if vtTool:getX() < -0.866 then
dHeadFront = 50
elseif vtTool:getX() <= 0 and dZup > 0 then
dHeadFront = max( 130, dHeadFront - dZup)
end
if abs( vtTool:getX()) < 0.5 and abs( vtTool:getZ()) > 0.259 and dZup < 0 then
if vtArm:getX() > 0.259 then
dHeadFront = 410
else
dHeadFront = EgtIf( vtTool:getZ() > 0.966, 160, 280)
end
end
-- per fresature longitudinali con utensile di fianco
if abs( vtTool:getX()) < 0.1 and vtTool:getZ() < 0.707 and vtArm:getX() > 0.5 then
dHeadFront = 400
end
-- per sega a catena di fianco
if bChain and vtTool:getX() > -0.5 and vtTool:getZ() < 0.5 and vtArm:getX() > 0.5 then
dHeadFront = max( dHeadFront, 510)
end
-- per fresa diretta quasi esattamente come X1+/- e con la testa non troppo nel pezzo
if not bChain and abs( vtTool:getX()) < 0.017 and abs( vtTool:getZ()) < 0.017 and
(( vtTool:getY() > 0 and ptHeadMin:getY() > 80) or ( vtTool:getY() < 0 and ptHeadMax:getY() < -EMC.WIDTHBEAM - 80)) then
dHeadFront = 130
end
-- per limiti corsa asse X2
if not bChain then
dHeadFront = max( dHeadFront, -MaxX2 + 1 + vtTool:getX() * ( MillOffs + dTLen))
else
dHeadFront = max( dHeadFront, -MaxX2 + 1 + vtAux:getX() * ( MillOffs + dTDist) + vtTool:getX() * dTLen)
end
end
-- Stampe debug
EgtOutLog( ' Tdir=' .. tostring( vtTool) .. ' Adir=' .. tostring( vtArm) .. ' Zup=' .. EgtNumToString( dZup), 3)
EgtOutLog( ' DistFront=' .. EgtNumToString( dDistFront) .. ' DistBack=' .. EgtNumToString( dDistBack) ..
' HeadFront=' .. EgtNumToString( dHeadFront) .. ' HeadBack=' .. EgtNumToString( dHeadBack), 3)
-- Restituisco ingombri effettivi
dHeadFront = dHeadFront + 30
dHeadBack = dHeadBack + 30
return ( dDistFront - dHeadFront), ( dDistBack - dHeadBack)
end
---------------------------------------------------------------------
function VerifyPartLength()
-- Verifico lunghezza pezzo
if EMC.LENGTHBEAM < MinJoin + MinOther + AGG_LOAD + EMC.HCING + EMC.HOVM then
EgtOutLog( ' Error CLAMP -> pezzo troppo corto')
EMC.ERR = 17
return false
end
return true
end
---------------------------------------------------------------------
function GetLoadCmd( dPosT, dDistFront, dDistBack)
--[L]
local dMinDistBack= max( dDistBack, MinJoin + EgtIf( IsMid2Phase( EMC.PHASE) or IsEnd2Phase( EMC.PHASE), EMC.TCING, 0))
local dNewX1Delta = max( EMC.LENGTHBEAM - dMinDistBack, MinOther + AGG_LOAD + EMC.HCING + EMC.HOVM)
local dNewX2Delta = nil
local dNewX1 = dPosT + TurnerOffs + dNewX1Delta
local vCmd = {}
EgtOutLog( ' *[L]', 1)
-- [L-1]
if dNewX1 - MaxX1 > 0 then
dNewX1Delta = min( EMC.LENGTHBEAM - MinJoin + AGG_LOAD, MaxX1 - dPosT - TurnerOffs)
EgtOutLog( ' *[L1]', 1)
end
--[L-2]
if EMC.LENGTHBEAM - dNewX1Delta < MinJoin then
dNewX1Delta = min( EMC.LENGTHBEAM - MinJoin + AGG_LOAD, MaxX1 - dPosT - TurnerOffs)
EgtOutLog( ' *[L2]', 1)
end
-- Commento
table.insert( vCmd, { 0, 'Loading'})
-- risalita testa a Zmax
vCmd = AddZmaxMove( vCmd)
-- Apro entrambe le morse
table.insert( vCmd, { 11, 0})
table.insert( vCmd, { 12, 0})
-- Sposto il carrello X1 per il carico
table.insert( vCmd, { 2, 'X1', dPosT + dNewX1Delta, 'X2', ParkX2})
-- Chiudo morsa X1
table.insert( vCmd, { 11, EgtIf( EMC.LENGTHBEAM - dNewX1Delta < LenToPress, 1, 2)})
-- confermo i nuovi parametri di aggancio
table.insert( vCmd, { 21, dNewX1Delta, 0})
-- Assegno stato corrente
EMC.TPOS = dPosT
EMC.X1DELTA = dNewX1Delta
EMC.X2DELTA = nil
-- Restituisco i comandi
return vCmd
end -- SpecAdjustLoad [L]
---------------------------------------------------------------------
function GetMachiningStartingPoint( idPath)
local idFirstObj = EgtGetFirstInGroup( idPath)
-- se esiste l'oggetto, recupero la coordinata del primo punto
if idFirstObj then
local vAxes = EmtGetAxesPos( idFirstObj)
if #vAxes > 0 then
return vAxes[1]
end
end
return nil
end
---------------------------------------------------------------------
function CalcCarriagesNewPositions( dDistFront, dDistBack)
local MinFrontJoin = MinJoin + EMC.HCING + EMC.HOVM
local MinBackJoin = MinJoin + EgtIf( IsMid2Phase( EMC.PHASE) or IsEnd2Phase( EMC.PHASE), EMC.TCING, 0)
local dDistFrontEff = min( dDistFront, EMC.LENGTHBEAM - MinOther - EMC.TCING)
local dDistBackEff = min( dDistBack, EMC.LENGTHBEAM - MinOther - EMC.HCING - EMC.HOVM)
local dNewX1Delta = nil
local dNewX2Delta = nil
-- [A] se posso mettere solo carrello X1
if dDistFrontEff < MinFrontJoin and dDistBackEff > MinBackJoin - GEO.EPS_SMALL then
dNewX1Delta = EMC.LENGTHBEAM - dDistBackEff
dNewX2Delta = nil
-- [B] se altrimenti posso mettere entrambi i carrelli X1 e X2
elseif dDistBackEff > MinBackJoin - GEO.EPS_SMALL and dDistFrontEff > MinFrontJoin - GEO.EPS_SMALL then
dNewX1Delta = EMC.LENGTHBEAM - dDistBackEff
dNewX2Delta = dDistFrontEff
-- [C] se altrimenti posso mettere solo carrello X2
elseif dDistBackEff < MinBackJoin and dDistFrontEff > MinFrontJoin - GEO.EPS_SMALL then
dNewX2Delta = dDistFrontEff
dNewX1Delta = nil
-- altrimenti errore
else
if EgtGetDebugLevel() < 3 then
EgtOutLog( ' Dist/Min : Back=' .. EgtNumToString( dDistBackEff, 1) .. '/' .. EgtNumToString( MinBackJoin, 1) ..
' Front=' .. EgtNumToString( dDistFrontEff, 1) .. '/' .. EgtNumToString( MinFrontJoin, 1))
end
EgtOutLog( ' Error CLAMP impossible')
EMC.ERR = 18
return nil
end
return true, dNewX1Delta, dNewX2Delta
end
---------------------------------------------------------------------
function GetCarriagesCmdFromMachEncumbrance( dDistFront, dDistBack)
local bOk, dNewX1Delta, dNewX2Delta = CalcCarriagesNewPositions( dDistFront, dDistBack)
if not bOk then
return {}
end
local dPosT = EMC.TPOS
local dX1Delta = EMC.X1DELTA
local dX2Delta = EMC.X2DELTA
local dNewPosT
-- se sono già settati, non calcolo posizione finale
if not EMC.X1DELTANEXT and not EMC.X2DELTANEXT then
dNewPosT = GetMachiningStartingPoint( EMC.PATHID)
end
-- salvo valori finali
EMC.X1DELTANEXT = dNewX1Delta
EMC.X2DELTANEXT = dNewX2Delta
-- se la posizione è già corretta, no nserve riposizionare
local bCarriagesPosIsOK = true
local vCmd = {}
local bSpecialStartCarrInPos = false
if IsStartPhase( EMC.PHASE) and EMC.X1DELTA and not EMC.X2DELTA then
if EMC.X1DELTANEXT and EMC.X1DELTA > EMC.X1DELTANEXT and EMC.X2DELTA == nil and EMC.X2DELTANEXT == nil then
bSpecialStartCarrInPos = true
end
end
if not bSpecialStartCarrInPos then
if ( EMC.X1DELTA == nil and EMC.X1DELTANEXT) or ( EMC.X1DELTA and EMC.X1DELTANEXT == nil) then
bCarriagesPosIsOK = bCarriagesPosIsOK and false
end
if ( EMC.X1DELTA and EMC.X1DELTANEXT and abs( EMC.X1DELTA - EMC.X1DELTANEXT) > 1000 * GEO.EPS_SMALL) then
bCarriagesPosIsOK = bCarriagesPosIsOK and false
end
if ( EMC.X2DELTA == nil and EMC.X2DELTANEXT) or ( EMC.X2DELTA and EMC.X2DELTANEXT == nil) then
bCarriagesPosIsOK = bCarriagesPosIsOK and false
end
if ( EMC.X2DELTA and EMC.X2DELTANEXT and abs( EMC.X2DELTA - EMC.X2DELTANEXT) > 1000 * GEO.EPS_SMALL) then
bCarriagesPosIsOK = bCarriagesPosIsOK and false
end
end
if not bCarriagesPosIsOK then
GetCarriagesRepositioningCmd( vCmd, dPosT, dX1Delta, dX2Delta, dNewPosT, dNewX1Delta, dNewX2Delta)
end
return vCmd
end
---------------------------------------------------------------------
function SpecCalcSplit( dLenRaw)
local vCmd = {}
EgtOutLog( ' *[S]', 1)
local bSplit = ( EMC.X2DELTA ~= nil)
local ParkT = LoadT
table.insert( vCmd, { 0, EgtIf( EMC.X2DELTA, 'Split', 'Fall')})
-- determino i grezzi da agganciare al carrello X1 (sono quelli presenti nella fase successiva dispari)
local nNextOddPhase = GetNextStartOrRestPhase( EMC.PHASE)
local nRawId = EgtGetFirstRawPart()
while nRawId do
if EgtVerifyRawPartPhase( nRawId, nNextOddPhase) then
table.insert( vCmd, { 31, nRawId, 'X1'})
end
nRawId = EgtGetNextRawPart( nRawId)
end
-- riporto il carrello X1 al carico con il resto della trave
local dLDelta = EMC.X1DELTA - dLenRaw
table.insert( vCmd, { 1, 'X1', ParkT + dLDelta})
table.insert( vCmd, { 21, 0, EMC.X2DELTA or 0})
-- imposto subito X1 non più attaccato al trave in lavoro
EMC.X1DELTA = nil
-- salvo posizione carrello X1 in disposizione del pezzo dopo split
local PostDispId = EgtGetPhaseDisposition( EMC.PHASE + 1)
if PostDispId then
if not bSplit then
EgtSetInfo( PostDispId, 'TPOS', ParkT)
else
EgtRemoveInfo( PostDispId, 'TPOS')
EgtSetInfo( PostDispId, 'TPARK', ParkT)
end
EgtSetInfo( PostDispId, 'X1POS', ParkT + dLDelta)
end
-- salvo posizione grezzo rimasto e posizione carrello X1 nella disposizione iniziale del pezzo succ (prossima fase dispari)
local NextDispId = EgtGetPhaseDisposition( nNextOddPhase)
if NextDispId then
EgtSetInfo( NextDispId, 'TPOS', ParkT)
EgtSetInfo( NextDispId, 'X1POS', ParkT + dLDelta)
end
return vCmd
end
---------------------------------------------------------------------
function SpecCalcSplitRot( dLenRaw)
local vCmd = {}
EgtOutLog( ' *[SR]', 1)
table.insert( vCmd, { 0, 'SplitRot'})
-- determino i grezzi da agganciare al carrello X1 (sono quelli presenti nella fase successiva dispari)
local vRaw = {}
local nNextOddPhase = GetNextStartOrRestPhase( EMC.PHASE)
local nRawId = EgtGetFirstRawPart()
while nRawId do
if EgtVerifyRawPartPhase( nRawId, nNextOddPhase) then
table.insert( vRaw, nRawId)
end
nRawId = EgtGetNextRawPart( nRawId)
end
for _, nId in ipairs( vRaw) do
table.insert( vCmd, { 31, nId, 'X1'})
end
-- riporto il carrello X1 al carico con il resto della trave
local dLDelta = EMC.X1DELTA - dLenRaw
table.insert( vCmd, { 1, 'X1', LoadT + TurnerOffs + dLDelta})
table.insert( vCmd, { 21, 0, EMC.X2DELTA})
-- imposto subito X1 non più attaccato alla trave in lavoro
EMC.X1DELTA = nil
-- apro il carrello X1
table.insert( vCmd, { 11, 0})
-- sgancio i grezzi dal carrello X1
for _, nId in ipairs( vRaw) do
table.insert( vCmd, { 31, nId, ''})
end
-- lo porto in parcheggio
table.insert( vCmd, { 1, 'X1', ParkX1})
-- salvo posizione grezzo rimasto nella disposizione iniziale del pezzo succ (prossima fase dispari)
local NextDispId = EgtGetPhaseDisposition( nNextOddPhase)
if NextDispId then
EgtSetInfo( NextDispId, 'TPOS', LoadT)
end
return vCmd
end
---------------------------------------------------------------------
function SpecCalcUnload()
local vCmdPre = {}
EgtOutLog( ' *[U]', 1)
-- Se pinza X1 chiusa , devo effettuare uno scambio
if EMC.X1DELTA then
-- determino posizione testa trave
local nLastEntId = EgtGetLastInGroup( EMC.PATHID)
local vAxes = EmtGetAxesPos( nLastEntId)
if #vAxes > 0 then EMC.TPOS = vAxes[1] end
local dX2CurrPos = EgtIf( EMC.X2DELTA, EMC.X2DELTA, EMC.TPOS + MaxX2)
local dX2LastPos = max( ( MinX2 + ( EMC.LENGTHBEAM - UnloadT)), EMC.X1DELTA - ( MinX1 - MaxX2))
EMC.X1DELTANEXT = nil
EMC.X2DELTANEXT = dX2LastPos
-- effettuo scambio
vCmdPre = GetCarriagesRepositioningCmd( vCmdPre, EMC.TPOS, EMC.X1DELTA, nil, nil, nil, dX2LastPos)
if EMC.ERR ~= 0 then
return {}
end
-- recupero nuova posizione carrelli
SpecSetCarrPosFromCmds( vCmdPre)
EgtOutLog( ' *[U1]', 1)
end
local vCmd = {}
-- Tipo di scarico
local bStdUl = ( MaxUnloadLen < 1 or EMC.LENGTHBEAM - EMC.HOVM < MaxUnloadLen + 1)
-- Commento
table.insert( vCmd, { 0, 'Unloading', EgtIf( bStdUl, 'Unloading', 'Manual Unloading')})
-- risalita testa a Zmax
vCmd = AddZmaxMove( vCmd)
-- Se pinza X1 chiusa, la apro
if EMC.X1DELTA then
table.insert( vCmd, { 11, 0})
end
-- Se non supero la lunghezza massima di scarico, sposto il pezzo in posizione di scarico
if bStdUl then
local dFinT = EgtIf( EMC.LENGTHBEAM < MaxLenSmT, UnloadSmT, UnloadT) - EMC.LENGTHBEAM
local dFinX2 = dFinT + EMC.X2DELTA
table.insert( vCmd, { 2, 'T', dFinT, 'X2', dFinX2})
else
table.insert( vCmd, { 1, 'X2', MaxX2})
end
-- apro la morsa
table.insert( vCmd, { 12, 0})
-- riporto il carrello in home
table.insert( vCmd, { 1, 'X2', ParkX2})
-- eventuale unione tabelle
if #vCmdPre > 0 then
vCmd = EgtJoinTables( vCmdPre, vCmd)
end
return vCmd
end
---------------------------------------------------------------------
function SpecCalcPreRot()
local vCmdPre = {}
EgtOutLog( ' *[PR]', 1)
-- Se pinza X2 chiusa , devo effettuare uno scambio
if EMC.X2DELTA then
-- determino posizione testa trave
local nLastEntId = EgtGetLastInGroup( EMC.PATHID)
local vAxes = EmtGetAxesPos( nLastEntId)
if #vAxes > 0 then EMC.TPOS = vAxes[1] end
local dX1CurrPos = EgtIf( EMC.X1DELTA, EMC.X1DELTA, nil)
local dX1LastPos = min ( MaxX1 - LoadT, EMC.X2DELTA + ( MinX1 - MaxX2))
EMC.X1DELTANEXT = dX1LastPos
EMC.X2DELTANEXT = nil
-- effettuo scambio
vCmdPre = GetCarriagesRepositioningCmd( vCmdPre, EMC.TPOS, dX1CurrPos, EMC.X2DELTA, nil, dX1LastPos, nil)
-- recupero nuova posizione carrelli
SpecSetCarrPosFromCmds( vCmdPre)
EgtOutLog( ' *[PR1]', 1)
end
-- porto il pezzo alla zona di rotazione con il carro X1
local vCmd = {}
-- Commento
table.insert( vCmd, { 0, 'Pre-Rotation'})
-- risalita testa a Zmax
vCmd = AddZmaxMove( vCmd)
-- Se pinza X2 chiusa, la apro
if EMC.X2DELTA then
table.insert( vCmd, { 12, 0})
end
-- riporto la trave al carico
local RotT = LoadT + TurnerOffs - EMC.HOVM
table.insert( vCmd, { 2, 'X1', RotT + EMC.X1DELTA, 'T', RotT})
-- apro la morsa
table.insert( vCmd, { 11, 0})
-- riporto il carrello in home
table.insert( vCmd, { 1, 'X1', ParkX1})
-- dichiaro fine movimenti
table.insert( vCmd, { 0, 'Move_End'})
-- eventuale unione tabelle
if #vCmdPre > 0 then
vCmd = EgtJoinTables( vCmdPre, vCmd)
end
return vCmd
end
---------------------------------------------------------------------
local function CalcCharStatus( sType, dDelta)
-- se per carrello X1
if sType == 'X1' then
return EgtIf( EMC.LENGTHBEAM - dDelta < LenToPress, 1, 2)
-- altrimenti per carrello X2
else
return EgtIf( dDelta < LenToPress, 1, 2)
end
end
---------------------------------------------------------------------
function GetCarriagesRepositioningCmd( vCmd, dTPosI, dX1DeltaI, dX2DeltaI, dTPosF, dX1DeltaF, dX2DeltaF)
local dX1PosA, dX2PosA, dTPosA
local dGainOnReclamping = BD.GAIN_RECLAMPING or 1000
-- se primo scambio
local MyMinX1 = MinX1
-- se pinza non in presa, setto offset minimo in base all'altra che sta pinzando
if not dX1DeltaI then
dX1DeltaI = dX2DeltaI + ( MyMinX1 - MaxX2)
end
if not dX2DeltaI then
dX2DeltaI = dX1DeltaI - ( MyMinX1 - MaxX2)
end
if not dX1DeltaF then
dX1DeltaF = dX2DeltaF + ( MyMinX1 - MaxX2)
end
if not dX2DeltaF then
dX2DeltaF = dX1DeltaF - ( MyMinX1 - MaxX2)
end
-- se non c'è posizione finale, è lo scarico. Allora setto al minimo della morsa allo scarico.
if not dTPosF then
dTPosF = MaxX2 - dX2DeltaF
end
-- se il pinzaggio deve essere invertito forzo entrata nei riposizionamenti
-- altrimenti posizioni iniziali e finali sono coincidenti dato che la pinza non in presa viene posizionata alla distanza minima a quella in presa
local bInvertClamping = not EMC.PILGRIMSTEP and EMC.X1DELTA ~= EMC.X1DELTANEXT and EMC.X2DELTA ~= EMC.X2DELTANEXT
-- verifico che le morse non sono in posizione
if ( abs( dX1DeltaF - dX1DeltaI) > 10 * GEO.EPS_SMALL or abs( dX2DeltaF - dX2DeltaI) > 10 * GEO.EPS_SMALL or bInvertClamping) and
( EMC.X1DELTA ~= EMC.X1DELTANEXT or EMC.X2DELTA ~= EMC.X2DELTANEXT) then
if #vCmd == 0 then
table.insert( vCmd, { 0, 'Clamp repositioning'})
-- risalita testa a Zmax
vCmd = AddZmaxMove( vCmd)
end
-- si ribadisce il pinzaggio
if EMC.X1DELTA then
table.insert( vCmd, { 11, 1})
end
if EMC.X2DELTA then
table.insert( vCmd, { 12, 1})
end
-- ricavo posizione delle morse nelle corse
local dX1PosI = max( MyMinX1, dTPosI + dX1DeltaI)
local dX2PosI = min( MaxX2, dTPosI + dX2DeltaI)
-- calcolo eventuale massimo riposizionamento con passo del pellegrino.
-- al primo step si calcolano posizioni attuali delle morse
-- al secondo step si considerano le corse massime
local dMaxMovePilgrimStepDoubleClamp, dMaxMovePilgrimStepSingleClampX1, dMaxMovePilgrimStepSingleClampX2
if not EMC.PILGRIMSTEP then
dMaxMovePilgrimStepDoubleClamp = MaxX1 - dX1PosI - MinX2 + dX2PosI
dMaxMovePilgrimStepSingleClampX1 = MaxX1 - dX1PosI
dMaxMovePilgrimStepSingleClampX2 = - MinX2 + dX2PosI
else
dMaxMovePilgrimStepDoubleClamp = MaxX1 - MinX1 - MinX2 + MaxX2
dMaxMovePilgrimStepSingleClampX1 = MaxX1 - MinX1
dMaxMovePilgrimStepSingleClampX2 = - MinX2 + MaxX2
end
-- calcolo delta spostamento trave
local dDeltaBeam = dTPosI - dTPosF -- se positivo, la trave si sposta dal carico allo scarico
local dBeamMove = 0
-- PRIMO CASO -> SCAMBIO DIRETTO : X2 IN POSIZIONE FINALE
-- X2 può andare in posizione direttamente se :
-- * rispetta interasse minimo con X1
-- * deve effettivamente spostarsi
-- * non si arriva da gestione passo del pellegrino
-- * se riesce a raggiungere la posizione con le corse a disposizione per come sono posizionate le morse attualmente
if ( dX1DeltaI - dX2DeltaF) + 10 * GEO.EPS_SMALL >= MyMinX1 - MaxX2 and
( abs( dX2DeltaF - dX2DeltaI) > 10 * GEO.EPS_SMALL or not EMC.X2DELTA) and
not EMC.PILGRIMSTEP and
( dX2DeltaF - dX2DeltaI > MinX2 - dX2PosI + MyMinX1 - dX1PosI) then
table.insert( vCmd, { 0, 'Direct-X2-X1'})
-- se l'altra morsa non era in presa, vado a pinzare il pezzo
if not EMC.X1DELTA then
dX1PosA = MyMinX1
dTPosA = MyMinX1 - dX1DeltaI
dX2PosA = dTPosA + dX2DeltaI
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
dTPosI = dTPosA
dX2PosI = dX2PosA
table.insert( vCmd, { 11, 1})
end
-- se spostando morsa diretto esco dalle corse, calcolo di quanto devo muovere la trave (cioè l'altra morsa) come minimo
-- se non era ingaggiata, vado al suo minimo
if not EMC.X2DELTA then
dBeamMove = -( MaxX2 - dX2DeltaF - dTPosI)
-- se spostamento verso lo scarico
elseif ( dX2PosI + ( dX2DeltaF - dX2DeltaI)) < MinX2 then
dBeamMove = dX2PosI + ( dX2DeltaF - dX2DeltaI) - MinX2
-- se spostamento verso il carico
elseif ( dX2PosI + ( dX2DeltaF - dX2DeltaI)) > MaxX2 then
dBeamMove = dX2PosI + ( dX2DeltaF - dX2DeltaI) - MaxX2
-- se è FASTCLAMPING attivo, si suddivide il movimento
elseif BD.FASTCLAMPING then
-- se la trave si sposta dal carico verso lo scarico
if dTPosI - dTPosF > 0 then
dBeamMove = min( -( dTPosF - dTPosI), -( MyMinX1 - dX1PosI), -( dX2DeltaI - dX2DeltaF))
else
dBeamMove = max( -( dTPosF - dTPosI), -( MyMinX1 - dX1PosI))
end
dBeamMove = dBeamMove / 2
-- altrimenti la trave resta ferma e la pinza 1 va in presa (si limita lo scivolamento del pezzo)
else
;
end
-- se serve un grande spostamento e si sta pinzando poco. X1 trascinatore pinza poco e X2 si sposta per prima per recuperare
if not BD.FASTCLAMPING and abs( dBeamMove) > 2000 and dDeltaBeam < 0 and EMC.LENGTHBEAM - dX1DeltaI < max( 550, (MinJoin * 2)) then
table.insert( vCmd, { 12, 0})
dX2PosA = dX2PosI - dGainOnReclamping
-- sposto il carrello X2 di 1000mm
table.insert( vCmd, { 1, 'X2', dX2PosA})
table.insert( vCmd, { 12, 1})
-- apro morsa X1 e recupero i 1000mm
table.insert( vCmd, { 11, 0})
dX2PosA = dX2PosI
dX1PosA = dX1PosI
dTPosA = dTPosI + dGainOnReclamping
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
dTPosI = dTPosA
dX2PosI = dX2PosA
dX2DeltaI = dX2DeltaI - dGainOnReclamping
dX1DeltaI = dX1DeltaI - dGainOnReclamping
table.insert( vCmd, { 11, 1})
dBeamMove = dBeamMove + dGainOnReclamping
end
table.insert( vCmd, { 12, 0})
dTPosA = dTPosI - dBeamMove
dX1PosA = dTPosA + dX1DeltaI
dX2PosA = dTPosA + dX2DeltaF
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
-- la morsa allo scarico è adesso in posizione
dX2DeltaI = dX2DeltaF
dTPosI = dTPosA
-- blocco la morsa
table.insert( vCmd, { 12, CalcCharStatus( 'X2', dX2DeltaF)})
-- imposto i nuovi parametri di aggancio
if EMC.X1DELTANEXT and EMC.X2DELTANEXT then
-- porto assi alla loro posizione finale
if abs( dX1DeltaF - dX1DeltaI) > 10 * GEO.EPS_SMALL then
table.insert( vCmd, { 11, 0})
dTPosA = dTPosF
dX1PosA = dTPosF + dX1DeltaF
dX2PosA = dTPosF + dX2DeltaF
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 11, CalcCharStatus( 'X1', dX1DeltaF)})
-- la morsa al carico è adesso in posizione
dX1DeltaI = dX1DeltaF
end
table.insert( vCmd, { 21, dX1DeltaF, dX2DeltaF})
elseif EMC.X1DELTANEXT then
if abs( dX1DeltaF - dX1DeltaI) > 10 * GEO.EPS_SMALL then
table.insert( vCmd, { 11, 0})
dX1PosA = max( MyMinX1, dTPosI + dX1DeltaF)
dTPosA = dX1PosA - dX1DeltaF
dX2PosA = dTPosA + dX2DeltaF
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 11, CalcCharStatus( 'X1', dX1DeltaF)})
-- la morsa al carico è adesso in posizione
dX1DeltaI = dX1DeltaF
end
table.insert( vCmd, { 12, 0})
-- sposto il carrello X2 in parcheggio
table.insert( vCmd, { 1, 'X2', ParkX2})
table.insert( vCmd, { 21, dX1DeltaF, 0})
else
table.insert( vCmd, { 11, 0})
table.insert( vCmd, { 1, 'X1', ParkX1})
table.insert( vCmd, { 21, 0, dX2DeltaF})
end
-- movimento terminato
dTPosI, dX1DeltaI, dX2DeltaI = dTPosF, dX1DeltaF, dX2DeltaF
EMC.X1DELTA = EMC.X1DELTANEXT
EMC.X2DELTA = EMC.X2DELTANEXT
-- SECONDO CASO -> SCAMBIO DIRETTO : X1 IN POSIZIONE FINALE
-- X1 può andare in posizione direttamente se :
-- * rispetta interasse minimo con X1
-- * deve effettivamente spostarsi
-- * non si arriva da gestione passo del pellegrino
-- * se riesce a raggiungere la posizione con le corse a disposizione per come sono posizionate le morse attualmente
elseif ( dX1DeltaF - dX2DeltaI) + 10 * GEO.EPS_SMALL >= MyMinX1 - MaxX2 and
( abs( dX1DeltaF - dX1DeltaI) > 10 * GEO.EPS_SMALL or not EMC.X1DELTA) and
not EMC.PILGRIMSTEP and
( dX1DeltaF - dX1DeltaI < MaxX1 - dX1PosI + MaxX2 - dX2PosI) then
table.insert( vCmd, { 0, 'Direct-X1-X2'})
-- se l'altra morsa non era in presa, vado a pinzare il pezzo
if not EMC.X2DELTA then
dX2PosA = MaxX2
dTPosA = MaxX2 - dX2DeltaI
dX1PosA = dTPosA + dX1DeltaI
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
dTPosI = dTPosA
dX1PosI = dX1PosA
table.insert( vCmd, { 12, 1})
end
-- se spostando morsa diretto esco dalle corse, calcolo di quanto devo muovere la trave (cioè l'altra morsa) come minimo
-- se non era ingaggiata, vado al suo minimo
if not EMC.X1DELTA then
dBeamMove = - ( dX1DeltaF - MyMinX1 + dTPosI)
-- se spostamento verso lo scarico
elseif ( dX1PosI + ( dX1DeltaF - dX1DeltaI)) < MyMinX1 then
dBeamMove = -( dX1PosI + ( dX1DeltaF - dX1DeltaI) - MyMinX1)
-- se spostamento verso il carico
elseif ( dX1PosI + ( dX1DeltaF - dX1DeltaI)) > MaxX1 then
dBeamMove = -( dX1PosI + ( dX1DeltaF - dX1DeltaI) - MaxX1)
-- se è FASTCLAMPING attivo, si suddivide il movimento
elseif BD.FASTCLAMPING then
-- se la trave si sposta dal carico verso lo scarico
if dTPosI - dTPosF > 0 then
dBeamMove = max( ( dTPosF - dTPosI), ( MinX2 - dX2PosI), ( dX1DeltaI - dX1DeltaF))
else
dBeamMove = min( ( dTPosF - dTPosI), ( dX2PosI - MaxX2))
end
dBeamMove = dBeamMove / 2
-- altrimenti la trave resta ferma e la pinza 1 va in presa (si limita lo scivolamento del pezzo)
else
;
end
-- se serve un grande spostamento e si sta pinzando poco. X2 trascinatore pinza poco e X1 si sposta per prima per recuperare
if not BD.FASTCLAMPING and abs( dBeamMove) > 2000 and dDeltaBeam > 0 and dX2DeltaI < max( 550, (MinJoin * 2)) then
table.insert( vCmd, { 11, 0})
dX1PosA = dX1PosI + dGainOnReclamping
-- sposto il carrello X2 di 1000mm
table.insert( vCmd, { 1, 'X1', dX1PosA})
table.insert( vCmd, { 11, 1})
-- apro morsa X1 e recupero i 1000mm
table.insert( vCmd, { 12, 0})
dX2PosA = dX2PosI
dX1PosA = dX1PosI
dTPosA = dTPosI - dGainOnReclamping
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
dTPosI = dTPosA
dX2PosI = dX2PosA
dX2DeltaI = dX2DeltaI + dGainOnReclamping
dX1DeltaI = dX1DeltaI + dGainOnReclamping
table.insert( vCmd, { 12, 1})
dBeamMove = dBeamMove - dGainOnReclamping
end
table.insert( vCmd, { 11, 0})
dTPosA = dTPosI + dBeamMove
dX1PosA = dTPosA + dX1DeltaF
dX2PosA = dTPosA + dX2DeltaI
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
-- la morsa al carico è adesso in posizione
dX1DeltaI = dX1DeltaF
dTPosI = dTPosA
-- blocco la morsa
table.insert( vCmd, { 11, CalcCharStatus( 'X1', dX1DeltaF)})
-- imposto i nuovi parametri di aggancio
if EMC.X1DELTANEXT and EMC.X2DELTANEXT then
if abs( dX2DeltaF - dX2DeltaI) > 10 * GEO.EPS_SMALL then
table.insert( vCmd, { 12, 0})
dTPosA = dTPosF
dX1PosA = dTPosF + dX1DeltaF
dX2PosA = dTPosF + dX2DeltaF
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 12, CalcCharStatus( 'X2', dX2DeltaF)})
-- la morsa al carico è adesso in posizione
dX2DeltaI = dX2DeltaF
end
table.insert( vCmd, { 21, dX1DeltaF, dX2DeltaF})
elseif EMC.X2DELTANEXT then
if abs( dX2DeltaF - dX2DeltaI) > 10 * GEO.EPS_SMALL then
table.insert( vCmd, { 12, 0})
dX2PosA = min( MaxX2, dTPosI + dX2DeltaF)
dTPosA = dX2PosA - dX2DeltaF
dX1PosA = dTPosA + dX1DeltaF
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 12, CalcCharStatus( 'X2', dX2DeltaF)})
-- la morsa al carico è adesso in posizione
dX2DeltaI = dX2DeltaF
end
table.insert( vCmd, { 11, 0})
-- sposto il carrello X1 in parcheggio
table.insert( vCmd, { 1, 'X1', ParkX1})
table.insert( vCmd, { 21, 0, dX2DeltaF})
else
table.insert( vCmd, { 12, 0})
-- sposto il carrello X2 in parcheggio
table.insert( vCmd, { 1, 'X2', ParkX2})
table.insert( vCmd, { 21, dX1DeltaF, 0})
end
-- movimento terminato
dTPosI, dX1DeltaI, dX2DeltaI = dTPosF, dX1DeltaF, dX2DeltaF
EMC.X1DELTA = EMC.X1DELTANEXT
EMC.X2DELTA = EMC.X2DELTANEXT
-- TERZO CASO -> PASSO DEL PELLEGRINO
-- non è possibile fare scambio diretto.
-- le morse vengono compattate e allargate sfruttando tutta la corsa X, massimizzando spostamento trave
else
EMC.PILGRIMSTEP = false
local bUpdateValues = false
table.insert( vCmd, { 0, 'Pilgrim Cycle'})
-- compatto al centro
if not EMC.X1DELTA then
table.insert( vCmd, { 0, 'Compact X1'})
table.insert( vCmd, { 11, 0})
dTPosA = MaxX2 - dX2DeltaI
dX2PosA = MaxX2
dX1PosA = MyMinX1
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 11, 1})
dX1DeltaI = dX2DeltaI - MaxX2 + MyMinX1
EMC.X1DELTA = dX1DeltaI
bUpdateValues = true
end
if not EMC.X2DELTA then
table.insert( vCmd, { 0, 'Compact X2'})
table.insert( vCmd, { 12, 0})
dTPosA = MyMinX1 - dX1DeltaI
dX2PosA = MaxX2
dX1PosA = MyMinX1
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 12, 1})
dX2DeltaI = dX1DeltaI + MaxX2 - MyMinX1
EMC.X2DELTA = dX2DeltaI
bUpdateValues = true
end
-- se si sono compattate le morse, bisogna aggiornare le posizioni e i massimi recuperi
if bUpdateValues then
dTPosI = dTPosA
dX1PosI = dX1PosA
dX2PosI = dX2PosA
dMaxMovePilgrimStepDoubleClamp = MaxX1 - MinX1 - MinX2 + MaxX2
dMaxMovePilgrimStepSingleClampX1 = MaxX1 - MinX1
dMaxMovePilgrimStepSingleClampX2 = - MinX2 + MaxX2
end
-- aggiorno delta mancante
dDeltaBeam = dTPosI - dTPosF
-- a questo punto entrambe le pinze sono in presa sul pezzo.
-- trave si muove dal carico allo scarico
-- Il trascinatore si decide in base alla direzione di movimento trave
-- trascino con morsa allo scarico. Obiettivo mandare X1 in posizione per prima
if dDeltaBeam > 0 then
-- se serve un grande spostamento e si sta pinzando poco. X1 trascinatore pinza poco e X2 si sposta per prima per recuperare
if not BD.FASTCLAMPING and abs( dDeltaBeam) > 2000 and dX2DeltaI < max( 550, (MinJoin * 2)) then
table.insert( vCmd, { 11, 0})
dX1PosA = dX1PosI + dGainOnReclamping
-- sposto il carrello X2 di 1000mm
table.insert( vCmd, { 1, 'X1', dX1PosA})
table.insert( vCmd, { 11, 1})
-- apro morsa X1 e recupero i 1000mm
table.insert( vCmd, { 12, 0})
dX2PosA = dX2PosI
dX1PosA = dX1PosI
dTPosA = dTPosI - dGainOnReclamping
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
dTPosI = dTPosA
dX2PosI = dX2PosA
dX2DeltaI = dX2DeltaI + dGainOnReclamping
dX1DeltaI = dX1DeltaI + dGainOnReclamping
table.insert( vCmd, { 12, 1})
end
-- apro morsa al carico
table.insert( vCmd, { 11, 0})
-- devo recuperare più delle corse disponibili di entrambi i carrelli
if abs( dX1DeltaI - dX1DeltaF) > dMaxMovePilgrimStepDoubleClamp then
dX1PosA = MaxX1
dX2PosA = MinX2
dTPosA = dTPosI - dX2PosI + MinX2
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 11, 1})
table.insert( vCmd, { 12, 0})
-- nuova posizione della morsa al carico dopo riposizionamento
dX1DeltaI = MaxX1 - dTPosA
dTPosI = dTPosA
EMC.X1DELTA = dX1DeltaI
EMC.X2DELTA = nil
EMC.PILGRIMSTEP = true
-- mi serve riposizonare di nuovo, quindi richiamo funzione in modo ricorsivo
vCmd = GetCarriagesRepositioningCmd( vCmd, dTPosI, dX1DeltaI, dX2DeltaI, dTPosF, dX1DeltaF, dX2DeltaF)
-- recupero una corsa massima e l'altra solo di quello che serve
elseif abs( dX1DeltaI - dX1DeltaF) > dMaxMovePilgrimStepSingleClampX2 then
-- suddivido il movimento su entrambe le morse
local dTotMove = ( dX1DeltaF - dX1DeltaI) / 2
-- morsa X1 arriva in posizione finale
dX2PosA = MaxX2 - dTotMove
dTPosA = dTPosI - dX2PosI + MaxX2 - dTotMove
dX1PosA = dX1DeltaF + dTPosA
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 11, CalcCharStatus( 'X1', dX1DeltaF)})
table.insert( vCmd, { 12, 0})
dX1DeltaI = dX1DeltaF
dTPosI = dTPosA
EMC.X1DELTA = dX1DeltaF
EMC.X2DELTA = nil
-- mi serve riposizonare di nuovo, quindi richiamo funzione in modo ricorsivo
vCmd = GetCarriagesRepositioningCmd( vCmd, dTPosI, dX1DeltaI, dX2DeltaI, dTPosF, dX1DeltaF, dX2DeltaF)
-- non serve recuperare al massimo della corsa, suddivido movimento in due
else
-- suddivido il movimento su entrambe le morse
local dTotMove = ( dX1DeltaF - dX1DeltaI) / 2
if abs( dTotMove) > 10 * GEO.EPS_SMALL then
dX1PosA = dTPosI + dX1DeltaI + dTotMove
dX2PosA = dTPosI + dX2DeltaI - dTotMove
dTPosA = dTPosI - dTotMove
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 11, CalcCharStatus( 'X1', dX1DeltaF)})
table.insert( vCmd, { 12, 0})
-- aggiorno nuova posizione della morsa al carico dopo riposizionamento
dX1DeltaI = dX1DeltaF ;
if not EMC.X2DELTANEXT then
dTPosA = dTPosF
dX1PosA = dTPosF + dX1DeltaF
dX2PosA = ParkX2
elseif EMC.X1DELTANEXT then
dTPosA = dTPosF
dX1PosA = dTPosF + dX1DeltaF
dX2PosA = dTPosF + dX2DeltaF
else
dX1PosA = MyMinX1
dTPosA = MyMinX1 - dX1DeltaF
dX2PosA = dTPosA + dX2DeltaF
end
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
dTPosI, dX1DeltaI, dX2DeltaI = dTPosF, dX1DeltaF, dX2DeltaF
EMC.X1DELTA = EMC.X1DELTANEXT
EMC.X2DELTA = EMC.X2DELTANEXT
end
-- imposto i nuovi parametri di aggancio
if EMC.X1DELTANEXT and EMC.X2DELTANEXT then
table.insert( vCmd, { 12, CalcCharStatus( 'X2', dX2DeltaF)})
table.insert( vCmd, { 21, dX1DeltaF, dX2DeltaF})
elseif EMC.X1DELTANEXT then
table.insert( vCmd, { 21, dX1DeltaF, 0})
else
table.insert( vCmd, { 12, CalcCharStatus( 'X2', dX2DeltaF)})
table.insert( vCmd, { 11, 0})
-- sposto il carrello X1 in parcheggio
table.insert( vCmd, { 1, 'X1', ParkX1})
table.insert( vCmd, { 21, 0, dX2DeltaF})
end
end
-- trave si muove dallo scarico verso il carico. Obiettivo mandare X2 in posizione per prima
else
-- se serve un grande spostamento e si sta pinzando poco. X1 trascinatore pinza poco e X2 si sposta per prima per recuperare
if not BD.FASTCLAMPING and abs( dDeltaBeam) > 2000 and EMC.LENGTHBEAM - dX1DeltaI < max( 550, (MinJoin * 2)) then
table.insert( vCmd, { 12, 0})
dX2PosA = dX2PosI - dGainOnReclamping
-- sposto il carrello X2 di 1000mm
table.insert( vCmd, { 1, 'X2', dX2PosA})
table.insert( vCmd, { 12, 1})
-- apro morsa X1 e recupero i 1000mm
table.insert( vCmd, { 11, 0})
dX2PosA = dX2PosI
dX1PosA = dX1PosI
dTPosA = dTPosI + dGainOnReclamping
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
dTPosI = dTPosA
dX2PosI = dX2PosA
dX2DeltaI = dX2DeltaI - dGainOnReclamping
dX1DeltaI = dX1DeltaI - dGainOnReclamping
table.insert( vCmd, { 11, 1})
end
-- apro morsa allo scarico
table.insert( vCmd, { 12, 0})
-- devo recuperare più del doppio delle corse
local dMaxMoveFirst
if abs( dX2DeltaI - dX2DeltaF) > dMaxMovePilgrimStepDoubleClamp then
dX1PosA = MaxX1
dX2PosA = MinX2
dTPosA = dTPosI + ( MaxX1 - dX1PosI)
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 12, 1})
table.insert( vCmd, { 11, 0})
-- nuova posizione della morsa allo scarico dopo riposizionamento
dX2DeltaI = MinX2 - dTPosA
dTPosI = dTPosA
EMC.X1DELTA = nil
EMC.X2DELTA = dX2DeltaI
EMC.PILGRIMSTEP = true
-- mi serve riposizonare di nuovo, quindi richiamo funzione in modo ricorsivo
vCmd = GetCarriagesRepositioningCmd( vCmd, dTPosI, dX1DeltaI, dX2DeltaI, dTPosF, dX1DeltaF, dX2DeltaF)
-- recupero una corsa massima e l'altra solo di quello che serve
elseif abs( dX2DeltaI - dX2DeltaF) > dMaxMovePilgrimStepSingleClampX1 then
-- suddivido il movimento su entrambe le morse
local dTotMove = ( dX2DeltaI - dX2DeltaF) / 2
-- morsa X2 arriva in posizione finale
dX1PosA = MaxX1 + dTotMove
dTPosA = dTPosI + ( MaxX1 - dX1PosI) + dTotMove
dX2PosA = dX2DeltaF + dTPosA
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 12, CalcCharStatus( 'X2', dX2DeltaF)})
table.insert( vCmd, { 11, 0})
dX2DeltaI = dX2DeltaF
dTPosI = dTPosA
EMC.X1DELTA = nil
EMC.X2DELTA = dX2DeltaF
-- mi serve riposizonare di nuovo, quindi richiamo funzione in modo ricorsivo
vCmd = GetCarriagesRepositioningCmd( vCmd, dTPosI, dX1DeltaI, dX2DeltaI, dTPosF, dX1DeltaF, dX2DeltaF)
-- non serve recuperare al massimo della corsa, suddivido movimento in due
else
-- suddivido il movimento su entrambe le morse
local dTotMove = ( dX2DeltaI - dX2DeltaF) / 2
if abs( dTotMove) > 10 * GEO.EPS_SMALL then
dX1PosA = dTPosI + dX1DeltaI + dTotMove
dX2PosA = dTPosI + dX2DeltaI - dTotMove
dTPosA = dTPosI + dTotMove
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
table.insert( vCmd, { 12, CalcCharStatus( 'X2', dX2DeltaF)})
table.insert( vCmd, { 11, 0})
-- aggiorno nuova posizione della morsa allo scarico dopo riposizionamento
dX2DeltaI = dX2DeltaF ;
if not EMC.X1DELTANEXT then
dTPosA = dTPosF
dX2PosA = dTPosF + dX2DeltaF
dX1PosA = ParkX1
elseif EMC.X2DELTANEXT then
dTPosA = dTPosF
dX1PosA = dTPosF + dX1DeltaF
dX2PosA = dTPosF + dX2DeltaF
else
dX2PosA = MaxX2
dTPosA = MaxX2 - dX2DeltaF
dX1PosA = dTPosA + dX1DeltaF
end
table.insert( vCmd, { 3, 'X1', dX1PosA , 'T', dTPosA, 'X2', dX2PosA})
dTPosI, dX1DeltaI, dX2DeltaI = dTPosF, dX1DeltaF, dX2DeltaF
EMC.X1DELTA = EMC.X1DELTANEXT
EMC.X2DELTA = EMC.X2DELTANEXT
end
-- imposto i nuovi parametri di aggancio
if EMC.X1DELTANEXT and EMC.X2DELTANEXT then
table.insert( vCmd, { 11, CalcCharStatus( 'X1', dX1DeltaF)})
table.insert( vCmd, { 21, dX1DeltaF, dX2DeltaF})
elseif EMC.X1DELTANEXT then
table.insert( vCmd, { 11, CalcCharStatus( 'X1', dX1DeltaF)})
-- sposto il carrello X1 in parcheggio
table.insert( vCmd, { 12, 0})
table.insert( vCmd, { 1, 'X2', ParkX2})
table.insert( vCmd, { 21, dX1DeltaF, 0})
else
table.insert( vCmd, { 21, 0, dX2DeltaF})
end
end
end
end
end
return vCmd
end
---------------------------------------------------------------------
function SpecOutputCmds( vCmd, bEnd)
local sRoot = EgtIf( not bEnd, 'AS', 'AE')
-- Registro il numero di comandi
if #vCmd > 0 then
EgtSetInfo( EMC.PATHID, sRoot..'#', #vCmd)
else
EgtRemoveInfo( EMC.PATHID, sRoot..'#')
end
-- Registro i comandi
for i = 1, #vCmd do
local Cmd = vCmd[i]
local sKey = sRoot..tostring( i)
-- commento
if Cmd[1] == 0 then
local sInfo = '0,'..Cmd[2]
if Cmd[3] then sInfo = sInfo..','..Cmd[3] end
EgtSetInfo( EMC.PATHID, sKey, sInfo)
-- movimento di 1 asse
elseif Cmd[1] == 1 then
local sInfo = '1,'..Cmd[2]..','..EgtNumToString( Cmd[3],3)
EgtSetInfo( EMC.PATHID, sKey, sInfo)
-- movimento di 2 assi
elseif Cmd[1] == 2 then
local sInfo = '2,'..Cmd[2]..','..EgtNumToString( Cmd[3],3)..','..Cmd[4]..','..EgtNumToString( Cmd[5],3)
EgtSetInfo( EMC.PATHID, sKey, sInfo)
-- movimento di 3 assi
elseif Cmd[1] == 3 then
local sInfo = '3,'..Cmd[2]..','..EgtNumToString( Cmd[3],3)..','..Cmd[4]..','..EgtNumToString( Cmd[5],3)..','..
Cmd[6]..','..EgtNumToString( Cmd[7],3)
EgtSetInfo( EMC.PATHID, sKey, sInfo)
-- apertura/chiusura morsa X1
elseif Cmd[1] == 11 then
local sInfo = '11,'..EgtNumToString( Cmd[2],0)
EgtSetInfo( EMC.PATHID, sKey, sInfo)
if Cmd[2] == 0 then EMC.X1DELTA = nil end
-- apertura/chiusura morsa X2
elseif Cmd[1] == 12 then
local sInfo = '12,'..EgtNumToString( Cmd[2],0)
EgtSetInfo( EMC.PATHID, sKey, sInfo)
if Cmd[2] == 0 then EMC.X2DELTA = nil end
-- impostazione nuovo stato dei carrelli
elseif Cmd[1] == 21 then
local sInfo = '21,'..EgtNumToString( Cmd[2],3)..','..EgtNumToString( Cmd[3],3)
EgtSetInfo( EMC.PATHID, sKey, sInfo)
if Cmd[2] > 0 and Cmd[3] > 0 then
EMC.X1DELTA = Cmd[2]
EMC.X2DELTA = Cmd[3]
elseif Cmd[2] > 0 then
EMC.X1DELTA = Cmd[2]
EMC.X2DELTA = nil
elseif Cmd[3] > 0 then
EMC.X1DELTA = nil
EMC.X2DELTA = Cmd[3]
end
-- aggancio grezzo a carrello
elseif Cmd[1] == 31 then
local sInfo = '31,'..EgtNumToString( Cmd[2],0)..','..Cmd[3]
EgtSetInfo( EMC.PATHID, sKey, sInfo)
end
end
-- gli ingombri della lavorazione sono sempre salvati
if EMC.DISTBACK then
EgtSetInfo( EMC.PATHID, 'DISTBACK', EMC.DISTBACK)
else
EgtRemoveInfo( EMC.PATHID, 'DISTBACK')
end
if EMC.DISTFRONT then
EgtSetInfo( EMC.PATHID, 'DISTFRONT', EMC.DISTFRONT)
else
EgtRemoveInfo( EMC.PATHID, 'DISTFRONT')
end
-- Salvo i nuovi delta dei carrelli
if EMC.X1DELTA then
EgtSetInfo( EMC.PATHID, 'X1DELTA', EMC.X1DELTA)
else
EgtRemoveInfo( EMC.PATHID, 'X1DELTA')
end
if EMC.X2DELTA then
EgtSetInfo( EMC.PATHID, 'X2DELTA', EMC.X2DELTA)
else
EgtRemoveInfo( EMC.PATHID, 'X2DELTA')
end
end
---------------------------------------------------------------------
function SpecSetCarrPosFromCmds( vCmd)
-- recupero nuova posizione carrelli
for i = 1, #vCmd do
local Cmd = vCmd[i]
if Cmd[1] == 21 then
if Cmd[2] > 0 and Cmd[3] > 0 then
EMC.X1DELTA = Cmd[2]
EMC.X2DELTA = Cmd[3]
elseif Cmd[2] > 0 then
EMC.X1DELTA = Cmd[2]
EMC.X2DELTA = nil
elseif Cmd[3] > 0 then
EMC.X1DELTA = nil
EMC.X2DELTA = Cmd[3]
end
end
end
end
---------------------------------------------------------------------
function SpecTestOnlyRemarkInCmds( vCmd)
if not vCmd then return true end
-- verifico se nella lista dei comandi ci sono solo commenti
for i = 1, #vCmd do
if vCmd[i][1] ~= 0 then
return false
end
end
return true
end