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

    M28 doesn't allow tabs to be written to file.

    Scheduled Pinned Locked Moved Unsolved
    Gcode meta commands
    3
    11
    405
    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.
    • OwenDundefined
      OwenD
      last edited by

      Now that we have conditional G code, it looks like some revision to M28 might be required.
      It seems that the default behavior is the trim leading spaces (and probably trailing) from the code as it writes it to the new file.
      That would have been logical in the past, but....
      This makes dynamically creating a job file that uses condition gcode impossible.
      I tried using /t and #9 as an escape character to no avail.
      Whilst the use cases for this might be low, I'll expand on what I was trying to achieve (a bit long winded).

      During upgrading to RRF3.3b3, I noticed some really erratic temperature readings.
      I couldn't find a loose connection, so I ran a new PID tune and the problem seemed to go away.
      That bugged me as there were no notes about changes to the heater routines, so I decided to do a macro that would run very fast random moves so I could watch the graph to see if the shaking gave any erratic heater values.
      I thought I'd use the status of my LED strip as a way to cancel out of the loop, but found that when run as a macro, it didn't work (possibly too many queued moves).
      I found if I ran it as a print job, I could indeed cancel out using my LED status.

      Then I decided "why not let the macro create the job file?"
      It was then I found the "bug" in M28

      Here's my macro

      ;random-moves.g
      ; macro to do high speed moves to random positions.  a small amount of filament will be extruded to sop it burning
      ; note if run as a macro, it can't be interupted, so a print job is created.
      if job.file.fileName!=null
      	echo "A print is running - macro cancelled"
      	M99
      if !exists(global.minX)
      	global minX = 80                        ; minimum X position
      if !exists(global.maxX)
      	global maxX = 120                       ; maximum X position
      if !exists(global.minY)
      	global minY = 80                        ; minimum Y position
      if !exists(global.maxY)
      	global maxY = 120                       ; maximum Y position
      if !exists(global.minSpeed)
      	global minSpeed = 9000                  ; minimum travel speed
      if !exists(global.maxSpeed)
      	global maxSpeed = 24000                 ; max travel speed this will be scaled based on the part fan speed, so it can be controlled/reduced during the test
      if !exists(global.outputIO)
      	global outputIO = 5                     ; tied to an output (LED) so we cabn interupt the "print" without a reset
      M566 X600.00 Y600.00 Z120.00 E6000.00       ; set maximum instantaneous speed changes (mm/min)
      M203 X36000.00 Y36000.00 Z900.00 E24000.00  ; set maximum speeds (mm/min)
      M201 X6000.00 Y6000.00 Z800.00 E6000.00     ; set accelerations (mm/s^2)
      M83 ; set relative extruder moves
      if fans[0].actualValue = 0
      	M106 P0 S1 ; make sure fan is on
      if !move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed
      	G28
      	if result != 0
      		abort "Homing failed"
      
      G1 X{global.minX + ((global.maxX-global.minX)/2)} Y{global.minY + ((global.maxY-global.minY)/2)} Z50 F3000 ; move to the centre of the range and 50mm above bed
      T0 ; select tool
      echo "waiting for heaters"
      G10 T0 S240 R180 ; set extruder temp
      M116 ; wait for temps
      M291 P"Ready to start?" R"Ready" S3
      M28 "0:/gcodes/random-moves-test.g"
      while state.gpOut[{global.outputIO}].pwm = 1
      	G1 X{max(random(global.maxX),global.minX)} Y{max(random(global.maxY),global.minY)} E0.05 F{max(random(global.maxSpeed),global.minSpeed)*fans[0].actualValue};
      	if result !=0
      		abort "Could not execute move"
      	M400
      	G4 P1
      echo "LED is off - moves cancelled"
      M98 P"0:/sys/set_max_speeds.g" ; reset speeds
      M29
      M32 "0:/gcodes/random-moves-test.g"
      M99 ; probably not needed
      
      

      and here is the output.

      while state.gpOut[{global.outputIO}].pwm = 1
      G1 X{max(random(global.maxX),global.minX)} Y{max(random(global.maxY),global.minY)} E0.05 F{max(random(global.maxSpeed),global.minSpeed)*fans[0].actualValue}
      if result !=0
      abort "Could not execute move"
      M400
      G4 P10
      echo "LED is off - moves cancelled"
      M98 P"0:/sys/set_max_speeds.g" 
      
      dc42undefined DonStaufferundefined 2 Replies Last reply Reply Quote 1
      • dc42undefined
        dc42 administrators @OwenD
        last edited by

        @owend, thanks for reporting this. I have added it to my list of things to look at.

        Duet WiFi hardware designer and firmware engineer
        Please do not ask me for Duet support via PM or email, use the forum
        http://www.escher3d.com, https://miscsolutions.wordpress.com

        1 Reply Last reply Reply Quote 0
        • DonStaufferundefined
          DonStauffer @OwenD
          last edited by

          @owend Have you tried M560? Just make sure to include the P parameter or I heard it can nuke your config.g! But the reason I suggest it is I've found that M560 will write comments, where M28 won't. So maybe it treats tabs differently as well. I don't know.

          Where with M28 you'd do this:

          M28 "<filespec>"
          . . .
          M29

          With M560 you do this:

          M560 P"<filespec>"
          . . .
          <!-- EoF -->

          OwenDundefined 1 Reply Last reply Reply Quote 0
          • OwenDundefined
            OwenD @DonStauffer
            last edited by

            @donstauffer
            My Understanding is that M559/M560 upload previously written files whereas M28 actually creates the file.
            Therefore unless I create the file externally, it doesn't help as the "problem" , small though it is, is that M28 won't allow tab characters to be written to the file.

            DonStaufferundefined 3 Replies Last reply Reply Quote 0
            • DonStaufferundefined
              DonStauffer @OwenD
              last edited by DonStauffer

              @owend I routinely create files with M560. In fact, if I want to create a macro which creates a macro, I nest them:

              Create a macro named "Maker", containing:

              M560 P"/macros/Outer"

              M28 "/macros/Inner"
              M98 P"/macros/Another"
              M29

              <!-- EoF -->

              Now, if you run "Maker", it creates a file "Outer", which contains:

              M28 "/macros/Inner"
              M98 P"/macros/Another"
              M29

              And then, if your run "Outer", it creates a file "Inner", which contains:

              M98 P"/macros/Another"

              Then, if you run "Inner", it will make a call to macro "Another".

              1 Reply Last reply Reply Quote 0
              • DonStaufferundefined
                DonStauffer @OwenD
                last edited by

                @owend The forum is doing something strange - it removed the asterisks from that termination (EoF) string, so if you copy and paste that it won't work. The string actually should have a pair of asterisks immediately preceding and after "EoF".

                1 Reply Last reply Reply Quote 0
                • DonStaufferundefined
                  DonStauffer @OwenD
                  last edited by

                  @owend I just tested the example I gave, with tabs. Both M28 and M560 preserved the tabs in the files they wrote. I put a pair of tabs directly after "M28" and "M98", and they did appear in Outer, and the M98 pair of tabs did appear in Inner, which was written by M28.

                  OwenDundefined 1 Reply Last reply Reply Quote 0
                  • OwenDundefined
                    OwenD @DonStauffer
                    last edited by

                    @donstauffer
                    I'm not seeing where your examples are creating macros with indented conditional code like the examples I posted.

                    DonStaufferundefined 3 Replies Last reply Reply Quote 0
                    • DonStaufferundefined
                      DonStauffer @OwenD
                      last edited by

                      @owend I tried it with an "if" and an indented "set", and M560 handled it but M28 didn't. Possibly M28 eats the tabs but only at the beginning or end of a line.

                      1 Reply Last reply Reply Quote 0
                      • DonStaufferundefined
                        DonStauffer @OwenD
                        last edited by DonStauffer

                        @owend Indent.jpg

                        There is an inconsequential error in this example. it should be "set var.X = 5", but since it will never execute it doesn't matter.

                        1 Reply Last reply Reply Quote 0
                        • DonStaufferundefined
                          DonStauffer @OwenD
                          last edited by DonStauffer

                          @owend The limitation on M28 actually presents a problem on a project I'm currently working on, because the project has macros which do nested writes, which can only be achieved using both M560 and M28, and the nested write does include a conditional. I haven't thought of how to deal with that yet.

                          I'm wondering if there's a character meta commands consider to be indents but M28 doesn't consider space to be removed. A no-break space (C2 A0) didn't work. Neither did a character code 255.

                          1 Reply Last reply Reply Quote 0
                          • First post
                            Last post
                          Unless otherwise noted, all forum content is licensed under CC-BY-SA