Part 4a

Polling the Error Channel

Setup

  1. Open up gui3.glade and save as gui4.glade.

  2. Open up gui3.py and save as gui4.py

The Python

  1. The first thing we will do is create an instance of the error channel and the status bar by adding the following to our init function.

    self.error_channel = self.emc.error_channel()
    self.statusbar = self.builder.get_object("statusbar1")
  2. The next thing we will do is add the following code to the periodic function to poll the error channel and if an error is found pop it to the status bar. A reminder if you add something to the periodic function that has an error it will not run so check for typos if you don’t get what you expect.

    # poll the error channel
    self.error_status = self.error_channel.poll()
    
    # if the error status is non zero push the error to the status bar
    if self.error_status: # if we have an error lets do something about it
    
      # print the object type which will show that it is a tuple
      print type(self.error_status)
    
      # print the tuple which might show up as (11, "Bad character 'a' used")
      print self.error_status
    
      # this will assign the integer to error_kind and the text to error_text
      self.error_kind, self.error_text = self.error_status
    
      # here we can determine if the error is critical or just informative
      if self.error_kind in (linuxcnc.NML_ERROR, linuxcnc.OPERATOR_ERROR):
        self.error_type = "Error "
      else:
        self.error_type = "Info "
      self.message_id = self.statusbar.push(0, self.error_type + self.error_text)

    Some information about NML messages like OPERATOR_ERROR can be found in the NML Messages chapter of the Developer Manual.

  3. Next we will change gui3 to gui4 in the python file.

The complete python file.

gui4.py
#!/usr/bin/env python

import gtk
import gobject
import gladevcp.makepins
from gladevcp.gladebuilder import GladeBuilder
import hal
import sys,os

# set up paths to files
BASE = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), ".."))
libdir = os.path.join(BASE, "lib", "python")
sys.path.insert(0, libdir)
datadir = os.path.join(BASE, "share", "linuxcnc")
xmlname = os.path.join(datadir,"gui4.glade")

import linuxcnc

class gui4(object):

  def __init__(self):
    self.emc = linuxcnc
    self.error_channel = self.emc.error_channel()
    self.status = self.emc.stat()
    self.builder = gtk.Builder()
    self.builder.add_from_file(xmlname)
    self.halcomp = hal.component("gui4")
    self.builder.connect_signals(self)
    self.window = self.builder.get_object("window1")
    self.statusbar = self.builder.get_object("statusbar1")
    self.window.show()
    self.panel = gladevcp.makepins.GladePanel(self.halcomp, xmlname, self.builder, None)
    self.halcomp.ready()
    # since the main loop is needed to handle the UI and its events, blocking calls like sleep()
    # will block the UI as well, so everything goes through event handlers (aka callbacks)
    # The gobject.timeout_add() function sets a function to be called at regular intervals
    # the time between calls to the function, in milliseconds
    gobject.timeout_add(100, self.periodic) # time between calls to the function, in milliseconds
    self.machine_status = 0

  def periodic(self): # fetch status items and update screen

    # poll the error channel
    self.error_status = self.error_channel.poll()
    if self.error_status:
      self.error_kind, self.error_text = self.error_status
      if self.error_kind in (linuxcnc.NML_ERROR, linuxcnc.OPERATOR_ERROR):
        self.error_type = "Error "
      else:
        self.error_type = "Info "
      self.message_id = self.statusbar.push(0, self.error_type + self.error_text)

    # poll the status channel
    self.status.poll()
    data = self.status.actual_position[0]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_x").set_text(text)

    data = self.status.actual_position[1]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_y").set_text(text)

    data = self.status.actual_position[2]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_z").set_text(text)

    return True # must return True to keep running

  def on_hal_stat1_mode_mdi(self, widget, data=None):
    self.mode_mdi = 1

  def on_test_button_clicked(self, widget, data=None):
    self.status.poll()
    print self.machine_status

  def on_window1_destroy(self, widget, data=None):
    print "quit with cancel"
    gtk.main_quit()

  def on_gtk_quit_activate(self, menuitem, data=None):
    print "quit from menu"
    gtk.main_quit()

if __name__ == "__main__":
  app = gui4()
  gtk.main()

Install your GUI

  1. To install your GUI rename gui4.py to gui4 with no extension. Open a terminal and change to your directory that contains the gui4 and gui4.glade files. Type in ls and make sure the gui4 file is green, if not change the permissions to execute with chmod +x gui4. Now to copy these files to the installed locations for LinuxCNC use these commands in a terminal.

    sudo cp gui4 /usr/bin
    sudo cp gui4.glade /usr/share/linuxcnc
  2. Make a copy of the linuxcnc/configs/gui3 directory and paste it back to the linuxcnc/configs directory then rename it to gui4.

  3. In the linuxcnc/gui4 directory rename gui3.hal to gui4.hal and gui3.ini to gui4.ini

  4. Open gui4.ini with a text editor and change the following lines:

    MACHINE = gui3
    to
    MACHINE = gui4
    
    DISPLAY = gui3
    to
    DISPLAY = gui4
    
    HALFILE = gui3.hal
    to
    HALFILE = gui4.hal
  5. Create a desktop launcher to run gui4.ini in a terminal.

Testing our Changes

  1. Create a test G code file and save it in the linuxcnc/nc_files directory.

    error.ngc
    A100
  2. Using the desktop launcher start up the GUI open the test G code file. Release the E-Stop and turn the power on and try and run the code. You should see the error on the status bar.

    Your GUI should look like this now.

    images/gui-04-01.png