QtVCP can be used to create control panels that interface with HAL.

1. Builtin Virtual Control Panels

There are several builtin HAL panels available.

In a terminal type qtvcp list to see a list.

1.1. copy

Used for copying QtVCP’s builtin Screens/VCP Panels/QtVismach code to a folder so one can customize it.

In a terminal run:

qtvcp copy
QtVCP copy Dialog - Screen, Panel or Vismach Code Copy Panel
Figure 1. QtVCP copy Dialog - Screen, VCP Panel or QtVismach Code Copy Panel

1.2. spindle_belts

This panel is designed to display additional RS485 VFD data and also to configure a 4 sheave, 2 belt spindle drive via a series of buttons.

QtVCP spindle_belts Panel - Spindle Belts VCP

In addition, it is also a useful template to use for your custom panel because it includes:

  • Display of additional HAL data

  • Buttons and button groups

  • Dynamic changes to button enabled/disabled state based on the state of other buttons

  • Saving data to the qtdragon.prefs file

  • Custom button to reset the VFD

Modify this panel to suit your own requirements. Most common features are used. The advantage of using panels is that it separates your custom display code from the qtdragon core code so upgrading the system will not break your customization.

1.2.1. Additional Requirements

  • A spindle drive (for instance VFDMOD)

  • A custom component that scales the VFD frequency to obtain the desired spindle speed.

  • A belt driven spindle that uses two belts and an intermediate idler pulley much like a drill press.

  • Connect the input pins qtdragon.belts.<pin-name> in your postgui HAL file.

1.2.2. Function

The belts are broken into two button groups, the front belts and the rear belts. These are numbered as per the plate on the machine. Buttons in a group are mutually exclusive, i.e., only one can be selected in the group.

Additionally, it’s not possible to have both belts on the same level with this kind of mechanism because you cannot fit two belts to the one idler pulley sheave. So if a belt is selected, its opposite button is disabled. E.g., if belt 3 is selected, belt 7 is disabled.

1.2.3. Embedding commands

Add these lines to the [DISPLAY] section in your .ini file
The example tab_location is for the QtDragon screen.

EMBED_TAB_NAME=Spindle Extras
EMBED_TAB_COMMAND=qtvcp spindle_belts
EMBED_TAB_LOCATION=tabWidget_utilities

Here is how to load spindle_belt from a HAL script:

loadusr qtvcp spindle_belts

1.2.4. Customization Hints

Customizing the panel:

  • Copy the files located in /user/share/qtvcp/qtdragon/panels/belts to: ~/linuxcnc/configs/<my_configuration_folder>/qtvcp/panels/belts (you can use the copy dialog panel to do this)

  • Edit belts.ui with designer.

  • Edit belts_handler.py with a text editor

  • Connect the relevant pins in a postgui.hal file

  • Make sure your postgui file is loaded by your .ini file.

For information on the finer points, consult the QtVCP and QtDragon documentation. The Python handler file also provides a useful template for any custom panel.

1.3. test_dial

  • This panel has a dial that adjusts S32 and Float HAL output pins.

  • The dial’s range can be adjusted from a drop down menu.

  • The output can be scaled with the spinbox.

  • A combobox can be used to automatically select and connect to a signal.

loadusr qtvcp test_dial
QtVCP test_dial Panel - Test Dial VCP
Figure 2. QtVCP test_dial Panel - Test Dial VCP

1.4. test_button

  • This panel has a button that will set a HAL pin.

  • The button can be selected as a momentary or a toggle button.

  • A HAL pin will be created that follows the button state.

  • The button’s indicator color can be adjusted from a drop down menu.

  • A HAL pin or signal can be selected to follow the button state.

  • You can add more buttons from the drop down menu.

  • You can load a Halmeter from the drop down menu.

  • You can load a test LED from the drop down menu.

  • The button can be detached from the main windows.

Here is how to load test_button from a HAL script:

loadusr qtvcp test_button
loadusr qtvcp -o 4 test_button

The -o switch sets how many buttons the panel starts with.
If loading directly from a terminal omit the loadusr.

QtVCP test_button - Test Button VCP
Figure 3. QtVCP test_button - Test Button VCP

