• Tags
  • Documentation
  • Order
  • Register
  • Login
Duet3D Logo Duet3D
  • Tags
  • Documentation
  • Order
  • Register
  • Login

A couple of questions regarding global variables

Scheduled Pinned Locked Moved
Gcode meta commands
6
22
2.1k
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • undefined
    deckingman
    last edited by 24 Aug 2021, 08:31

    Short version.

    Q1 This guide https://duet3d.dozuki.com/Wiki/GCode_Meta_Commands talks about how to declare global variables but it doesn't say where to put that declaration. Would I be correct in assuming that I could add the relevant commands to the end of my config.g file for example?

    Q2 The same guide states "Within a macro file, parameters that were passed to the macro (typically in the M98 command) can be retrieved using the syntax....." But the description of M98 https://duet3d.dozuki.com/Wiki/Gcode#Section_M98_Call_Macro_Subprogram makes no mention of how to pass parameters to a macro. Would I be correct in assuming that if I declare a global variable in config.g, then it will be automatically available within any macro or do I need to do something to pass the variable to the macro (and if so, what and how)?

    Longer version

    I have a number of macros (nozzle heat, purge, wipe and sections of my homing files) which move a number of gantries (XY, UV and AB) to the same fixed set of XY co-ordinates. But those XY co-ordinates might need to be "tweaked". Changing every co-ordinate, for every macro is a little tiresome (and prone to "fat finger syndrome") so I'd like to set those co-ordinates in one place. I.e. use global variables which be used by all gantries and all macros (e.g "left_pos" and "rear_pos" or some such names).

    Ian
    https://somei3deas.wordpress.com/
    https://www.youtube.com/@deckingman

    undefined 1 Reply Last reply 24 Aug 2021, 08:36 Reply Quote 0
    • undefined
      jay_s_uk @deckingman
      last edited by 24 Aug 2021, 08:36

      @deckingman said in A couple of questions regarding global variables:

      that I could add the relevant commands to the end of my config.g file for example?

      yes or in any other file. you could call another file that just allocates global variables (which would be tidier) but really they can be created from anywhere as long as its from before they are called.

      @deckingman said in A couple of questions regarding global variables:

      Within a macro file, parameters that were passed to the macro (typically in the M98 command) can be retrieved using the syntax

      this is different to a global variable and allows a value to be passed to a macro without the need to populate a variable. e.g. G1 X1 passes the value 1 for axis X to the G1 command. I've not tried any yet so can't elaborate further but from your long description, a global variable sounds most appropriate for your use case

      Owns various duet boards and is the main wiki maintainer for the Teamgloomy LPC/STM32 port of RRF. Assume I'm running whatever the latest beta/stable build is

      undefined 1 Reply Last reply 24 Aug 2021, 09:35 Reply Quote 1
      • undefined
        deckingman @jay_s_uk
        last edited by 24 Aug 2021, 09:35

        @jay_s_uk Thanks. I like your idea of using a separate file to declare variables. I'll appreciate that in 6 months time when I need to change something but can't remember where I put it.

        Ian
        https://somei3deas.wordpress.com/
        https://www.youtube.com/@deckingman

        1 Reply Last reply Reply Quote 2
        • undefined
          OwenD
          last edited by OwenD 24 Aug 2021, 09:59

          As has been pointed out, you can declare the globals wherever you like, but of course you must ensure that you do so before you try to use them anywhere.
          I always check if the global has already been created as I don't like seeing the errors if I run M98 P"0:/sys/config.g" for example.
          It also ensures the global is reset in case I changed it in code somewhere.
          In some cases I check for a null value, but in most cases that's probably not necessary.

          if !exists(global.InputStart) || global.InputStart=null
          global InputStart=0
          else
          set global.InputStart=0
          if !exists(global.InputEnd) || global.InputEnd=null
          global InputEnd=1
          else
          set global.InputEnd=1

          With regards to sending parameters using M98, it's pretty straight forward.
          For example you might use it when there is a value you want to use from your slicer.
          Here I pass an "S" and a "D" parameter taken from the slicer

          M98 P"0:/macros/print/doPrimeLine" S[extrusion_multiplier] D[nozzle_diameter] F[filament_diameter] ; does prime line with calculated extrusion amount

          In my macro I use the values passed thus
          This macro also uses local variables which are freed once the macro has run.
          It's a fair bit of overkill to do a prime line, but it was mainly a test bed for various methods

          ; 0:/macros/print/doPrimeLine
          if state.currentTool = -1
          abort "No tool selected"
          var ThisHeater = tools[state.currentTool].heaters[0] ; create local variable
          if {heat.heaters[var.ThisHeater].state != "active"}
          abort "Heater " ^ var.ThisHeater ^ " on " ^ tools[state.currentTool].name ^ " not active"
          if {heat.heaters[var.ThisHeater].active < heat.coldExtrudeTemperature}
          abort "Heater " ^ var.ThisHeater ^ " on " ^ tools[state.currentTool].name ^ " set below min extrude temp"
          if !exists(param.S)
          abort "no ""S"" (extrusion factor) parameter sent to macro in M98"
          if !exists(param.D)
          abort "no ""D"" (nozzle diameter) parameter sent to macro in M98"
          if !exists(param.F)
          abort "no ""F"" (filament diameter) parameter sent to macro in M98"
          M116 ; wait for heaters to settle
          var height = 0.2 ; create a variable then set it depending on slicer commanded position prior to calling this macro
          if move.axes[2].machinePosition <= 0.4
          set var.height = move.axes[2].machinePosition
          else
          set var.height = 0.3
          var SF = 100
          if param.S <=1 ; check if slicer sends percentage of 1 or 100
          set var.SF = param.S ; extrusion multiplier as a percentage of 1
          else
          set var.SF = param.S / 100
          var FD = 1.75 ; set default filament diameter
          set var.FD = param.F ; but over write with slicer setting
          ; set start and end of move in Y direction - X position will be set manually
          var start = {move.axes[1].max -10 } ; extrude line start position
          var end = {move.axes[1].min +10} ; extrude line end position
          var l = var.start - var.end ; calculated line length
          var d = param.D ; nozzle diameter that is passed to macro as paramater
          var amount = ((var.d*var.height*var.l) + (pi*((var.height/2)*(var.height/2))*var.l)) / (pi*((var.FD/2)*(var.FD/2))) * var.SF ; calculate how many mm of filament to extrude - Owen's calculation
          echo "flow rate value " ^ var.SF ^ " with " ^ var.d ^ "mm nozzle, " ^ var.FD ^ "mm filament dia over " ^ var.l ^ "mm length = E" ^ var.amount ^ "mm"
          M83 ; set relative extrusion
          G1 X0 Y{var.start} Z{var.height} F1200 ; move to edge to wipe any oozed filament
          G1 X0 Y{var.end} F600 E{var.amount}; move and extrude
          G1 X{var.d} ; move by one nozle width
          G1 Y{var.start} F600 E{var.amount}; move and extrude
          G10 ; retract
          undefined 1 Reply Last reply 24 Aug 2021, 10:09 Reply Quote 4
          • undefined
            deckingman @OwenD
            last edited by 24 Aug 2021, 10:09

            @owend Thanks. I always appreciate your replies. You have a good way of explaining things in a way that an old retired mechanical engineer can understand. 🙂

            Ian
            https://somei3deas.wordpress.com/
            https://www.youtube.com/@deckingman

            undefined 1 Reply Last reply 24 Aug 2021, 10:15 Reply Quote 0
            • undefined
              OwenD @deckingman
              last edited by 24 Aug 2021, 10:15

              @deckingman said in A couple of questions regarding global variables:

              @owend Thanks. I always appreciate your replies. You have a good way of explaining things in a way that an old retired mechanical engineer can understand. 🙂

              Ah well, I'm a welder by trade, so we're used to telling engineers how it "should have been done" 😂 😂 😂
              Sorry, couldn't help myself

              1 Reply Last reply Reply Quote 2
              • undefined
                deckingman
                last edited by 24 Aug 2021, 13:05

                For the sake of completeness and for anyone stumbling on this thread in the future, and thanks to those who helped, I have created a macro called "declareGlobals". This macro contains:-

                global left=64 ; 64mm from left hand edge
                global rear=366; equal to Y max

                I call this macro from my config.g file with :-

                M98 P"0:/macros/declareGlobals.g"
                

                In my "user macros", I then use commands such as:-

                G1 X{global.left} U{global.left} A{global.left} F12000
                G1 Y{global.rear} V{global.rear} B{global.rear} F12000

                Which all works a treat. So if the position of my nozzle relative to my wiping strip changes (as it is apt to do when I modify things or swap hot ends), then all I have to do is set the variables "left" and "rear" to some other value and all gantries will move to the new position for any of the multiple macros which are affected.

                Thanks again @jay_s_uk & @OwenD

                Ian
                https://somei3deas.wordpress.com/
                https://www.youtube.com/@deckingman

                1 Reply Last reply Reply Quote 3
                • undefined
                  deckingman
                  last edited by 25 Aug 2021, 12:45

                  Just a quick update on this. Having slept on it, I'm not sure if putting the variable declarations into a separate file is quite such a good idea. The reason being that if I make changes to those global variables (i.e edit the macro and save it) I must remember to run that macro again because the changes only get applied when the macro is run and not when it's saved. The same thing applies if the variables are set in config.g but at least I get a prompt and config.g will get run "automatically" again if any changes are made to it, whereas this doesn't happen when changes are made to any other macro.

                  I'll leave it for now and I've put a comment in the macro in big bold letters to remind me to always run it if any changes are made. But I suspect it might come back to bite me at some point in the future.

                  Ian
                  https://somei3deas.wordpress.com/
                  https://www.youtube.com/@deckingman

                  undefined 1 Reply Last reply 25 Aug 2021, 13:47 Reply Quote 0
                  • undefined
                    o_lampe @deckingman
                    last edited by 25 Aug 2021, 13:47

                    @deckingman you could also add a trigger event to the end of the macro which asks you to rerun it or not.

                    undefined 1 Reply Last reply 25 Aug 2021, 13:48 Reply Quote 0
                    • undefined
                      deckingman @o_lampe
                      last edited by deckingman 25 Aug 2021, 13:48

                      @o_lampe said in A couple of questions regarding global variables:

                      @deckingman you could also add a trigger event to the end of the macro which asks you to rerun it or not.

                      Now that's a brilliant idea!. How would I go about adding such a trigger?

                      Ian
                      https://somei3deas.wordpress.com/
                      https://www.youtube.com/@deckingman

                      undefined 1 Reply Last reply 25 Aug 2021, 13:55 Reply Quote 0
                      • undefined
                        o_lampe @deckingman
                        last edited by 25 Aug 2021, 13:55

                        @deckingman there's an option to add external trigger or use the touchpad of a PanelDue

                        undefined 1 Reply Last reply 25 Aug 2021, 13:57 Reply Quote 0
                        • undefined
                          jay_s_uk @o_lampe
                          last edited by 25 Aug 2021, 13:57

                          @o_lampe i suppose the only issue there is remembering to run the macro once you've edited it.
                          You'd also have to include the checks that @OwenD mentioned so you don't get errors

                          Owns various duet boards and is the main wiki maintainer for the Teamgloomy LPC/STM32 port of RRF. Assume I'm running whatever the latest beta/stable build is

                          undefined 1 Reply Last reply 25 Aug 2021, 14:01 Reply Quote 0
                          • undefined
                            o_lampe @jay_s_uk
                            last edited by 25 Aug 2021, 14:01

                            @jay_s_uk
                            I'm struggling to find the right command which pops up a question and asks you to confirm or cancel.

                            undefined 1 Reply Last reply 25 Aug 2021, 14:01 Reply Quote 0
                            • undefined
                              jay_s_uk @o_lampe
                              last edited by 25 Aug 2021, 14:01

                              @o_lampe M291

                              Owns various duet boards and is the main wiki maintainer for the Teamgloomy LPC/STM32 port of RRF. Assume I'm running whatever the latest beta/stable build is

                              1 Reply Last reply Reply Quote 2
                              • undefined
                                OwenD
                                last edited by OwenD 25 Aug 2021, 20:57

                                @deckingman
                                I'm going to have a bit of a rant, but it's not aimed at you specifically, it's more an observation given the embryonic state of people using conditional code on printers.

                                I still feel the best way is have a section in config.g where you put all your global variables.
                                I also feel checking if the global exists is important not just from the point of view of avoiding console errors.
                                It is equally important to ensure that any temporary alteration to that global is returned to the default on a restart.
                                Putting the code in config.g handles that most completely and easily.
                                As you've deducted, using a macro called from config only works if you then have a mechanism to ensure changes apply.
                                I guess you could check the file hash value from daemon.g, but why?
                                Some people feel doing such checks is "too much work", but the fact is that if you want to start using code, then you'd better start getting used to ensuring YOUR code handles unexpected events.
                                If YOUR code will except something to be in a certain state, then it's YOUR responsibility to ensure that is the case before your code executes.

                                I wonder if the guy that programmed the plc in your microwave said "meh - too much work to check the doors closed before starting... we know they're going to close it right?"

                                undefined undefined 2 Replies Last reply 25 Aug 2021, 21:31 Reply Quote 1
                                • undefined
                                  deckingman @OwenD
                                  last edited by 25 Aug 2021, 21:31

                                  @owend Fair comments I suppose. It's the mechanical engineer mentality thing vs software engineer thing again. If I adjust something mechanically, I tend to accept that the adjusting screw that I know I fitted earlier exists. I don't say to myself, "every time I want to turn this adjusting screw, I must check that I fitted this adjusting screw and if I didn't, then fit one and turn it, else just turn it".

                                  Ian
                                  https://somei3deas.wordpress.com/
                                  https://www.youtube.com/@deckingman

                                  fcwiltundefined 1 Reply Last reply 25 Aug 2021, 22:17 Reply Quote 1
                                  • fcwiltundefined
                                    fcwilt @deckingman
                                    last edited by 25 Aug 2021, 22:17

                                    @deckingman

                                    To give you an opinion from a retired programmer:

                                    • if we had a command to remove all existing global vars I would create them all in a file which I called from config.g
                                    • since we don't I create them all in config.g
                                    • I do not check for their existence when I use them - I verify my code works and leave it at that

                                    Frederick

                                    Printers: a small Utilmaker style, a small CoreXY and a E3D MS/TC setup. Various hotends. Using Duet 3 hardware running 3.4.6

                                    1 Reply Last reply Reply Quote 1
                                    • undefined
                                      o_lampe @OwenD
                                      last edited by 26 Aug 2021, 06:21

                                      @owend
                                      Some macros can get several pages long, so I agree it's best practice to check for existing variable names. Especially when more than one person develops or changes this macro over time.
                                      Additional to your post, I'd propose NOT to use standard variable names (X,Y, I,J etc) but 'speaking' names, but that's common sense I guess.

                                      1 Reply Last reply Reply Quote 0
                                      • undefined
                                        deckingman
                                        last edited by 26 Aug 2021, 06:52

                                        Playing Devils advocate here, but going back to my original use case, the reason I wanted to use global variables in a number of macros, was so that I could set the values in one place and any macro that needed to use those values would do so. The alternative (which I used before) is to use a fixed value which involves editing numerous files if that value needed to be changed. This could mean that "fat finger syndrome" might mean that one or more macros could use the wrong value. If I check that the global variable exists and that it is set to a certain value at the start of every macro, then I'm back to editing every file which uses those global variables every time I make a change. Which negates the advantages of using global variables instead of fixed values does it not?

                                        Ian
                                        https://somei3deas.wordpress.com/
                                        https://www.youtube.com/@deckingman

                                        undefined 1 Reply Last reply 26 Aug 2021, 08:51 Reply Quote 0
                                        • undefined
                                          OwenD @deckingman
                                          last edited by 26 Aug 2021, 08:51

                                          @deckingman
                                          I think you misunderstand my reasoning.
                                          The only place I definitely check for the existence of the global is in config.g
                                          If you don't do so and run say M98 P"config.g" then you'll get error messages saying the global already exists.
                                          Maybe not a big deal, but apart from the aesthetic annoyance it also also means you can't reset your globals to "default" without a full restart.

                                          When you run M98 P"config.g" and it gets to your global creation directive it does not process the value if it already exists. It (correctly) gives an error and moves on.
                                          So any changes to your values require a full restart of they won't apply!

                                          So... if it doesn't exist, I create it and apply a value.
                                          If it DOES exist I reset the value because I can be pretty sure it's been changed in code somewhere.

                                          With the calls to allow globals to be freed, it will become more important to check for existence in all macros.

                                          Personally I think there's less chance of drama the way it is now.
                                          If you don't want a persistent variable use a var instead of a global.
                                          That said there are probably cases where it might be handy to free individual globals, so I'm not fussed either way there.

                                          undefined 1 Reply Last reply 26 Aug 2021, 12:39 Reply Quote 0
                                          4 out of 22
                                          • First post
                                            4/22
                                            Last post
                                          Unless otherwise noted, all forum content is licensed under CC-BY-SA