Sending a file with G-Code to the controller

Sending a file with G-Code to the controller

Postby jjturbo » 07 Sep 2016, 07:03

Hello together,

how can i send a file with G-Code to the controller and start it?


With best regards,
Oliver
jjturbo
 
Posts: 2
Joined: 07 Sep 2016, 07:00
Controller: Mk3

Re: Sending a file with G-Code to the controller

Postby Support » 08 Sep 2016, 13:45

G-code file is not directly sent to controller. Software generates motion commands based on g-code that are sent to controller which are then interpreted by controller itself.
Support
 
Posts: 2571
Joined: 07 Apr 2014, 17:39
Controller: Many controllers

Re: Sending a file with G-Code to the controller

Postby jjturbo » 19 Sep 2016, 08:13

But it is possible to send more than 1 motion command? For example i want to send 3 motion commands and after sending a Start Signal it shall start each motion automatically.
jjturbo
 
Posts: 2
Joined: 07 Sep 2016, 07:00
Controller: Mk3

Re: Sending a file with G-Code to the controller

Postby NXTwoThou » 22 Sep 2016, 21:24

I haven't hit that part of my project yet, but I'm in the same boat.

I'm building a proof of concept machine that will be downloading project files, auto loading parts, running some g-code, then unloading the parts and figuring out the next project to do. My software needs the api for a few motions determined by reading a bunch of sensors to handle loading, sending notices about how many blanks are left, when projects have started and stopped, etc. When it comes to the actual part generation, I just want to load the g-code I've been writing and get notified of current line number and completion. Then my software can get back to manual moves.

I'm mostly replying to this thread so you know someone else is probably going to be asking the same question.
NXTwoThou
 
Posts: 7
Joined: 22 Sep 2016, 21:18
Controller: None

Re: Sending a file with G-Code to the controller

Postby NXTwoThou » 26 Sep 2016, 23:36

I just started playing with this today. After I created some code to handle single axis movement(since it apparently disappeared in later versions of the API from some of the examples). I started work on an insanely rough G-Code runner for my own project. It's just an hour or two of playing around but thought I'd share the concept in case someone else wanted to run with it properly.

I took the api example and have just been hacking extra bits in.