1.5. test_led

  • This panel has an LED that can selected to watch HAL bit pins/signals.

  • The LED’s color can be adjusted from a drop down menu.

  • The text box and state can be output as speech if sound is selected.

  • A combobox can be used to automatically select and connect to a pin/signal.

  • You can add more LEDs from the drop down menu.

  • The LED can be detached from the main windows.

Here is how to load test_led from a HAL script:

loadusr qtvcp test_led
loadusr qtvcp -o 4 test_led

The -o switch sets how many LEDs the panel starts with.
If loading directly from a terminal omit the loadusr.

QtVCP test_dial Panel - Test LED VCP
Figure 4. QtVCP test_dial Panel - Test LED VCP

1.6. test_panel

Collection of useful widgets for testing HAL component, including speech of LED state.

loadusr qtvcp test_panel
QtVCP test_panel - HAL Component Testing Panel
Figure 5. QtVCP test_panel - HAL Component Testing Panel

1.7. cam_align

A camera display widget for rotational alignment.

QtVCP cam_align Panel - Camera Based Alignment Panel
Figure 6. QtVCP cam_align Panel - Camera Based Alignment Panel
Usage

Add these lines to the INI file:

[DISPLAY]
EMBED_TAB_NAME = cam_align
EMBED_TAB_COMMAND = halcmd loadusr -Wn qtvcp_embed qtvcp -d -c qtvcp_embed -x {XID} cam_align
# The following line is needed if embedding in GMOCCAPY
EMBED_TAB_LOCATION = ntb_preview
Note
All <options> must appear before the cam_align panel name.
Qtvcp Options
  • -c NAME HAL component name. Default is to use the UI file name.

  • -d Debugging on. or remove for no minimum output

  • -x {XID} used for embedding into AXIS or Gmoccapy

  • -o <option> Options passed to cam_align

Cam_align Options
  • size=400,400 Size of the embedded window (width,height)

  • imagesize=300,300 Size of the image inside the window (width,height)

  • rotincr=5 Sets the increment of the crosshair rotation. (degrees)

  • xscale=100 Scales the image in X. A negative value will flip the image in X (percent)

  • yscale=100 Scales the image in Y. A negative value will flip the image in Y (percent)

  • camnumber=1 Sets what system camera to use

For instance you can add window width and height size, rotation increment, and camera number from the INI with -o options.

EMBED_TAB_COMMAND = halcmd loadusr -Wn qtvcp_embed qtvcp -d -c qtvcp_embed -x {XID} -o size=400,400 -o rotincr=.2 -o camnumber=0 cam_align

Mouse controls:

  • left mouse single click - increase cross hair rotation one increment

  • right mouse single click - decrease cross hair rotation one increment

  • middle mouse single click - cycle through rotation increments

  • left mouse hold and scroll - scroll camera zoom

  • right mouse hold and scroll - scroll cross hair rotation angle

  • mouse scroll only - scroll circle diameter

  • left mouse double click - reset zoom

  • right mouse double click - reset rotation

  • middle mouse double click - reset circle diameter

To use the top buttons you have to assign a command (or a sub-routine). This could look like this:

[MDI_COMMAND_LIST]
MDI_COMMAND_CAM_ALIGN1=G10 L20 P1 X0 Y0,Set XY\nOrigin
MDI_COMMAND_CAM_ALIGN2=G0 X0 Y0,Go To\nOrigin

Where the first command is referring to the button "SET origin" and the second to the button "GOTO Origin".
Note the comma and text after is optional - it will override the default button text.
These buttons are QtVCP action buttons and follow those rules.

1.8. sim_panel

Small control panel to simulate MPG jogging controls etc for simulated configurations.
The MPG, selection buttons and control buttons export HAL pins to connect to linuxcnc.
The selection and control group boxes can be hidden if not needed by using the -o hide= option.
groupBoxControl and groupBoxSelection are the widget names that can be hidden.
If you want to hide both, use a comma between them with no spaces.
The -a option will make the panel always-on-top of all windows.

loadusr qtvcp sim_panel

Here we load the panel with no MPG selection buttons and the always-on-top option.

loadusr qtvcp -a -o hide=groupBoxSelection sim_panel
QtVCP sim_panel - Simulated Controls Panel For Screen Testing
Figure 7. QtVCP sim_panel - Simulated Controls Panel For Screen Testing.

1.9. tool_dialog

Manual tool change dialog that gives tool description.

