Search code examples
c#coordinatesrepeatg-codecnc

How to restart motors by accepting current position as first coordinate


I have a C# code which generates some x and y coordinates and i am sending these coordinates as g-code to the arduino which is programmed for 2-axis cnc code.

I am listing all the coordinates in the listbox and after 750 ms, i am sending each coordinates to the arduino.

What is my problem is that when all coordinates are sent to the arduino, i want to re-send all the coordinates again and again until sending stop command. But when coordinates are re-sent to the arduino, motors move to the position of the first coordinates as expected. However, what i want is that motors take the current coordinates as the first coordinate in the listbox instead of moving back to the first starting point.

Please help me how to readjust the code.

I am adding the current code to the below.

        private void btnSendData_Click(object sender, EventArgs e)
        {
            
            if (serialPort1.IsOpen && listBox1.Items.Count > 1)
            {
                currentIndex = 0; // Reset the index to start from the first item
                timer1.Interval = 750;  // in mili-second
                timer1.Start();

            }
            else
            {
                MessageBox.Show("Port Closed or Not Enough Data");
            }
        }

        private void SendDataToArduino()
        {
            if (currentIndex < listBox1.Items.Count)
            {
                string command = listBox1.Items[currentIndex].ToString(); // Get the item as a string
                command = command.Replace(": ", ""); // Remove the colon
                command = command.Replace(",", ""); // Remove comma if needed

                serialPort1.WriteLine(command);

                textBox3.Text = command;

                currentIndex++; // Move to the next item

            }
            else
            {
                // Tüm veriler gönderildi, işlemi yeniden başlat
                currentIndex = 0;
            }

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            SendDataToArduino();
        }

I have tried to add each x value to the first coordinates in the each loop. But this is ridiculous.


Solution

  • Based on what we discussed in the comments, I created a small Winforms project to emulate what you are trying to achieve.

    First of all, I added several controls:

    1. listBox2: Saves the positions of the pattern that is to be repeated by the motor
    2. btnCalculatePattern: When clicked, calculates the repeating pattern from the coordinates that you set in the listBox1
    3. btnAvatar: this is just to display the movements of the motor in the screen by moving the button around.

    I also enabled the Console window in order to see the commands that are being sent to the motor.

    First, before sending the commands to the motor, calculate the pattern by clicking on "Calculate Pattern". After that, click on "Send Data" and this will activate the timer (like in your original code) and start sending the data:

    enter image description here

    You can find the whole solution in this GitHub repository, or alternative download it as a zip here. Let me know if you have any issues opening it.

    I didn't know in what format you are sending the data to the motor, so I just used strings with the format "X.Y", separated by a point '.', so you'll probably need to adjust this part with the string format you are using.

    This is the code of Form1 with the new changes. I had to move the command variable outside of SendDataToArduino, made several changes to this method and added other methods btnCalculatePattern_Click and UpdateCoordinates:

    public partial class Form1 : Form
    {
        bool serialPortIsOpen = true;
    
        int currentIndex = 0;
    
        string command = "";
    
        public Form1()
        {
            InitializeComponent();
    
            //Move the visual avatar to the starting position
            MoveAvatar(listBox1.Items[0].ToString());
        }
    
        private void MoveAvatar(string point)
        {
            var currentCoordinates = point.Split('.');
            var current_x = Convert.ToInt32(currentCoordinates[0]);
            var current_y = Convert.ToInt32(currentCoordinates[1]);
            btnAvatar.Location = new System.Drawing.Point(current_x, current_y);
        }
    
        private void btnSendData_Click(object sender, EventArgs e)
        {
            if (serialPortIsOpen && listBox1.Items.Count > 1)
            {
                currentIndex = 0; // Reset the index to start from the first item
                timer1.Interval = 750;  // in mili-second
                timer1.Start();
    
            }
            else
            {
                MessageBox.Show("Port Closed or Not Enough Data");
            }
        }
    
        private void btnCalculatePattern_Click(object sender, EventArgs e)
        {
            // The first item of the pattern is always (0,0)
            listBox2.Items.Add($"0.0");
    
            for (int i = 0; i < listBox1.Items.Count - 1; i++)
            {
                var currentCoordinates = listBox1.Items[i].ToString().Split('.');
                var current_x = Convert.ToInt32(currentCoordinates[0]);
                var current_y = Convert.ToInt32(currentCoordinates[1]);
    
                var nextCoordinates = listBox1.Items[i + 1].ToString().Split('.');
                var next_x = Convert.ToInt32(nextCoordinates[0]);
                var next_y = Convert.ToInt32(nextCoordinates[1]);
    
                var x = next_x - current_x;
                var y = next_y - current_y;
    
                listBox2.Items.Add($"{x}.{y}");
            }
    
            btnCalculatePattern.Enabled = false;
            btnSendData.Enabled = true;
        }
        private void UpdateCoordinates(string startingPoint)
        {
            // The startingPoint is the ending point of the last iteration
            listBox1.Items[0] = startingPoint;
    
            var startingPointSplit = startingPoint.Split(".");
            var startingPoint_x = Convert.ToInt32(startingPointSplit[0]);
            var startingPoint_y = Convert.ToInt32(startingPointSplit[1]);
    
            // Calculate the rest of the coordinates for this iteration from
            // the starting point and the pattern
    
            var x = startingPoint_x;
            var y = startingPoint_y;
    
            for (int i = 0; i < listBox1.Items.Count; i++)
            {
                var pattern = listBox2.Items[i].ToString().Split('.');
                var pattern_x = Convert.ToInt32(pattern[0]);
                var pattern_y = Convert.ToInt32(pattern[1]);
    
                x += pattern_x;
                y += pattern_y;
    
                listBox1.Items[i] = $"{x}.{y}";
            }
        }
    
        private void SendDataToArduino()
        {
            // Send commands with the current state of Coordinates
    
            if (currentIndex < listBox1.Items.Count)
            {
                command = listBox1.Items[currentIndex].ToString();
                command = command.Replace(": ", ""); // Remove the colon
                command = command.Replace(",", ""); // Remove comma if needed
    
                //We move the visual avatar and print the coordinates to the console
                // to simulate the motor receiving the commands 
                // serialPort1.WriteLine(command);
                Console.WriteLine(command);
                MoveAvatar(command);
    
                textBox3.Text = command;
    
                currentIndex++; // Move to the next item
    
            }
            else
            {
                // Tüm veriler gönderildi, işlemi yeniden başlat
                currentIndex = 0;
    
                // Update the Coordinates in the listBox with the Pattern information
                // passing the last point of the current iteration
                // as the starting point of the next iteration.
                UpdateCoordinates(command);
            }
        }
    
        private void timer1_Tick(object sender, EventArgs e)
        {
            SendDataToArduino();
        }
    }