Special actions after machine is stopped by the user

More
01 Mar 2019 09:25 #127392 by LostInTheHal
Hello everyone,

I come to you to have your insights on a functionality I don't really know how to implement in a clever and hopefully simple way.

I use LinuxCNC to drive an additive manufacturing machine with a non standard kinematic.
The materials I use are typically reactive polymers. So instead of having a cutting tool, I have a mixer which blends the polymers components and pump them to the extrusion head. Everything seems to work almost correctly on the CNC part but not always in the material blending part. The trouble is once the components are blended together, the polymerization is launched and one need to purge the system quickly (few tens of seconds) if anything goes wrong unless all the material handling system can go to trash!

As I can monitor part of the material preparation quality, I was thinking of incorporating a kind of "Process E-Stop" which would require, upon a signal sent by the processing unit:
1 - Halt the execution of the Gcode, ideally remembering the current line number (I understood it was not so simple in LinuxCNC)
2 - Move the tool to a "purging area"
3 - Activate a purge cycle for a given time or until the processing unit asks for it.

I suppose there are various ways to do so, but as I am quite new to linuxcnc, I am sure you will have great advice!

I thank you in advance,

Have a good day,

B

Please Log in or Create an account to join the conversation.

More
01 Mar 2019 15:38 #127430 by mozmck
See if the ON_ABORT_COMMAND in the ini will do what you need:
linuxcnc.org/docs/devel/html/remap/remap...g_dealing_with_abort
The following user(s) said Thank You: LostInTheHal, engineer

Please Log in or Create an account to join the conversation.

More
01 Mar 2019 17:13 #127442 by Leon82
It sounds like you want an inspection point type mevent

Retract
Purge
Resume

In a cam system it can be done. Can you do it in your software and activate it with an mcode?
The following user(s) said Thank You: LostInTheHal

Please Log in or Create an account to join the conversation.

More
01 Mar 2019 17:23 #127443 by tommylight
Something like a tool change could be implemented.

Please Log in or Create an account to join the conversation.

More
01 Mar 2019 17:42 #127445 by LostInTheHal
Thank you for this Idea,

I gave it a quick try and it seems that the motion module does not like to have motion commands in the ON_ABORT_COMMAND macro. When just loading the config file, I have the following error : "need to be enabled, in coord mode for linear move". It is thrown infinitely and I can even not zero my machine.

If I understand correctly, this would have permitted to purge the system but in case of full stop only.
Unless you find it totally irrelevant, I will give a try to a custom hal component saving the current program line number, stopping the program and sending move commands to go to the "purge point"...

I'll keep informed in case of success!

Have a good day,

B

Please Log in or Create an account to join the conversation.

More
01 Mar 2019 17:49 #127446 by LostInTheHal
Thank you for this Idea, but I am not sure to understand how it would work.
I may be totally wrong but I think user can not send a M code (through the interface for example) while a gcode file is executed. Is that correct?
If not it is a very interesting approach, indeed.

Thank you,

B

Please Log in or Create an account to join the conversation.

More
01 Mar 2019 18:25 #127450 by Leon82
I'm not sure what software you use but for example in mastercam after a certain distance or time you can retract a tool for an inspection point.

So say print for 40 minutes retract activate the purge m code resume. The operator would not have to push any buttons

Please Log in or Create an account to join the conversation.

More
01 Mar 2019 19:45 #127455 by Mike_Eitel
I think if you use a real button, connect it to hal, write a comp that saves your program line, saved all momentary g code settings, switches all your axes away from actual motion... Stop execution of gcode, restart with a special, absolute values based g code... You can do it. Puh, I'd guess a bunch of code.
m5c

Please Log in or Create an account to join the conversation.

More
03 Mar 2019 08:09 #127577 by LostInTheHal
Thank You Mike,

I gave a try with a python script and all the functionalities seems to be easily accessible.
The only and big trouble I have, is that I use a custom Mcode to launch the script (I did not find any other way) so I found no way to have it running when in Auto mode. I can only launch it in manual or mdi mode, consequently loosing all info concerning the interpreter position in the Gcode file before leaving auto mode.

