Axis not always polling for state correctly?

More
09 Jan 2016 03:03 #68095 by tome
I posted this on the dev email list as well (as a followup to subject: Axis bug in 2.7.3 (was: Question on a change in Axis from 2.5 to 2.7.3). Thought I'd post here as well in case some aren't on the dev list.

We have a glade panel that among other things has three buttons, "Touch Off X,Y", "Go To Machine Zero", and "Go to Home - Touch off Point". Rather than execute mdi commands (in .ngc files) and using axis-remote to reload the file on touch off (which was causing problems) we changed our gladevcp panel to execute python functions directly and are reloading the file after touch off using a tk call within Python. The code that pertains to the button presses is:
      def mdi_exec(self,c,s,cmd):
              s.poll()
              if not s.estop and s.enabled and s.homed and (s.interp_state == linuxcnc.INTERP_IDLE):
                      c.mode(linuxcnc.MODE_MDI)
                      while c.wait_complete() == -1:
                              pass

                      c.mdi(cmd)
                      while c.wait_complete() == -1:
                              pass

      def on_touchoffXYbtn_pressed(self,obj,data=None):
              t = Tkinter.Tk(); t.wm_withdraw()

              c = linuxcnc.command()
              s = linuxcnc.stat()
              s.poll()
              start_mode = s.motion_mode

              c.mode(linuxcnc.MODE_MDI)
              self.mdi_exec(c,s,"G10 L20 P1 X0Y0")

              try:
                 msg = t.tk.call("send", "axis", ("remote","reload_file"))
              except:
                 pass
              while c.wait_complete() == -1:
                 pass

              c.mode(start_mode)
              while c.wait_complete() == -1:
                 pass

      def on_gomachinezero_btn_pressed(self,obj,data=None):
              c = linuxcnc.command()
              s = linuxcnc.stat()
              s.poll()
              start_mode = s.motion_mode

              self.mdi_exec(c,s,"G53 G0 Z0")
              self.mdi_exec(c,s,"G53 G0 X0Y0Z0")

              c.mode(start_mode)
              while c.wait_complete() == -1:
                 pass

      def on_gohome_btn_pressed(self,obj,data=None):
              c = linuxcnc.command()
              s = linuxcnc.stat()
              s.poll()
              start_mode = s.motion_mode

              self.mdi_exec(c,s,"G53 G0 Z0")
              self.mdi_exec(c,s,"G0 X0Y0")
              self.mdi_exec(c,s,"G0 Z0")

              c.mode(start_mode)
              while c.wait_complete() == -1:
                 pass

As you can see we are saving the initial MODE (Axis tab state), and restoring that after the gcode (and/or reload) is completed. The touch off/reload definition seems to complete 100% of the time - always restoring Axis to the tab it started in.

The other two definitions however only complete about 90% of the time. What we suspect (though don’t know for sure) is that even though we are requesting the mode change and Linuxcnc indeed changes it's mode, Axis does not poll, for some reason, and so doesn’t get the message and change it’s tab to manual. Again, it does work about 90% of the time, but 1 out of 10 times or so Axis just doesn’t change back to the Manual Mode after going into MDI mode to execute the commands. Even if we explicitly change mode to manual ( c.mode(linuxcnc.MODE_MANUAL)) rather than using our saved start_mode value (c.mode(start_mode)), it still fails intermittently. Even if we put in long pauses (using time.sleep()) it still fails.

Considering that the first touch off definition seems to complete correctly is there something about the fact that we are tickling Axis to reload the the file that is helping us? That is happening before the restore mode though so I don’t understand why it would. I don’t NEED to reload the file on the moves to machine zero or home point but I guess I will try that to see if it helps. Is there some way to yell at Axis to poll and get in sync? If that is what is failing. Or what else might be going on?

-Tom

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

More
09 Jan 2016 05:04 - 09 Jan 2016 05:06 #68100 by cmorley
So the idea of the wait_complete() is to...wait for it to complete the MDI command.
(well, wait for whatever command to linuxcnc complete)
It actually block execution of the python script.

on the two routines you have that don't work properly, you have the wait_complete _after_ the request for mode change.
On the one that works you have it after as well but you have another wait just before the mode change request.

You need;

record mode
mdi command
wait for it to complete
change the mode.

Chris M
Last edit: 09 Jan 2016 05:06 by cmorley.

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

More
09 Jan 2016 05:48 - 09 Jan 2016 05:49 #68105 by tome

So the idea of the wait_complete() is to...wait for it to complete the MDI command.
(well, wait for whatever command to linuxcnc complete)
It actually block execution of the python script.

on the two routines you have that don't work properly, you have the wait_complete _after_ the request for mode change.
On the one that works you have it after as well but you have another wait just before the mode change request.

You need;

record mode
mdi command
wait for it to complete
change the mode.

Chris M


All of the functions, the touch off that works and the go-to's that don't, the mdi command is executed in the function mdi_exec which has a wait after the mode change AND after the command itself. The wait that is then in the failing function(s) after the mode change was just put in there to see if that would help (it didn't). In other words we ARE waiting after every single action but it is still failing.

So we do have waits in the order you suggest in addition to the wait after the mode change....

-Tom
Last edit: 09 Jan 2016 05:49 by tome.

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

More
09 Jan 2016 20:37 - 09 Jan 2016 20:38 #68123 by cmorley
Ahh yes I see that now - sorry.

Well the next thing I wonder is about the wait time of wait_complete()
Does the distance the machine has to move make any difference in the reliability of the change?
I mean if it is very close (less then couple seconds of movement) does it work right all the time?

Another technique you could use is make an gobject timer that checks for the interpreter idle and changes mode then.
The function sets a global variable that says what mode you wish to change to.
the timer checks for idleness then changes the mode then resets the variable to ignore.
I can give you code example is you like.

But I would see if extending the wait_complete() time helps : wait_conplete(2) maybe

Chris M
Last edit: 09 Jan 2016 20:38 by cmorley.

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

More
09 Jan 2016 22:54 - 09 Jan 2016 22:55 #68135 by tome

Ahh yes I see that now - sorry.

Well the next thing I wonder is about the wait time of wait_complete()
Does the distance the machine has to move make any difference in the reliability of the change?
I mean if it is very close (less then couple seconds of movement) does it work right all the time?


I will try that next time I am at the machine. I don't know the answer, I was always moving to the same spot which was fairly far from home. I will do some experimentation with that.

Another technique you could use is make an gobject timer that checks for the interpreter idle and changes mode then.
The function sets a global variable that says what mode you wish to change to.
the timer checks for idleness then changes the mode then resets the variable to ignore.
I can give you code example is you like.


Yes, please. I would like to give that a try as well.

But I would see if extending the wait_complete() time helps : wait_conplete(2) maybe

Chris M


Will try that as well.

Thanks Chris!
-Tom
Last edit: 09 Jan 2016 22:55 by tome.

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

More
10 Jan 2016 02:53 - 10 Jan 2016 02:57 #68145 by cmorley
import gobject

def some_init_code:
        self.emc = linuxcnc
        self.emcstat = linuxcnc.stat()
        self.emccommand = linuxcnc.command()
        # The update time: every 100 milliseonds
        gobject.timeout_add(100, self.periodic) 

def periodic(self):
            # return mode back to preset variable, when idle
        if self.return_to_mode > -1:
            self.emcstat.poll()
            if self.emcstat.interp_state == self.emc.INTERP_IDLE:
                self.emccommand.mode(self.return_to_mode)
                self.return_to_mode = -1

# checks if ready for commands
# calls MDI commands and when idle, periodic() will return to the mode it was in
 def mdi_and_return(self, cmd):
        if self.ok_for_mdi():
            self.return_to_mode = self.get_mode() # for periodic()
            self.set_mdi_mode()
            self.emccommand.mdi(str(cmd))

This should give you the general idea.
There are a few functions missing - I think you can figure it out.

Chris M
Last edit: 10 Jan 2016 02:57 by cmorley.

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

More
21 Jan 2016 01:36 #68859 by tome
So it turns out we were already waiting on interpreter idle. But that isn't enough. I ended up putting in some 0.2 sec waits before attempting to change mode in the code in order to get it to complete successfully 100% (I think) of the time. It's a hack but it seems to work.
	def on_gomachinezero_btn_pressed(self,obj,data=None):
                c = linuxcnc.command()
                s = linuxcnc.stat()
                s.poll()
                start_mode = s.motion_mode
                #print "!!Start Mode: ", start_mode

                self.mdi_exec(c,s,"G53 G0 Z0")
                self.mdi_exec(c,s,"G53 G0 X0Y0Z0")

		s.poll()
		while (s.interp_state != linuxcnc.INTERP_IDLE):
			time.sleep(0.1)
			s.poll()
		time.sleep(.2)
                c.mode(start_mode)
                while c.wait_complete() == -1:
                   pass

	def on_gohome_btn_pressed(self,obj,data=None):
                c = linuxcnc.command()
                s = linuxcnc.stat()
                s.poll()
                start_mode = s.motion_mode
                #print "!!Start Mode: ", start_mode

                self.mdi_exec(c,s,"G53 G0 Z0")
                self.mdi_exec(c,s,"G0 X0Y0")
                self.mdi_exec(c,s,"G0 Z0")

		s.poll()
		while (s.interp_state != linuxcnc.INTERP_IDLE):
			time.sleep(0.1)
			s.poll()
		time.sleep(.2)
                c.mode(start_mode)
                while c.wait_complete() == -1:
                   pass

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

Time to create page: 0.110 seconds
Powered by Kunena Forum