Linuxcnc Hal Component to implement ATC for a EMCO Turn120 / Compact6 CNC lathe This is a direct interface, where Linuxcnc reads the opto sensor board and controls the toolturret motor, 6pins on the parallelport are used (4opto sensors, motor direction, motor enable) Once the correct tool position has been reached, the motor is reversed and pulse width modulated to hold around 0.8 Amp. Thanks to ArcEye 01122011 schooner30@tiscali.co.uk and cncbasher who wrote the origional component for a Denford Orac Lathe http://wiki.linuxcnc.org/cgi-bin/wiki.pl?ContributedComponents#Denford_Orac_Lathe_ATC_toolchanger_component I only modified their work to suit the emco lathe. Instructions: in the terminal run: sudo apt-get install emc2-dev sudo apt-get install build-essential Extract the emcochanger component from this text file and place it in a file named emcochanger.comp , copy this to you config file. cd/linuxcnc/configs/ "your lathe name" / install the component with: sudo comp --install emcochanger.comp Extract the hal component and add it to your .hal file. Hardware Notes: The EMCO opto sensor board runs on 24VDC, I used a voltage divider with R1=10k & R2=2.2k to drop the voltage before connecting to the parallel port. Pinout: brown -> 24V green -> GND blue -> opto 1 pink -> 2 yellow -> 3 gray -> 4 on the motor output side I used an H-Bridge IC, and a 2222 transistor to switch form motor direction to In1 & In2 of the H-bridge. *******************************hal component****************************************** #load pwmgen for run pwm loadrt pwmgen output_type=0 addf pwmgen.update servo-thread addf pwmgen.make-pulses base-thread setp pwmgen.0.pwm-freq 500.0 setp pwmgen.0.scale 100.0 setp pwmgen.0.offset 0.0 loadrt emcochanger addf emcochanger servo-thread loadrt timedelay count=1 addf timedelay.0 servo-thread # will wait 5 secs approx and turn motor off after reversing against stop setp timedelay.0.on-delay 2 net tool-change iocontrol.0.tool-change => emcochanger.toolchange net tool-changed iocontrol.0.tool-changed <= emcochanger.toolchanged net tool-number iocontrol.0.tool-prep-number => emcochanger.toolnumber net tool-oldnumber iocontrol.0.tool-number => emcochanger.currenttoolnumber net tool-prepare-loopback iocontrol.0.tool-prepare => iocontrol.0.tool-prepared net sig1 emcochanger.opto1 <= parport.0.pin-10-in net sig2 emcochanger.opto2 <= parport.0.pin-11-in net sig3 emcochanger.opto3 <= parport.0.pin-12-in net sig4 emcochanger.opto4 <= parport.0.pin-13-in net sig-forward emcochanger.forward => parport.0.pin-16-out net Xen => pwmgen.0.enable net pwmgen_value pwmgen.0.value <= emcochanger.setpwm net pwmgen_out pwmgen.0.pwm => parport.0.pin-17-out net xhomed axis.0.homed => emcochanger.ishomedX net zhomed axis.2.homed => emcochanger.ishomedZ net delaystart timedelay.0.in <= emcochanger.delaystart net delaydone timedelay.0.out => emcochanger.delaydone ********************************* emcochanger component*********************************** component emcochanger "This component controls the EMCO Lathe Auto Tool Changer. M6 calls this"; pin in bit toolchange "Receives signal from M6 that tool change required"; pin in s32 toolnumber "Receives Tx data from M6 (tool number requested) Only allows 1-8"; pin in s32 currenttoolnumber "Receives old tool number"; pin out bit toolchanged = false "Sends signal when tool change finished"; pin in bit Xen = false; pin out bit delaystart = false "Starts timerdelay"; pin in bit delaydone =false "Signals timer finished"; pin in bit opto1 = false "State of opto sensor 1"; pin in bit opto2 = false "State of opto sensor 2"; pin in bit opto3 = false "State of opto sensor 3"; pin in bit opto4 = false "State of opto sensor 4"; pin out bit forward = false "Direction signal"; pin out float setpwm = 100 "Motor PWM"; pin in bit ishomedX = false "Status of X axis homing"; pin in bit ishomedZ = false "Status of Z axis homing"; pin out s32 position = 0 "Initialised as a pin for debugging so we can check where it thinks it is"; param rw float times = 500 "Number of polls of progress_levels 1 & 3 before beginning next move - gives delay for relays"; // Internal and debugging stuff pin out s32 progress_level = 0; // tracks the progress of the toolchange, just here so it can be read easily param rw s32 tnumber = 0; // Internal toolnumber to allow overrun of quadrant by 1 then reverse back onto it variable float sleeptime = 0; // our own timer to set delay between progress levels 1 and 2 option singleton yes; // makes no sense to have more than one of these components running - only one ATC function _; author "ArcEye schooner30@tiscali.co.uk"; license "GPL"; ;; FUNCTION(_) { switch (progress_level) { case 0: // idle waiting for toolchange request axis does not remember the current tool number, so prompt for it once homed if(toolchange && !toolchanged) // prevent cycling after change done { if( (toolnumber != currenttoolnumber) && (toolnumber > 0) && (toolnumber < 9) ) // if a valid number { tnumber = toolnumber; delaystart = false; //new toolchange - reset comp forward = true; sleeptime = 0; progress_level = 1; setpwm = 100; //reset the pwm to 100 for forward running break; } else { // if tool requested is out of range set the toolchanged flag and exit should only get this if tool table has more tools than ATC can have otherwise emc will error the M6 command progress_level = 5; } } if(!toolchange && toolchanged) toolchanged = false; // reset once toolchange flag reset by system if(delaydone) // after motor has locked reduce the pwm { setpwm = 40; delaystart = false; } break; case 1: // programmed delay to allow relays time to change over if(sleeptime < times) { sleeptime++; break; } progress_level = 2; break; case 2: // Forward move - read the truth table to determine position if(opto1 && !opto2 && opto3 && opto4) position = 1; else if(!opto1 && !opto2 && opto3 && opto4) position = 2; else if(!opto1 && opto2 && opto3 && opto4) position = 3; else if(!opto1 && opto2 && opto3 && !opto4) position = 4; else if(opto1 && opto2 && opto3 && !opto4) position = 5; else if(opto1 && opto2 && !opto3 && !opto4) position = 6; else if(opto1 && opto2 && !opto3 && opto4) position = 7; else if(opto1 && !opto2 && !opto3 && opto4) position = 8; else position = 0; if(!position) // if returning 0 something is wrong { rtapi_print_msg(RTAPI_MSG_ERR, "Error - opto inputs do not match truth table"); progress_level = 12; // doesn't exist so will go to default, output msg and then sit in level 10 break; } if(position != tnumber) // wait for next tool + 1 to come around break; forward = false; sleeptime = 0; delaystart = true; progress_level = 3; break; case 3: // programmed delay to allow relays time to change over if(sleeptime < times) { sleeptime++; break; } delaystart = true; progress_level = 5; // after first toolchange or update of tool number this is default, reverse with 12v applied to lock break; case 5: // clean up ready for next toolchange delaystart = true; // start the 5 second delay relay component to give time to latch progress_level = 0; toolchanged = true; // signal finished break; default: progress_level = 10; rtapi_print_msg(RTAPI_MSG_ERR, "Error state in emcochanger - now disabled - unload emcochanger"); break; } }