loadusr -Wn tool_dialog qtvcp -o speak_on -o audio_on tool_dialog

Options:

  • -o notify_on - use desktop notify dialogs instead of QtVCP native ones.

  • -o audio_on - play sound on tool change

  • -o speak_on - speak announcement of tool change

QtVCP tool_dialog - Manual Tool Change Dialog
Figure 8. QtVCP tool_dialog - Manual Tool Change Dialog

2. vismach 3D Simulation Panels

These panels are prebuilt simulation of common machine types.

These are also embed-able in other screens such as AXIS or GMOCCAPY.

2.1. QtVCP vismach_mill_xyz

3D OpenGL view of a 3-Axis milling machine.

loadusr qtvcp vismach_mill_xyz
QtVCP vismach_mill_xyz - 3-Axis Mill 3D View Panel
Figure 9. QtVCP vismach_mill_xyz - 3-Axis Mill 3D View Panel

2.2. QtVCP vismach_router_atc

3D OpenGL view of a 3-Axis router style, gantry bed milling machine.
This particular panel shows how to define and connect the model parts in the handler file, rather then importing the pre-built model from QtVCP’s vismach library.

loadusr qtvcp vismach_router_atc
QtVCP vismach_router_atc - 3-Axis Gantry Bed Mill 3D View Panel
Figure 10. QtVCP vismach_router_atc - 3-Axis Gantry Bed Mill 3D View Panel

2.3. QtVCP vismach_scara

3D OpenGL view of a SCARA based milling machine.

loadusr qtvcp vismach_scara
QtVCP vismach_scara - SCARA Mill 3D View Panel
Figure 11. QtVCP vismach_scara - SCARA Mill 3D View Panel

2.4. QtVCP vismach_millturn

3D OpenGL view of a 3-Axis milling machine with an A axis/spindle.

loadusr qtvcp vismach_millturn
QtVCP vismach_millturn - 4 Axis MillTurn 3D View Panel
Figure 12. QtVCP vismach_millturn - 4 Axis MillTurn 3D View Panel

2.5. QtVCP vismach_mill_5axis_gantry

3D OpenGL view of a 5-Axis gantry type milling machine.

loadusr qtvcp vismach_mill_5axis_gantry
QtVCP vismach_mill_5axis_gantry - 5-Axis Gantry Mill 3D View Panel
Figure 13. QtVCP vismach_mill_5axis_gantry - 5-AxIs Gantry Mill 3D View Panel

2.6. QtVCP vismach_fanuc_200f

3D openGL view of a 6 joint robotic arm.

loadusr qtvcp vismach_fanuc_200f
QtVCP vismach_fanuc_200f - 6 Joint Robotic Arm
Figure 14. QtVCP vismach_fanuc_200f - 6 Joint Robotic Arm

3. Custom Virtual Control Panels

You can of course make your own panel and load it.

If you made a UI file named my_panel.ui and a HAL file named my_panel.hal, you would then load this from a terminal with:

halrun -I -f my_panel.hal
Example HAL file loading a QtVCP panel
# load realtime components
loadrt threads
loadrt classicladder_rt

# load non-realtime programs
loadusr classicladder
loadusr -Wn my_panel qtvcp my_panel.ui  # <1>

# add components to thread
addf classicladder.0.refresh thread1


# connect pins
net bit-input1     test_panel.checkbox_1        classicladder.0.in-00
net bit-hide       test_panel.checkbox_4        classicladder.0.hide_gui

net bit-output1    test_panel.led_1             classicladder.0.out-00

net s32-in1        test_panel.doublescale_1-s   classicladder.0.s32in-00

# start thread
start
  1. In this case we load qtvcp using -Wn which waits for the panel to finish loading before continuing to run the next HAL command.
    This is to ensure that the panel created HAL pins are actually done in case they are used in the rest of the file.

4. Embedding QtVCP Virtual Control Panels into QtVCP Screens

QtVCP panels can be embedded into most QtVCP screens and avoids problems such as focus transferring that can be a problem in non-native embedding.

4.1. Embedding Commands

A typical screen such as QtDragon will search the INI file under the heading [DISPLAY] for commands to embed a panel.

[DISPLAY]
EMBED_TAB_NAME=Embedding demo
EMBED_TAB_COMMAND=qtvcp simple_hal
EMBED_TAB_LOCATION=tabWidget_utilities
EMBED_TAB_NAME

