'Code by Johan Schoeman (August 2025).
'© August 2025 Johan Schoeman. All rights reserved.
'The base of this code was developed and tested on Saturday 23 and Sunday 24 August 2025 using a mockup at home with 24vdc LED lights simulating the banks of IR lights.
'Control 4 x IR light banks (or more/less) on a Uteco Onyx based on calculated speed of the machine at any time using a PNP proximity switch and a target on the steel chill roller of the machine
'without the need for any intervention by operators to avoid a web burn.
'The code can be used on any of the Controllino PLC's (i.e mini, maxi, mega or any variant thereof) provided you have access to B4R and can select the equivalent Arduino board and map the pins correctly
'This code can be adapted for use on any other CI printing machine making use of water based inks (using a suitable Controllino variant)
'The code does not provide for PID control (but can be incorporated) to control intensity of individual lamps but at present only
'controls "intensity" by switching on/off banks of IR lights relative to the speed that the CI press is running at - a suitable and accurate web temperature measurement sensor will be required.
'Other versions could included PWM control of individual IR lamps to control intensity of individual lamps/lights and PID control based on an inline temperature measurement of the running web.
'On the camera "cage" of the Uteco Onyx a bank of 10+ IR lamps can be installed and can then be selected individually by the operator from a TFT interface/display at the operator station to accommodate:
' 1. LDPE, PET, BOPP, etc
' 2. Surface print / reverse print (the web around the camera changes when doing reverse/surface print)
' 3. The IR lights to installed in such a way as to avoid heating up sensitive electronic equipment such as sensors, cameras, etc while also transferring heat to the path rollers mounted before, inside, and after the camera cage.
' 4. Single turn or multiple turn pots can be installed at the operator station to set the machine speed for lamps to switch on/off
' 5. The chiller feeding the chill roller must be fully operational and chiller roller not blocked to ensure sufficient cooling of the web before winding to avoid post cooling and core crushing - the web exists the camera cage at pre-shrinkage temperature and needs to be cooled before winding to avoud shrinkage and possible paper based core collapse.
#Region Project Attributes
#AutoFlushLogs: True
#CheckArrayBounds: True
#StackBufferSize: 300
#End Region
'Ctrl+Click to open the C code folder: ide://run?File=%WINDIR%\System32\explorer.exe&Args=%PROJECT%\Objects\Src
Sub Process_Globals
Public Serial1 As Serial
Dim proxy As Pin 'A0 - input from the proxy (but A0 configured and used as a digital input)
Dim bank1 As Pin 'DO 0 - controls bank1 2000W (shortwave)
Dim bank2 As Pin 'DO 1 - controls bank2 2000W (shortwave)
Dim bank3 As Pin 'DO 2 - controls bank3 3000W (shortwave)
Dim bank4 As Pin 'DO 3 - controls bank4 3000W (shortwave)
Dim speed As ULong 'speed of machine in m/min
Dim maxspeed As ULong 'maximum speed of the machine = 300m/min
Dim minspeed As ULong 'minumum speed for switching on bank 1 of IR lights
Dim revcount, prevrevcount As ULong 'counters used to determine if machine is running or not - checked in evert timer_tick event
Dim proxytimer As Timer ' timer to determine if machine stopped or running
Dim interval As ULong ' interval that timer will be fired to establish if machine is running or not
Dim prevmillis, currentmillis As ULong ' prevmillis - store previous internal clock time when the State_Changed event was last fired
Dim timelapse As ULong ' currentmillis - time of internal clock when State_Changed is fired again relative to previous event
Dim rollercircumference As Double ' timelapse - time it took the target to rotate one full rotation past the proxy
' rollercircumference - the circumference of the steel chill roller (615mmm for the Uteco Onyx).
End Sub
Private Sub AppStart
Serial1.Initialize(115200) 'set up comms port for logging purposes
Log("AppStart") 'just log someting to see if connection has been established
interval = 1500 'timer will be fired every 1500 milliseconds (to establish if machine is running or not)
'this timer interval is based on the minimum speed of the printing machine + an observed margin
rollercircumference = 0.615 'the circumference of the steel chill roller in meters (i.e 615mm)
prevmillis = 0 'variables to store internal clock values that are used for calculation of speed
currentmillis = 0
maxspeed = 300 'mximum speed of the printing machine (m/min) - anything calculated as higher than this will be ignored
minspeed = 30 'minimum speed to start switching on 1st bank of IR lights
bank1.Initialize(4, bank1.MODE_OUTPUT) ' initialize pin 4 that will be used to switch solenoid of bank 1 contactor
bank2.Initialize(5, bank2.MODE_OUTPUT) ' initialize pin 5 that will be used to switch solenoid of bank 2 contactor
bank3.Initialize(6, bank3.MODE_OUTPUT) ' initialize pin 6 that will be used to switch solenoid of bank 3 contactor
bank4.Initialize(7, bank4.MODE_OUTPUT) ' initialize pin 7 that will be used to switch solenoid of bank 4 contactor
proxytimer.Initialize("proxy_tick", interval) 'initialize the timer to fire every variable "interval" milliseconds
proxytimer.Enabled = True 'Enable the timer - it will start the timer immediately
proxy.Initialize(14, proxy.MODE_INPUT) 'The proxy is connected to input A0 which is pin 14 on the Controllino Mini - but configured as a digital input
proxy.AddListener("proxymade_StateChanged") 'Add a listener to the proxy pin (A0) that will trigger the State_Changed event every time the 24vdc PNP proxy goes high
revcount = 0 'counter to count how many time proxy is turned high (or high/low)
prevrevcount = 0 'counter to check what was last count of proxy turned high/low - used for figuring out if machine is running or not
End Sub
Sub proxymade_StateChanged(State As Boolean)
Delay(20) 'A delay to take care of a possible proxy bounce when proxy goes from low to high or from high to low
Log("State = ", State) 'Will log State = 0 when proxy is going from high to low or State = 1 when proxy goes from low to high
If State = True Then 'proxy has been pulled high
revcount = revcount + 1 'increase the count every time the proxy is going high i.e the target passes the proxy
currentmillis = Millis 'get the time of the internal clock (time in milliseconds since device has been powered up or has been reset - stored in a type Ulong variable)
timelapse = currentmillis - prevmillis 'calculate the milliseconds between consecutive proxy highs
prevmillis = currentmillis 'store current millis in prevmillis
Log("timelapse = ", timelapse) 'log the milliseconds between consecutive proxy triggers
speed = rollercircumference/(timelapse/1000/60) 'calculate the speed of the machine in m/min using the time between consecutive proxy highs and the circumference of the steel chill roller where the drain plug is used as a target for the proxy
Log("speed (m/min) = ", speed) 'log the speed in the IDE to confirm with operator this a speed that he/she has set
Log(" ") 'log a CRLF in the IDE
If (speed > maxspeed Or speed < 0) Then 'switch banks of IR lights based on speed conditions in the code below
bank1.DigitalWrite(False) 'False - switch bank off, True - switch bank on
bank2.DigitalWrite(False) 'switching banks of IR lights on/off will depend on calculated speed of the machine using the proxy input
bank3.DigitalWrite(False)
bank4.DigitalWrite(False)
else If (speed >= 30 And speed < 60) Then 'switch on bank 1 IR lights
bank1.DigitalWrite(True)
bank2.DigitalWrite(False)
bank3.DigitalWrite(False)
bank4.DigitalWrite(False)
else if (speed >=60 And speed < 90) Then 'switch on banks 1 and 2 IR lights
bank1.DigitalWrite(True)
bank2.DigitalWrite(True)
bank3.DigitalWrite(False)
bank4.DigitalWrite(False)
else if (speed >= 90 And speed < 120) Then 'switch on banks 1, 2 and 3 IR lights
bank1.DigitalWrite(True)
bank2.DigitalWrite(True)
bank3.DigitalWrite(True)
bank4.DigitalWrite(False)
else if speed >= 120 Then 'switch on banks 1, 2, 3, and 4 IR lights
bank1.DigitalWrite(True)
bank2.DigitalWrite(True)
bank3.DigitalWrite(True)
bank4.DigitalWrite(True)
else if speed < minspeed Then '30m/min is the cut-off speed where all banks of IR lights will be switched off
bank1.DigitalWrite(False)
bank2.DigitalWrite(False)
bank3.DigitalWrite(False)
bank4.DigitalWrite(False)
End If
Log(" ") 'log a CRLF in the IDE
End If
End Sub
Sub proxy_tick 'this timer is used to ensure that a web burn is prevented as far as posible when the machine stops and IR light bank(s) was/were switched on.
Log("prevcount = ", prevrevcount) 'log the previous count stored in the IDE
Log("revcount = ", revcount) 'log the current count in the IDE
Log(" ")
If prevrevcount <> revcount Then 'machine is running when prevrevcount <> revcount
prevrevcount = revcount 'store the revcount in prevcount for comparing in the next timer_tick event
Else 'machine is not running prevrevcount = revcount
speed = 0 'set value of variable speed to 0
bank1.DigitalWrite(False) 'switch off all banks
bank2.DigitalWrite(False)
bank3.DigitalWrite(False)
bank4.DigitalWrite(False)
prevrevcount = 0 'reset counters to zero if established that machine has stopped/is not running (based on feedback from the proxy)
revcount = 0
speed = 0 'set variable speed to zero when machine is not running
End If
End Sub