Code: Select all
private class RunGCode
        {
            public bool bAlwaysFlushCommands = false; // if true, buffer must be completely empty to send next command
            private PlanetCNC.API.CNC cnc = null;
            private int GCommandCurrentLine = 0;
            private ArrayList GCommands = new ArrayList();
            private System.Timers.Timer GCommandTimer = new System.Timers.Timer();
            private double CurrentSpeed;
            private bool bInTimerEvent = false;
            private bool bNeedsFlush = false;
            private bool bNewPositionIsSafe = false;
            private Coord NewPosition = null;
            #region Event Handlers
            public class UpdateEventArgs : EventArgs
            {
                public int CommandCurrent { get; set; }
                public int CommandCount { get; set; }
                public string CommandLine { get; set; }
                public UpdateEventArgs(int Current, int Count, string Line)
                {
                    CommandCurrent = Current;
                    CommandCount = Count;
                    CommandLine = Line;
                }
            }
            public delegate void OnUpdateHandler(object sender, UpdateEventArgs e);
            public event OnUpdateHandler Updated;
            protected virtual void OnUpdated(UpdateEventArgs e)
            {
                if (Updated != null)
                    Updated(this, e);
            }

            public delegate void OnCompleteHandler(object sender, EventArgs e);
            public event OnCompleteHandler Completed;
            protected virtual void OnCompleted(EventArgs e)
            {
                if (Completed != null)
                    Completed(this, e);
            }

            public delegate void OnCancelHandler(object sender, EventArgs e);
            public event OnCancelHandler Canceled;
            protected virtual void OnCanceled(EventArgs e)
            {
                if (Canceled != null)
                    Canceled(this, e);
            }
            #endregion

            public RunGCode(PlanetCNC.API.CNC cnc)
            {
                this.cnc = cnc;
                Reset();
            }
            public RunGCode(PlanetCNC.API.CNC cnc,bool bAlwaysFlushCommands)
            {               
                this.cnc = cnc;
                this.bAlwaysFlushCommands = bAlwaysFlushCommands;
                Reset();
            }
            public void LoadGCode(string GCode)
            {
                Reset();
                string line;
                StringReader sr = new StringReader(GCode);
                while ((line = sr.ReadLine()) != null)
                {
                    line = line.Trim();
                    if (line.Length > 0 && line[0] != '%' && line[0] != '(')
                        GCommands.Add(line);
                }
                sr.Close();               
            }

            public void Start()
            {
                if (GCommandTimer == null)
                {
                    if(GCommands.Count==0)
                    {
                        throw new Exception("No commands to execute, please use LoadGCode first");
                    }
                    GCommandTimer = new System.Timers.Timer(20);
                    GCommandTimer.Elapsed += GCommandTimerTick;
                    GCommandTimer.Start();
                }
            }
            private void Reset()
            {
                if (GCommandTimer != null)
                {
                    GCommandTimer.Stop();
                    GCommandTimer = null;
                    bInTimerEvent = false;
                }
                if (cnc != null)
                    CurrentSpeed = cnc.FeedSpeed;
                GCommands = new ArrayList();
                GCommandCurrentLine = 0;
                bInTimerEvent = false;
                bNeedsFlush = false;
                bNewPositionIsSafe = false;
                NewPosition = null;
            }

           
            private void GCommandTimerTick(object sender, System.Timers.ElapsedEventArgs e)
            {
                if (bInTimerEvent)
                    return;
                bInTimerEvent = true;
                if (cnc != null && bNeedsFlush)
                {
                    if (cnc.BufferFree < cnc.BufferSize)
                    {
                        bInTimerEvent = false;
                        return;
                    }
                    else
                    {
                        bNewPositionIsSafe = false;
                        bNeedsFlush = false;
                    }
                }
                if (GCommandCurrentLine >= GCommands.Count)
                {
                    GCommandTimer.Stop();
                    GCommandTimer = null;
                    bInTimerEvent = false;
                    OnCompleted(null);
                    return;
                }
                if ((cnc != null) && (cnc.BufferFree > 10))
                {
                    string line = (string)GCommands[GCommandCurrentLine];
                    bool bNeedMove = false;
                    string[] commands = line.Split(new char[] { ' ' });
                    for (int i = 0; i < commands.Length; i++)
                    {
                        if (commands[i].Length > 0)
                        {
                            switch (commands[i][0])
                            {
                                case ')':
                                    break;
                                case '(':
                                    while (i < commands.Length && commands[i][0] != ')')
                                        i++;
                                    break;
                                case 'G':
                                    switch (commands[i].Substring(1))
                                    {
                                        case "00":
                                            {
                                                CurrentSpeed = cnc.TraverseSpeed;
                                                bNeedsFlush = true;
                                            }
                                            break;
                                        case "01":
                                            {
                                                CurrentSpeed = cnc.FeedSpeed;
                                                bNeedsFlush = true;
                                            }
                                            break;
                                        case "28":
                                            Coord c = new Coord();
                                            c.X = 0;
                                            c.Y = 0;
                                            c.W = 0;
                                            c.Z = 0;
                                            c.Units = PlanetCNC.API.UnitsEnum.Millimeters;
                                            cnc.Home(c);                                           
                                            bNeedsFlush = true;
                                            break;
                                    }
                                    break;
                                case 'X':
                                case 'Y':
                                case 'Z':
                                case 'W':
                                    if (!bNewPositionIsSafe)
                                    {
                                        bNewPositionIsSafe = true;
                                        NewPosition = new Coord();
                                        NewPosition.CopyFrom(cnc.Position);
                                    }
                                    string pos = commands[i].Substring(1);
                                    if (pos.Length > 0)
                                    {
                                        double val = double.Parse(pos);
                                        if (commands[i][0] == 'X' && NewPosition.X != val)
                                        {
                                            NewPosition.X = val;
                                            bNeedMove = true;
                                        }
                                        else if (commands[i][0] == 'Y' && NewPosition.Y != val)
                                        {
                                            NewPosition.Y = val;
                                            bNeedMove = true;
                                        }
                                        else if (commands[i][0] == 'Z' && NewPosition.Z != val)
                                        {
                                            NewPosition.Z = val;
                                            bNeedMove = true;
                                        }
                                        else if (commands[i][0] == 'W' && NewPosition.W != val)
                                        {
                                            NewPosition.W = val;
                                            bNeedMove = true;
                                        }
                                    }
                                    break;
                            }
                        }
                    }
                    if (bNeedMove)
                        cnc.SendMovePos(cnc.Position, NewPosition, CurrentSpeed);
                    OnUpdated(new UpdateEventArgs(GCommandCurrentLine, GCommands.Count, line));
                    if (bAlwaysFlushCommands)
                        bNeedsFlush = true;
                    GCommandCurrentLine++;
                    if (GCommandCurrentLine >= GCommands.Count)
                        bNeedsFlush = true;
                }
                bInTimerEvent = false;
            }

            public void Stop()
            {
                GCommandTimer.Stop();
                GCommandTimer = null;
                OnCanceled(null);
            }
            public void ClearCompleteHandler()
            {
                foreach (Delegate d in Completed.GetInvocationList())
                {
                    Completed -= (OnCompleteHandler)d;
                }
            }
            public void ClearUpdateHandler()
            {
                foreach (Delegate d in Updated.GetInvocationList())
                {
                    Updated -= (OnUpdateHandler)d;
                }
            }
        }