Is there a way to launch a python script when in auto mode from a hal pin or through pyVCP or others?

The only trick I found (but I don't really like it and did not tested it yet) is to have a script running permanently in background listening for a given hal pin to be triggered. If this pin is triggered, it saves relevant info, switches to MDI, move the tool and starts purging...

An other similar way would be to have a custom Mcode call repeatedly in my Gcode file (lets say every X moves) which execution would be conditioned by the state of a trigger hal pin. But I find it a quite messy approach!

Thanks for suggestions,

Have a good day,

B

Please Log in or Create an account to join the conversation.

More
03 Mar 2019 13:56 #127602 by LostInTheHal
Thank you all,

I finished to code a python user space hal components which almost does what I want. It has a single boolean in pin "gotopurge.purge" which triggers the treatment.
All works fine except loading the updated gcode file through python linuxcnc.command.program_open(finename). It does not throw any exception but no file seems to be loading in Axis. I understand (maybe wrongly) that it is not a function dedicated to load a gcode file in Axis but just in linuxCNC.

For those who may find it useful a day or another, here is the python code for this component (note that the final Gcode file loading seems not effective; the rest of the code is quite naive but should be a good base to start from):
#!/usr/bin/python
# ----------------------------------------------------------------------
#  HAL USERSPACE COMPONENT GO_TO_PURGE
#
#
# ----------------------------------------------------------------------

"""
requires: sys, linuxcnc, hal, time, os

If the input pin "gotopurge" is trigerred :

The script shall:
	- stop Gcode execution
	- save the current:
			- program line number : 
				* motion.program-line
			- head position
			- motion status:
				* motion.in-position
				* motion.distance-to-go
			- ...
	- switch to MDI mode
	- move the head to the purge point
	- activate purging signal pin (custom M112 command)
	- copy the Gcode File
	- clean it to the point we are
	- load it in EMC waiting operator to relaunch it

"""


import sys
import linuxcnc
import hal
import time
import os

dumpfilename = "DUMPFILE.txt"
go2purgeSequence = ["G0 Z4000.0 F10000", "G0 X2000.0 Y2000.0", "G0 Z200.0", "M112"]

#                 HAL US COMPONENT INSTANCIATION
myComponent = hal.component("gotopurge")
myComponent.newpin("purge", hal.HAL_BIT, hal.HAL_IN)



#                 STATUS CHANNEL INSTANCIATION
try:
	status = linuxcnc.stat() # create a connection to the status channel
	status.poll() # get current values
except linuxcnc.error, detail:
	print "\nBDE ERROR : in stop_to_purge.py status: ", detail
	sys.exit(1)

#                 COMMAND CHANNEL INSTANCIATION
try:
	command = linuxcnc.command() # create a connection to the command channel

except linuxcnc.error, detail:
	print "\nBDE ERROR : in stop_to_purge.py command: ", detail
	sys.exit(1)


myComponent.ready()






# ######################################################################
#                     UTILITY FUNCTIONS
# ######################################################################

# ----------------------------------------------------------------------
#  Switching to mdi mode, going to purge_point
# ----------------------------------------------------------------------
def go_to_purge(go2purgeSequence):
	if isReady_for_mdi:
		command.mode(linuxcnc.MODE_MDI) # going to MDI mode
		command.wait_complete()         # waits until mode has changed
		time.sleep(0.1)
		print " Going to MDI mode"
		for cmd in go2purgeSequence :
			command.mdi(cmd)   			# sending Gcode to move to purge
			command.wait_complete() 
		print "\nBDE INFO : stop_to_purge.py : Purging Started ...\nPlease stop it when OK...\n"
	else:
		print "\nBDE WARNING : stop_to_purge.py : Machine not ready to go in MDI mode - aborting\n"

   
# ----------------------------------------------------------------------
#  Recovering usefull status information
# ----------------------------------------------------------------------
def grab_status():
	statdict = {}
	status.poll()

	statdict["current_pos"] = status.actual_position
	statdict["traj_position"] = status.position

	statdict["disp_dtg"] = status.distance_to_go
	statdict["xyz_dtg"] = status.dtg

	statdict["actual_jpos"] = status.joint_actual_position
	statdict["desired_jpos"] = status.joint_position

	statdict["current_file"] = status.file
	statdict["current_line"] = status.current_line
	statdict["motion_line"] = status.motion_line
	statdict["read_line"] = status.read_line

	print "\n\nBDE stop_to_purge.py : STATUS IS :"
	for key in statdict:
		print "	", key, " --> ", statdict[key]

	# Dump status to a file :
	f = open(dumpfilename, "a")
	f.write("\n###################################################\n")
	for key in statdict:
		f.write( str(key)+ " = " + str(statdict[key]) +"\n")

	f.write("\n")
	f.close()

	return statdict

# ----------------------------------------------------------------------
#  Is machine state OK to send MDI Commands ?
# ----------------------------------------------------------------------
def isReady_for_mdi():
	status.poll()
	estopOK = not status.estop
	enableOK = status.enabled
	homedOK = status.homed
	idleOK = (status.interp_state == linuxcnc.INTERP_IDLE)
	isReady = estopOK and enableOK and homedOK and idleOK
	return isReady

# ----------------------------------------------------------------------
#  Update a copy of Gcode file to be able to restart
# ----------------------------------------------------------------------
def update_Gcode_file(statdict):
	removeItems = ["g0", "g0 ","g00", "g00 ", "g1", "g1 ", "g01", "g01 "]

	filepath = statdict["current_file"]
	path, filename = os.path.split(filepath)
	basename, ext = filename.split(".")
	if "_STOP_" in basename:
		basenameroot, laststop_number = basename.split("_STOP_")
	else:
		basenameroot = basename
		laststop_number = "0"

	newstop_number = int(laststop_number) + 1
	newfileName = basename + "_STOP_" + str(newstop_number)+"."+ ext
	newfilePath = path + "/" + newfileName
	print "\nNew File Path is : " , newfilePath

	original_file = open(filepath , "r").readlines()
	new_file = open(newfilePath , "w")
	# It seems that "motion line" is the only relevant for restarting
	ml = statdict["motion_line"]
	print "\n motion stopped at line = ", ml 

	# Write relevant Gcode lines from the old file to the new one
        # Note : this only removes all moves before the stop; it should be modified for robustness to cope with modal command which
        # should not be ignored
	new_file.write("; File created for restart from unattended stop : "+ newfilePath)
	for iline, line in enumerate(original_file):
		if iline < ml: # If the line is in the already fabricated part
			# If we do not have any G1 , G01 , G0 , G00 
			OK = True
			#print iline, " --> " , line
			for cmd in ["G0 " , "G00 " , "G1 ", "G01 ", "g0 " , "g00 " , "g1 ", "g01 "]:
				if cmd in line:
					#print "cmd found in :" , cmd
					OK = OK & False
			if OK:
				new_file.write(line)
		else:
			new_file.write(line)
	new_file.close()
	print "\nBDE INFO: gotopurge : new Gcode file saved in :\n", "		-->", newfilePath

	# Resets the current file and load the new one
	command.wait_complete()
	command.reset_interpreter()
	command.wait_complete()
	command.program_open(newfilePath)
	command.wait_complete()
	print "\nBDE INFO: new Gcode file \n(", newfilePath , ")\nloaded..."

# ######################################################################
#                     MAIN LOOP 
#      (should be at the end for the interpreter to read all...)
# ######################################################################
def doActions():
	print "\n\nBDE stop_to_purge.py aborting motion..."
	# Stop motion
	command.abort()
	# Get current status
	statdict = grab_status()
	# Go to PP and start purging
	go_to_purge(go2purgeSequence)
	# Modify Gcode file and loads it
	update_Gcode_file(statdict)

lastState = False
try:
	while 1:
		time.sleep(0.1)
		if (myComponent["purge"] == True and lastState == False):
			lastState = True
			doActions()

except KeyboardInterrupt:
    raise SystemExit


Have a good day,

B

Please Log in or Create an account to join the conversation.

Time to create page: 0.092 seconds
Powered by Kunena Forum