will typically be the title of the tab.

EMBED_TAB_LOCATION

will be specific to the screen and specifies the tabWidget or stackedWidget to embed into.

EMBED_TAB_COMMAND

is the command used to invoke loading of the panel. For native embedded panels the first word will always be qtvcp, the last will be the panel name to load. You can also pass options to the panel with -o switches in the command line between qtvcp and the panel name. The panel will follow the debugging mode setting of the main screen.

4.2. Location of builtin Panels

There are panels available that are included with LinuxCNC. To see a list open a terminal and type qtvcp and press return.
You will get a help printout and a list of builtin screen and panels.
Pick any of the names from the panel list and add that to the COMMAND entry after qtvcp.
The builtin panel search path is share/qtvcp/panels/PANELNAME.
Run-In-Place and installed versions of LinuxCNC have these in different locations on the system.

4.3. Location of Custom Panels

Custom panels can be embedded too -either a modified builtin panel or a new user-built one.
When loading panels, QtVCP looks in the configuration folders path for qtvcp/panels/PANELNAME/PANELNAME.ui.
PANNELNAME being any valid string with no spaces. If no path is found there, then looks in the builtin file path.
QtVCP will do the same process for the optional handler file: qtvcp/panels/PANELNAME/PANELNAME_handler.py

4.4. Handler Programming Tips

In a screen handler file, the reference used for the window is self.w.
In QtVCP panels, that reference will refers to the panel’s window.
To reference the main window use self.w.MAIN. If your panel is to be able to run independently and embedded, you must trap errors from referencing objects not available. (Note, main screen objects are not available in an independent panel.)

E.g., this would use the panel’s preference file if there is one.

try:
    belt_en = self.w.PREFS_.getpref('Front_Belt_enabled', 1, int, 'SPINDLE_EXTRAS')
except:
    belt_en = 1

This would use the main screen preference file if there is one.

try:
    belt_en = self.w.MAIN.PREFS_.getpref('Front_Belt_enabled', 1, int, 'SPINDLE_EXTRAS')
except:
    belt_en = 1

4.5. Designer Widget Tips

When using Python command option in Action Button widgets of an embedded panel:

INSTANCE

refers to the panel window. E.g., INSTANCE.my_panel_handler_function_call(True)

MAIN_INSTANCE

refers to the main screen window. E.g., MAIN_INSTANCE.my_main_screen_handler_function_call(True)

If the panel is not embedded, both refer to the panel window.

4.6. Handler Patching - Subclassing Builtin Panels

We can have QtVCP load a subclassed version of the standard handler file. In that file we can manipulate the original functions or add new ones.
Subclassing just means our handler file first loads the original handler file and adds our new code on top of it - effectively a patch of changes.
This is useful for changing/adding behaviour while still retaining standard handler updates from LinuxCNC repositories.

You may still need to use the handler copy dialog to copy the original handler file to decide how to patch it.

There should be a folder in the config folder; for panel: named <CONFIG FOLDER>/qtvcp/panels/<PANEL NAME>/
add the handle patch file there, named like so <ORIGINAL PANEL NAME>_handler.py,
i.e. for cam_align the file would be called cam_align_handler.py.

Here is a sample to change the circle color in cam_align:

import sys
import os
import importlib
from PyQt5.QtCore import Qt
from qtvcp.core import Path

PATH = Path()

# get reference to original handler file so we can subclass it
sys.path.insert(0, PATH.PANELDIR)
panel = os.path.splitext(os.path.basename(os.path.basename(__file__)))[0]
base = panel.replace('_handler','')
module = "{}.{}".format(base,panel)
mod = importlib.import_module(module, PATH.PANELDIR)
sys.path.remove(PATH.PANELDIR)
HandlerClass = mod.HandlerClass

# return our subclassed handler object to Qtvcp
def get_handlers(halcomp, widgets, paths):
    return [UserHandlerClass(halcomp, widgets, paths)]

# subclassed from HandlerClass which was imported above
class UserHandlerClass(HandlerClass):
    print('Custom subclassed panel handler loaded\n')

    def initialized__(self):
        # call original handler initialized function
        super().initialized__()

        # add our customization
        self.w.camview.circle_color = Qt.green