def create_temperature_control(name, section, thread, hardwareOkSignal=None, coolingFan=None, hotendFan=None): tempSet = hal.newsig('%s-temp-set' % name, hal.HAL_FLOAT) tempMeas = hal.newsig('%s-temp-meas' % name, hal.HAL_FLOAT) tempInRange = hal.newsig('%s-temp-in-range' % name, hal.HAL_BIT) tempPwm = hal.newsig('%s-temp-pwm' % name, hal.HAL_FLOAT) tempPwmMax = hal.newsig('%s-temp-pwm-max' % name, hal.HAL_FLOAT) tempLimitMin = hal.newsig('%s-temp-limit-min' % name, hal.HAL_FLOAT) tempLimitMax = hal.newsig('%s-temp-limit-max' % name, hal.HAL_FLOAT) tempStandby = hal.newsig('%s-temp-standby' % name, hal.HAL_FLOAT) tempInLimit = hal.newsig('%s-temp-in-limit' % name, hal.HAL_BIT) tempThermOk = hal.newsig('%s-temp-therm-ok' % name, hal.HAL_BIT) error = hal.newsig('%s-error' % name, hal.HAL_BIT) active = hal.newsig('%s-active' % name, hal.HAL_BIT) tempPidPgain = hal.newsig('%s-temp-pid-Pgain' % name, hal.HAL_FLOAT) tempPidIgain = hal.newsig('%s-temp-pid-Igain' % name, hal.HAL_FLOAT) tempPidDgain = hal.newsig('%s-temp-pid-Dgain' % name, hal.HAL_FLOAT) tempPidMaxerrorI = hal.newsig('%s-temp-pid-maxerrorI' % name, hal.HAL_FLOAT) tempPidOut = hal.newsig('%s-temp-pid-out' % name, hal.HAL_FLOAT) tempPidBias = hal.newsig('%s-temp-pid-bias' % name, hal.HAL_FLOAT) tempRangeMin = hal.newsig('%s-temp-range-min' % name, hal.HAL_FLOAT) tempRangeMax = hal.newsig('%s-temp-range-max' % name, hal.HAL_FLOAT) noErrorIn = hal.newsig('%s-no-error-in' % name, hal.HAL_BIT) errorIn = hal.newsig('%s-error-in' % name, hal.HAL_BIT) tempPidBiasOut = tempPidBias # coolingFan compensation if coolingFan: tempPidFanBias = hal.newsig('%s-temp-pid-fan-bias' % name, hal.HAL_FLOAT) tempPidBiasOut = hal.newsig('%s-temp-pid-bias-out' % name, hal.HAL_FLOAT) scale = rt.newinst('scale', 'scale.%s-temp-pid-fan-bias' % name) hal.addf(scale.name, thread) scale.pin('in').link('%s.pwm' % coolingFan) scale.pin('out').link(tempPidFanBias) scale.pin('gain').set(c.find(section, 'FAN_BIAS')) sum2 = rt.newinst('sum2', 'sum2.%s-temp-pid-bias' % name) hal.addf(sum2.name, thread) sum2.pin('in0').link(tempPidBias) sum2.pin('in1').link(tempPidFanBias) sum2.pin('out').link(tempPidBiasOut) # PID pid = rt.newinst('pid', 'pid.%s' % name) hal.addf('%s.do-pid-calcs' % pid.name, thread) pid.pin('enable').link('emcmot-0-enable') # motor enable pid.pin('feedback').link(tempMeas) pid.pin('command').link(tempSet) pid.pin('output').link(tempPidOut) pid.pin('maxoutput').link(tempPwmMax) pid.pin('bias').link(tempPidBias) pid.pin('Pgain').link(tempPidPgain) pid.pin('Igain').link(tempPidIgain) pid.pin('Dgain').link(tempPidDgain) pid.pin('maxerrorI').link(tempPidMaxerrorI) # Limit heater PWM to positive values # PWM mimics hm2 implementation, which generates output for negative values limit1 = rt.newinst('limit1', 'limit.%s-temp-heaterl' % name) hal.addf(limit1.name, thread) limit1.pin('in').link(tempPidOut) limit1.pin('out').link(tempPwm) limit1.pin('min').set(0.0) limit1.pin('max').link(tempPwmMax) # Temperature checking sum2 = rt.newinst('sum2', 'sum2.%s-temp-range-pos' % name) hal.addf(sum2.name, thread) sum2.pin('in0').link(tempSet) sum2.pin('in1').set(c.find(section, 'TEMP_RANGE_POS_ERROR')) sum2.pin('out').link(tempRangeMax) sum2 = rt.newinst('sum2', 'sum2.%s-temp-range-neg' % name) hal.addf(sum2.name, thread) sum2.pin('in0').link(tempSet) sum2.pin('in1').set(c.find(section, 'TEMP_RANGE_NEG_ERROR')) sum2.pin('out').link(tempRangeMin) #the output of this component will say if measured temperature is in range of set value wcomp = rt.newinst('wcomp', 'wcomp.%s-temp-in-range' % name) hal.addf(wcomp.name, thread) wcomp.pin('min').link(tempRangeMin) wcomp.pin('max').link(tempRangeMax) wcomp.pin('in').link(tempMeas) wcomp.pin('out').link(tempInRange) # limit the output temperature to prevent damage when thermistor is broken/removed wcomp = rt.newinst('wcomp', 'wcomp.%s-temp-in-limit' % name) hal.addf(wcomp.name, thread) wcomp.pin('min').link(tempLimitMin) wcomp.pin('max').link(tempLimitMax) wcomp.pin('in').link(tempMeas) wcomp.pin('out').link(tempInLimit) # check the thermistor # net e0.temp.meas => thermistor-check.e0.temp # net e0.temp.in-range => not.e0-temp-range.in # net e0.temp.in-range_n <= not.e0-temp-range.out # net e0.temp.in-range_n => thermistor-check.e0.enable # net e0.heaterl => thermistor-check.e0.pid # net e0.therm-ok <= thermistor-check.e0.no-error # no error chain and3 = rt.newinst('andn', 'and3.%s-no-error-in' % name, pincount=3) hal.addf(and3.name, thread) and3.pin('in0').link(tempThermOk) and3.pin('in1').link(tempInLimit) if hardwareOkSignal: and3.pin('in2').link(hardwareOkSignal) else: and3.pin('in2').set(True) and3.pin('out').link(noErrorIn) tempThermOk.set(True) # thermistor checking for now disabled notComp = rt.newinst('not', 'not.%s-error-in' % name) hal.addf(notComp.name, thread) notComp.pin('in').link(noErrorIn) notComp.pin('out').link(errorIn) safetyLatch = rt.newinst('safety_latch', 'safety-latch.%s-error' % name) hal.addf(safetyLatch.name, thread) safetyLatch.pin('error-in').link(errorIn) safetyLatch.pin('error-out').link(error) safetyLatch.pin('reset').link('estop-reset') safetyLatch.pin('threshold').set(500) # 500ms error safetyLatch.pin('latching').set(True) # active chain comp = rt.newinst('comp', 'comp.%s-active' % name) hal.addf(comp.name, thread) comp.pin('in0').set(0.0001) comp.pin('hyst').set(0.0) comp.pin('in1').link(tempPwm) comp.pin('out').link(active) # Thermistor checking # setp thermistor-check.e0.wait 9.0 # setp thermistor-check.e0.min-pid 1.5 # disable0.25 # setp thermistor-check.e0.min-temp 1.5 # net e0.pid.bias => thermistor-check.e0.bias # Hotend fan if hotendFan: comp = rt.newinst('comp', 'comp.%s-pwm-enable' % hotendFan) hal.addf(comp.name, thread) comp.pin('in0').set(c.find(section, 'HOTEND_FAN_THRESHOLD', 50.0)) comp.pin('in1').link(tempMeas) comp.pin('hyst').set(c.find(section, 'HOTEND_FAN_HYST', 2.0)) comp.pin('out').link('%s-pwm-enable' % hotendFan) hal.Signal('%s-pwm' % hotendFan).set(1.0) rcomps.create_temperature_rcomp(name) motion.setup_temperature_io(name) # init parameter signals tempLimitMin.set(c.find(section, 'TEMP_LIMIT_MIN')) tempLimitMax.set(c.find(section, 'TEMP_LIMIT_MAX')) tempStandby.set(c.find(section, 'TEMP_STANDBY')) tempPwmMax.set(c.find(section, 'PWM_MAX')) tempPidPgain.set(c.find(section, 'PID_PGAIN')) tempPidIgain.set(c.find(section, 'PID_IGAIN')) tempPidDgain.set(c.find(section, 'PID_DGAIN')) tempPidMaxerrorI.set(c.find(section, 'PID_MAXERRORI')) tempPidBias.set(c.find(section, 'PID_BIAS'))
def create_temperature_control(name, section, thread, hardwareOkSignal=None, coolingFan=None, hotendFan=None): tempSet = hal.newsig('%s-temp-set' % name, hal.HAL_FLOAT) tempMeas = hal.newsig('%s-temp-meas' % name, hal.HAL_FLOAT) tempInRange = hal.newsig('%s-temp-in-range' % name, hal.HAL_BIT) tempPwm = hal.newsig('%s-temp-pwm' % name, hal.HAL_FLOAT) tempPwmMax = hal.newsig('%s-temp-pwm-max' % name, hal.HAL_FLOAT) tempLimitMin = hal.newsig('%s-temp-limit-min' % name, hal.HAL_FLOAT) tempLimitMax = hal.newsig('%s-temp-limit-max' % name, hal.HAL_FLOAT) tempStandby = hal.newsig('%s-temp-standby' % name, hal.HAL_FLOAT) tempInLimit = hal.newsig('%s-temp-in-limit' % name, hal.HAL_BIT) tempThermOk = hal.newsig('%s-temp-therm-ok' % name, hal.HAL_BIT) error = hal.newsig('%s-error' % name, hal.HAL_BIT) active = hal.newsig('%s-active' % name, hal.HAL_BIT) tempPidPgain = hal.newsig('%s-temp-pid-Pgain' % name, hal.HAL_FLOAT) tempPidIgain = hal.newsig('%s-temp-pid-Igain' % name, hal.HAL_FLOAT) tempPidDgain = hal.newsig('%s-temp-pid-Dgain' % name, hal.HAL_FLOAT) tempPidMaxerrorI = hal.newsig('%s-temp-pid-maxerrorI' % name, hal.HAL_FLOAT) tempPidOut = hal.newsig('%s-temp-pid-out' % name, hal.HAL_FLOAT) tempPidBias = hal.newsig('%s-temp-pid-bias' % name, hal.HAL_FLOAT) tempRangeMin = hal.newsig('%s-temp-range-min' % name, hal.HAL_FLOAT) tempRangeMax = hal.newsig('%s-temp-range-max' % name, hal.HAL_FLOAT) noErrorIn = hal.newsig('%s-no-error-in' % name, hal.HAL_BIT) errorIn = hal.newsig('%s-error-in' % name, hal.HAL_BIT) # reset set temperature when estop is cleared reset = rt.newinst('reset', 'reset.%s-temp-set' % name) hal.addf(reset.name, thread) reset.pin('reset-float').set(0.0) reset.pin('out-float').link(tempSet) reset.pin('rising').set(True) reset.pin('falling').set(False) reset.pin('trigger').link('estop-reset') tempPidBiasOut = tempPidBias # coolingFan compensation if coolingFan: tempPidFanBias = hal.newsig('%s-temp-pid-fan-bias' % name, hal.HAL_FLOAT) tempPidBiasOut = hal.newsig('%s-temp-pid-bias-out' % name, hal.HAL_FLOAT) scale = rt.newinst('scale', 'scale.%s-temp-pid-fan-bias' % name) hal.addf(scale.name, thread) scale.pin('in').link('%s.pwm' % coolingFan) scale.pin('out').link(tempPidFanBias) scale.pin('gain').set(c.find(section, 'FAN_BIAS')) sum2 = rt.newinst('sum2', 'sum2.%s-temp-pid-bias' % name) hal.addf(sum2.name, thread) sum2.pin('in0').link(tempPidBias) sum2.pin('in1').link(tempPidFanBias) sum2.pin('out').link(tempPidBiasOut) # PID pid = rt.newinst('pid', 'pid.%s' % name) hal.addf('%s.do-pid-calcs' % pid.name, thread) pid.pin('enable').link('emcmot-0-enable') # motor enable pid.pin('feedback').link(tempMeas) pid.pin('command').link(tempSet) pid.pin('output').link(tempPidOut) pid.pin('maxoutput').link(tempPwmMax) pid.pin('bias').link(tempPidBias) pid.pin('Pgain').link(tempPidPgain) pid.pin('Igain').link(tempPidIgain) pid.pin('Dgain').link(tempPidDgain) pid.pin('maxerrorI').link(tempPidMaxerrorI) # Limit heater PWM to positive values # PWM mimics hm2 implementation, which generates output for negative values limit1 = rt.newinst('limit1', 'limit.%s-temp-heaterl' % name) hal.addf(limit1.name, thread) limit1.pin('in').link(tempPidOut) limit1.pin('out').link(tempPwm) limit1.pin('min').set(0.0) limit1.pin('max').link(tempPwmMax) # Temperature checking sum2 = rt.newinst('sum2', 'sum2.%s-temp-range-pos' % name) hal.addf(sum2.name, thread) sum2.pin('in0').link(tempSet) sum2.pin('in1').set(c.find(section, 'TEMP_RANGE_POS_ERROR')) sum2.pin('out').link(tempRangeMax) sum2 = rt.newinst('sum2', 'sum2.%s-temp-range-neg' % name) hal.addf(sum2.name, thread) sum2.pin('in0').link(tempSet) sum2.pin('in1').set(c.find(section, 'TEMP_RANGE_NEG_ERROR')) sum2.pin('out').link(tempRangeMin) #the output of this component will say if measured temperature is in range of set value wcomp = rt.newinst('wcomp', 'wcomp.%s-temp-in-range' % name) hal.addf(wcomp.name, thread) wcomp.pin('min').link(tempRangeMin) wcomp.pin('max').link(tempRangeMax) wcomp.pin('in').link(tempMeas) wcomp.pin('out').link(tempInRange) # limit the output temperature to prevent damage when thermistor is broken/removed wcomp = rt.newinst('wcomp', 'wcomp.%s-temp-in-limit' % name) hal.addf(wcomp.name, thread) wcomp.pin('min').link(tempLimitMin) wcomp.pin('max').link(tempLimitMax) wcomp.pin('in').link(tempMeas) wcomp.pin('out').link(tempInLimit) # check the thermistor # net e0.temp.meas => thermistor-check.e0.temp # net e0.temp.in-range => not.e0-temp-range.in # net e0.temp.in-range_n <= not.e0-temp-range.out # net e0.temp.in-range_n => thermistor-check.e0.enable # net e0.heaterl => thermistor-check.e0.pid # net e0.therm-ok <= thermistor-check.e0.no-error # no error chain and3 = rt.newinst('andn', 'and3.%s-no-error-in' % name, pincount=3) hal.addf(and3.name, thread) and3.pin('in0').link(tempThermOk) and3.pin('in1').link(tempInLimit) if hardwareOkSignal: and3.pin('in2').link(hardwareOkSignal) else: and3.pin('in2').set(True) and3.pin('out').link(noErrorIn) tempThermOk.set(True) # thermistor checking for now disabled notComp = rt.newinst('not', 'not.%s-error-in' % name) hal.addf(notComp.name, thread) notComp.pin('in').link(noErrorIn) notComp.pin('out').link(errorIn) safetyLatch = rt.newinst('safety_latch', 'safety-latch.%s-error' % name) hal.addf(safetyLatch.name, thread) safetyLatch.pin('error-in').link(errorIn) safetyLatch.pin('error-out').link(error) safetyLatch.pin('reset').link('estop-reset') safetyLatch.pin('threshold').set(500) # 500ms error safetyLatch.pin('latching').set(True) # active chain comp = rt.newinst('comp', 'comp.%s-active' % name) hal.addf(comp.name, thread) comp.pin('in0').set(0.0001) comp.pin('hyst').set(0.0) comp.pin('in1').link(tempPwm) comp.pin('out').link(active) # Thermistor checking # setp thermistor-check.e0.wait 9.0 # setp thermistor-check.e0.min-pid 1.5 # disable0.25 # setp thermistor-check.e0.min-temp 1.5 # net e0.pid.bias => thermistor-check.e0.bias # Hotend fan if hotendFan: comp = rt.newinst('comp', 'comp.%s-pwm-enable' % hotendFan) hal.addf(comp.name, thread) comp.pin('in0').set(c.find(section, 'HOTEND_FAN_THRESHOLD', 50.0)) comp.pin('in1').link(tempMeas) comp.pin('hyst').set(c.find(section, 'HOTEND_FAN_HYST', 2.0)) comp.pin('out').link('%s-pwm-enable' % hotendFan) hal.Signal('%s-pwm' % hotendFan).set(1.0) rcomps.create_temperature_rcomp(name) motion.setup_temperature_io(name) # init parameter signals tempLimitMin.set(c.find(section, 'TEMP_LIMIT_MIN')) tempLimitMax.set(c.find(section, 'TEMP_LIMIT_MAX')) tempStandby.set(c.find(section, 'TEMP_STANDBY')) tempPwmMax.set(c.find(section, 'PWM_MAX')) tempPidPgain.set(c.find(section, 'PID_PGAIN')) tempPidIgain.set(c.find(section, 'PID_IGAIN')) tempPidDgain.set(c.find(section, 'PID_DGAIN')) tempPidMaxerrorI.set(c.find(section, 'PID_MAXERRORI')) tempPidBias.set(c.find(section, 'PID_BIAS'))
def create_temperature_control(name, section, thread, hardwareOkSignal=None, coolingFan=None, hotendFan=None, tclab_index=0): tempSet = hal.newsig('%s-temp-set' % name, hal.HAL_FLOAT) tempMeas = hal.newsig('%s-temp-meas' % name, hal.HAL_FLOAT) tempInRange = hal.newsig('%s-temp-in-range' % name, hal.HAL_BIT) tempInRangePre = hal.newsig('%s-temp-in-range-pre-check' % name, hal.HAL_BIT) active = hal.newsig('%s-active' % name, hal.HAL_BIT) tempLimitMin = hal.newsig('%s-temp-limit-min' % name, hal.HAL_FLOAT) tempLimitMax = hal.newsig('%s-temp-limit-max' % name, hal.HAL_FLOAT) hal.Pin("hal_tclab.temperature-%s" % str(tclab_index)).link(tempMeas) hal.Pin("hal_tclab.setpoint-%s" % str(tclab_index)).link(tempSet) hal.Pin("hal_tclab.enable-%s" % str(tclab_index)).link(active) active.set(1) tempInLimit = hal.newsig('%s-temp-in-limit' % name, hal.HAL_BIT) tempThermOk = hal.newsig('%s-temp-therm-ok' % name, hal.HAL_BIT) error = hal.newsig('%s-error' % name, hal.HAL_BIT) tempPidPgain = hal.newsig('%s-temp-pid-Pgain' % name, hal.HAL_FLOAT) tempPidIgain = hal.newsig('%s-temp-pid-Igain' % name, hal.HAL_FLOAT) tempPidDgain = hal.newsig('%s-temp-pid-Dgain' % name, hal.HAL_FLOAT) tempPidMaxerrorI = hal.newsig('%s-temp-pid-maxerrorI' % name, hal.HAL_FLOAT) tempPidOut = hal.newsig('%s-temp-pid-out' % name, hal.HAL_FLOAT) tempPidBias = hal.newsig('%s-temp-pid-bias' % name, hal.HAL_FLOAT) tempRangeMin = hal.newsig('%s-temp-range-min' % name, hal.HAL_FLOAT) tempRangeMax = hal.newsig('%s-temp-range-max' % name, hal.HAL_FLOAT) noErrorIn = hal.newsig('%s-no-error-in' % name, hal.HAL_BIT) errorIn = hal.newsig('%s-error-in' % name, hal.HAL_BIT) sum2 = rt.newinst('sum2', 'sum2.%s-temp-range-pos' % name) hal.addf(sum2.name, thread) sum2.pin('in0').link(tempSet) sum2.pin('in1').set(c.find(section, 'TEMP_RANGE_POS_ERROR')) sum2.pin('out').link(tempRangeMax) sum2 = rt.newinst('sum2', 'sum2.%s-temp-range-neg' % name) hal.addf(sum2.name, thread) sum2.pin('in0').link(tempSet) sum2.pin('in1').set(c.find(section, 'TEMP_RANGE_NEG_ERROR')) sum2.pin('out').link(tempRangeMin) #the output of this component will say if measured temperature is in range of set value wcomp = rt.newinst('wcomp', 'wcomp.%s-temp-in-range' % name) hal.addf(wcomp.name, thread) wcomp.pin('min').link(tempRangeMin) wcomp.pin('max').link(tempRangeMax) wcomp.pin('in').link(tempMeas) wcomp.pin('out').link(tempInRangePre) notActive = hal.newsig('%s-not-active' % name, hal.HAL_BIT) activeNot = rt.newinst('not', 'not.%s.active-not' % name) hal.addf(activeNot.name, thread) activeNot.pin('in').link(active) activeNot.pin('out').link(notActive) or2 = rt.newinst('orn', 'or2.%s-check-temp-in-range' % name, pincount='2') hal.addf(or2.name, thread) or2.pin('in1').link(tempInRangePre) or2.pin('in0').link(notActive) or2.pin('out').link(tempInRange) # limit the output temperature to prevent damage when thermistor is broken/removed wcomp = rt.newinst('wcomp', 'wcomp.%s-temp-in-limit' % name) hal.addf(wcomp.name, thread) wcomp.pin('min').link(tempLimitMin) wcomp.pin('max').link(tempLimitMax) wcomp.pin('in').link(tempMeas) wcomp.pin('out').link(tempInLimit) rcomps.create_temperature_rcomp(name) motion.setup_temperature_io(name) tempLimitMax.set(c.find(section, "TEMP_LIMIT_MAX")) print("max set to", c.find(section, "TEMP_LIMIT_MAX")) tempLimitMin.set(c.find(section, "TEMP_LIMIT_MIN"))