Programming a 'custom' button

More
10 Apr 2013 19:31 #32525 by beltramidave
John,
Your tutorials are awesome! Thanks.

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

More
10 Apr 2013 22:25 #32529 by andypugh

I need a way for an operator to "add" a new position to a button. I was hoping that if I created a 'custom' button in my .xml file and tied it to a MDI command in the .ini file that I could somehow transfer my wanted position coordinates into my MDI command in the .ini file.


Would a button that stores the position in persistent G-code variables (#5161-#5390) work?
www.linuxcnc.org/docs/html/gcode/overview.html#sec:parameters

Program button calls MDI sub, #5161=#5420 / #5162=#5421

Recall button calls MDI sub G0 X#5161 Y#5162

PyVCP indicators could be updated by the first button by use of G-code analogue inputs. ( www.linuxcnc.org/docs/html/gcode/m-code....ec:M68-Analog-Output )
The following user(s) said Thank You: beltramidave

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

More
10 Apr 2013 22:41 #32533 by ArcEye
Just shows there are as many ways to skin a cat, as there are cats, Andy has another method.

I'll leave you to read JTs tutorials, which have certainly fleshed out and increased since I last visited, looking very good.

If you want to try the C, component method later, you know where to ask.

regards
The following user(s) said Thank You: beltramidave

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

More
11 Apr 2013 01:24 #32547 by beltramidave
Andy,

This looks like what I am after. I see the current X & Y positions are held in 5420 & 5421. So by pushing the 'program' button, it will load those values into 5161 & 5162 and then pushing the 'recall' button, it will run a subroutine with the coordinates from 5161 & 5162? Are these values retained in 5161 & 5162 until they are replaced, even after a program restart? What is the range of parameter numbers that can be used for this purpose (so I could have multiple buttons)?

I am not sure that I understand what you are doing with the analog input.

Any chance I could persuade you into giving a sample of code to help me better understand this whole process? I very much appreciate everyone's input on this as it seems that I am always pressing the limits on what can be done.

ArcEye, I would still be interested in hearing your method if you think I could understand it.

Regards

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

More
11 Apr 2013 05:34 #32551 by andypugh

Are these values retained in 5161 & 5162 until they are replaced, even after a program restart?


According to the link I posted, they are. (I actually think that you can add other numbers to the .vars file and they will also be stored on shut-down).

The analog outputs would just be set by the same G-code sub that it storing the values, putting the numbers on HAL pins to be displayed in the PyVCP.

#5161=#5420
#5162=#5421
M68 E0 Q#5161
M68 E1 Q#5162

Then net some pyvcp display thing to motion.analog-out-00 and motion.analog-out-01.

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

More
12 Apr 2013 00:09 #32583 by ArcEye

ArcEye, I would still be interested in hearing your method if you think I could understand it.


It is simply a userspace component ( running in a normal binary thread rather than in kernel space, so that you have access to file I/O etc)

I haven't written it, my mental roadmap is:

It would have pins that are connected to Xpos and Ypos signals to get current position
Upon a trigger signal to another pin from a pyVCP button, these co-ordinate pairs are allocated to an array of positions

Each array index could be output to an out pin, so that they can be displayed by a pyVCP number widget
Each index would also have an activate pin to be linked to a 'goto' pyVCP button

There is an option to load pre-set co-ordinate pairs from file either automatically or on command, likewise writing to file before closure.
This would open up the possibility of several different preset files, or simply persistence between boots

When the operator presses the trigger button, the current co-ordinates are saved and displayed in a label by a 'goto' button.
When the 'goto' button is pressed a move to the associated co-ordinates is commanded

Whether this outline is of use to you depends upon your knowledge of programming, to be able to maintain it and tailor to the requirements of your design process.

I would write it in C as a .comp file, but you could do exactly the same in python

If you want something that you can implement within the .hal .ini files using existing resources, then Andys solution may be easier for you.

regards

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

More
12 Apr 2013 00:16 #32584 by beltramidave
Your idea sounds really cool, but I don't know anything about C programming and I am still very green in Python, but learning daily. I have not got a chance to try Andy's idea yet, but hope to over the weekend.

Thanks

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

More
14 Apr 2013 18:58 - 14 Apr 2013 19:01 #32722 by ArcEye
Hi

I have written a userspace module called points, along the lines I outlined.

Attached is a simulator based upon axis_mm which incorporates it.
Place the folder /points in your /home/yourname/linuxcnc/configs folder
Copy the binary points in that folder to /usr/bin
Create a blank file called /usr/share/linuxcnc/points.txt (touch /usr/share/linuxcnc/points.txt)

An item to note, points captures co-ordinates in machine co-ordinates and outputs G53 commands
(press # to display machine co-ordinates and the DRO and captured points will make sense)





The code is here, however note you would have to patch comp as described in the code, to be able to compile the code as it is.
component points                    "hal userspace component to plot XY points";

pin in float xposition              "Receives current position from Xpos";
pin in float yposition              "Receives current position from Ypos";

pin in bit savepoints = 0           "Trigger to save current XY co-ordinates";
pin in bit previous = 0             "Trigger to move current points back one";
pin in bit next = 0             "Trigger to move current points forward one";
pin in bit loadfile = 0             "Load XY co-ordinates from file";
pin in bit writefile = 0            "Write XY co-ordinates to file";

pin out float xout-##[8] = 0        "X Output values";
pin out float yout-##[8] = 0        "Y Output values";

pin in bit gotoXY-##[8] = 0         "Trigger pin to goto points in array";
pin out bit select-##[8] = 0        "pin to light led to indicate which points current";

option singleton yes;               
option userspace yes;

author "ArcEye - 2013";
license "GPL";
;;

/**********************************************************************
NB.  This file is intended to be compiled with my own version of comp
which creates the struct __comp_state *inst as a global
to allow direct manipulation of pin values etc

comp.patch

--- /usr/bin/comp-orig	2012-10-10 16:11:00.000000000 +0100
+++ /usr/bin/comp	2013-04-13 12:42:51.000000000 +0100
@@ -653,7 +653,8 @@
         print >>f, "#define true (1)"
         print >>f, "#undef false"
         print >>f, "#define false (0)"
-
+## altered to expose the struct for use in comp files
+    print >>f, "struct __comp_state *inst;"
     print >>f
     if has_personality:
         print >>f, "static int export(char *prefix, long extra_arg, long personality) {"
@@ -664,7 +665,7 @@
     if has_array:
         print >>f, "    int j = 0;"
     print >>f, "    int sz = sizeof(struct __comp_state) + __comp_get_data_size();"
-    print >>f, "    struct __comp_state *inst = hal_malloc(sz);"
+    print >>f, "    inst = hal_malloc(sz);"
     print >>f, "    memset(inst, 0, sz);"
     if has_data:
         print >>f, "    inst->_data = (char*)inst + sizeof(struct __comp_state);"

***********************************************************************/

#include <stdio.h>    /* Standard input/output definitions */
#include <stdlib.h> 
#include <stdint.h>   /* Standard types */
#include <string.h>   /* String function definitions */
#include <unistd.h>   /* UNIX standard function definitions */
#include <fcntl.h>    /* File control definitions */
#include <errno.h>    /* Error number definitions */
#include <signal.h>

int done = 0;

void adios(int sig)
{
    done = 1;
}


void user_mainloop(void)
{
char points_file[] = "/usr/share/linuxcnc/points.txt";

char buffX[80];
char buffY[80];
char buff_cmd[120];

int j = 0;
int point_index = 0;
int saved, loaded, written, next_pressed, previous_pressed, go_pressed;
int retval = 1;

    signal(SIGINT, adios);
    signal(SIGTERM, adios);
    
    // flags to prevent cycling whilst button depressed 
    saved = loaded = written = next_pressed = previous_pressed = go_pressed = 0;
    
    bzero(buffX, 80);
    bzero(buffY, 80);    
    bzero(buff_cmd, 120);
    
        while(!done)
            {
            usleep(100000);
            FOR_ALL_INSTS()  
                { 
                ////////////////////////////////////////////////////////////////////////////
                // button pressed to save current points 
                if(savepoints && !saved)            
                    {
                    if(point_index == 8)  // if array full go back to start
                        point_index = 0; 
                    *(inst->xout[point_index]) = xposition;
                    *(inst->yout[point_index]) = yposition;
                    point_index++;
                    saved = 1;
                    }
                ////////////////////////////////////////////////////////////////////////////
                // button pressed to load points from file
                if(loadfile && !loaded)         
                    {
                    FILE *fptr1;
                    fptr1 = fopen(points_file, "r");
                    if(fptr1 != NULL)
                        {                    
                        point_index = 0;
                        retval = 1;
                        while(retval && (point_index < 8))
                            {
                            if(fgets(buffX, 80, fptr1) != NULL )
                                *(inst->xout[point_index]) =  atof(buffX);
                            else
                                retval = 0;
                                
                            if(fgets(buffY, 80, fptr1) != NULL )
                                *(inst->yout[point_index]) = atof(buffY); 
                            else
                                retval = 0;   
                            point_index++;
                            }
                        point_index--;  // it will be one higher than it should be
                        fclose(fptr1);
                        loaded = 1;
                        printf("Points loaded from %s\n",points_file);
                        }
                    else
                        printf("Failed to open %s\n", points_file);
                    }
                //////////////////////////////////////////////////////////////////////////////    
                // button pressed to write points to file
                if(writefile && !written)          
                    {
                    FILE *fptr2;
                    fptr2 = fopen(points_file, "w");
                    if(fptr2 != NULL)
                        {
                        for(j = 0; j < 8; j++)
                            {
                            fprintf(fptr2, "%09.04f\n", *(inst->xout[j])); 
                            fprintf(fptr2, "%09.04f\n", *(inst->yout[j]));   
                            }
                        written  = 1;
                        fclose(fptr2);
                        printf("Points written to %s\n",points_file);
                        }
                    else
                        printf("Failed to open %s\n", points_file);
                    }             
                ////////////////////////////////////////////////////////////////////
                // next and previous points buttons
                if(next && !next_pressed)
                    {
                    point_index++;
                    next_pressed = 1;
                    }
                if(previous && !previous_pressed)
                    {
                    point_index--;
                    previous_pressed = 1;
                    }
                ////////////////////////////////////////////////////////////////////
                // update current points LED
                if(point_index > 7) 
                        point_index = point_index - 8; 
                if(point_index < 0) 
                        point_index = point_index + 8; 
                
                for(j = 0; j < 8; j++)
                    {
                    if(j == point_index)
                        *(inst->select[j]) = 1;
                    else
                        *(inst->select[j]) = 0;                                      
                    }
                ///////////////////////////////////////////////////////////////////    
                // check for goto button activation
                if(!go_pressed)
                    {
                    for(j = 0; j < 8; j++)
                        {
                        if(*(inst->gotoXY[j]))
                            {
                            go_pressed = 1;
                            sprintf(buff_cmd, "axis-remote --mdi 'G53 G00 X%9.4f Y%9.4f'", *(inst->xout[j]), *(inst->yout[j]) );
                            system(buff_cmd);
                            bzero(buff_cmd, 120);
                            break;
                            }
                        }
                    }
                     
                ///////////////////////////////////////////////////////////////
                // zero the flags if the relevant button has been released                  
                if(!savepoints && saved) saved = 0;
                if(!loadfile && loaded) loaded = 0;
                if(!writefile && written) written = 0;
                if(!next && next_pressed) next_pressed = 0;
                if(!previous && previous_pressed) previous_pressed = 0;
                
                if(go_pressed)
                    {
                    go_pressed = 0;
                    for(j = 0; j < 8; j++)
                        {
                        if(*(inst->gotoXY[j]))
                            {
                            go_pressed = 1;
                            break;
                            }
                        }
                    } 
                //////////////////////////////////////////////////////////////
                                   
                } // FOR_ALL_INSTS          
            }// while(!done)
    
    exit(0);
}

It is not a polished item and not warranted fit for any purpose whatsoever.

Just shows what is possible and how flexible Linuxcnc is.

regards

File Attachment:

File Name: points.zip
File Size:15 KB
Attachments:
Last edit: 14 Apr 2013 19:01 by ArcEye.
The following user(s) said Thank You: beltramidave

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

More
14 Apr 2013 22:10 #32729 by andypugh

The code is here, however note you would have to patch comp as described in the code, to be able to compile the code as it is.


That might not be necessary any more:
git.linuxcnc.org/gitweb?p=linuxcnc.git;a...b0657e9655236f614353
(Or might be more necessary)
The following user(s) said Thank You: beltramidave

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

More
14 Apr 2013 22:16 #32730 by ArcEye
Sebs patch is far more comprehensive than my quick hack.

Excellent, I was not aware of that, great minds obviously think alike. (or fools never differ!)

It certainly makes programming, using arrays of pins in particular, much easier.

cheers

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

Time to create page: 0.185 seconds
Powered by Kunena Forum