Basically, this class allows you to load a string that contains a very limited subset of G codes(I'm only caring about the commands I've been using in my tests) that have to be formatted a certain way, parses it, and fills the cnc api command buffer when started. It then fires off events after lines are added to the command buffer, when everything completes, and if someone uses the stop command. It has a bool that forces it to wait for the buffer to be completely empty before sending the next command if you want more accurate updates.

Here's an example that just homes the pile of junk sitting on my desk and moves it around a few times at different speeds. It uses the complete event to fire off another sequence of movements.

Code: Select all
private RunGCode rG = null;
        private void b_Test_Click(object sender, EventArgs e)
        {
            if (cnc == null)
                btnInit_Click(null, null);
            string GCode =
                "G28\r\n" +
                "G00 Y190 X20\r\n" +
                "Y0 X0\r\n"+
                "Y190 X20\r\n" +
                "Y0 X0\r\n" +
                "G01 Y10 X10\r\n" +
                "Y0 X0\r\n";
            if (rG == null)
                rG = new RunGCode(cnc);
            rG.LoadGCode(GCode);
            rG.Completed += RUnload_Completed;
            rG.Updated += RG_Updated;
            rG.Start();
        }

        private void RG_Updated(object sender, RunGCode.UpdateEventArgs e)
        {
            txtLog.Text += e.CommandCurrent + "/" + e.CommandCount + " " + e.CommandLine + "\r\n";
        }

        private void RUnload_Completed(object sender, EventArgs e)
        {
            rG.ClearCompleteHandler();
            rG.ClearUpdateHandler();
            string GCode =
                "G00\r\n" +
                "Y190 X20\r\n" +
                "Y0 X0\r\n"+
                "Y190 X20\r\n" +
                "Y0 X0\r\n" +
                "G28\r\n";               
            if (rG == null)
                rG = new RunGCode(cnc);
            rG.bAlwaysFlushCommands = true;
            rG.LoadGCode(GCode);
            rG.Completed += R2_Completed;
            rG.Updated += RG_Updated;
            rG.Start();
        }
        private void R2_Completed(object sender, EventArgs e)
        {
            rG.ClearCompleteHandler();
            rG.ClearUpdateHandler();
            MessageBox.Show("Really done!");
        }


It's ugly, but it works for me and didn't take much time to throw together as an example. I'm hoping someone might take it and run with it into creating something full featured on what I think several people have been asking for.
NXTwoThou
 
Posts: 7
Joined: 22 Sep 2016, 21:18
Controller: None

Re: Sending a file with G-Code to the controller

Postby NXTwoThou » 27 Sep 2016, 14:31

Right now I'm in that "ah, crap" phase where I run my G Code through the regular software and it takes about 1 hour, 18 minutes to run and sounds great. When I run the same thing through my code it takes 1 hour, 22 minutes and you can really hear the accel/deccel that the regular software is optimizing.

This is one of those reasons where those of us playing with the API really want a "run this chunk of G code, let me know when it's finished so I can go do my next thing". You've already done all that work in building an optimizer that works great, we just need to use the API to OEM brand the final product, dynamically load programs, get results from other hardware, send out notifications based on status, and make high level decisions(some with user input).
NXTwoThou
 
Posts: 7
Joined: 22 Sep 2016, 21:18
Controller: None

Re: Sending a file with G-Code to the controller

Postby Support » 28 Sep 2016, 12:04

You could use "SendMoveEx" function, which would settle the accelerations at the beginning and deceleration ad the end.

This would not optimise your situation but it would improve current state.
Support
 
Posts: 2571
Joined: 07 Apr 2014, 17:39
Controller: Many controllers

Re: Sending a file with G-Code to the controller

Postby NXTwoThou » 28 Sep 2016, 13:10

Thanks, but it's the logic behind how I should change the accel/deccel that I'm trying to work out(that someone infinitely more experienced with this has already worked out)
NXTwoThou
 
Posts: 7
Joined: 22 Sep 2016, 21:18
Controller: None


Return to API



Who is online

Users browsing this forum: No registered users and 1 guest