You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调整C#代码让CNC电机以当前位置为起点重复发送G代码

解决方案

你的问题核心是循环时重置索引到0,导致电机回到初始绝对坐标位置。下面提供两种针对性修改方案:


方案一:跳过初始点循环路径(保持绝对坐标模式)

如果你的列表第一个项是初始位置,后续是运动路径,这个方案会在第一次走完所有点后,循环执行从第二个点到最后一个点的路径,避免回到初始位置。

修改步骤:

  1. 添加类级别的布尔变量,标记是否是第一次循环:
private bool isFirstLoop = true;
private int currentIndex = 0; // 确保这个变量已在类中定义
  1. 修改btnSendData_Click方法,重置循环标记:
private void btnSendData_Click(object sender, EventArgs e)
{
    if (serialPort1.IsOpen && listBox1.Items.Count > 1)
    {
        currentIndex = 0;
        isFirstLoop = true; // 重置首次循环标记
        timer1.Interval = 750;
        timer1.Start();
    }
    else
    {
        MessageBox.Show("端口未打开或数据不足");
    }
}
  1. 修改SendDataToArduino方法,调整循环逻辑:
private void SendDataToArduino()
{
    if (currentIndex < listBox1.Items.Count)
    {
        string command = listBox1.Items[currentIndex].ToString();
        command = command.Replace(": ", "");
        command = command.Replace(",", "");

        serialPort1.WriteLine(command);
        textBox3.Text = command;

        currentIndex++;
    }
    else
    {
        // 首次循环完成后,后续从第二个点开始循环
        if (isFirstLoop)
        {
            isFirstLoop = false;
            currentIndex = 1;
        }
        else
        {
            currentIndex = 1;
        }
    }
}

方案二:转为相对坐标模式(连续循环运动)

如果希望循环时电机从当前位置平滑衔接路径(而非跳转到某个绝对坐标),可以将绝对坐标转为相对移动指令,这样循环时自然保持连续运动。

修改步骤:

  1. 添加类级别的变量记录当前位置和运行状态:
private int currentIndex = 0;
private double currentX = 0;
private double currentY = 0;
private bool isFirstRun = true;
  1. 修改btnSendData_Click方法,重置状态变量:
private void btnSendData_Click(object sender, EventArgs e)
{
    if (serialPort1.IsOpen && listBox1.Items.Count > 1)
    {
        currentIndex = 0;
        currentX = 0;
        currentY = 0;
        isFirstRun = true;
        timer1.Interval = 750;
        timer1.Start();
    }
    else
    {
        MessageBox.Show("端口未打开或数据不足");
    }
}
  1. 修改SendDataToArduino方法,解析坐标并生成相对移动指令:
private void SendDataToArduino()
{
    if (currentIndex < listBox1.Items.Count)
    {
        string item = listBox1.Items[currentIndex].ToString();
        item = item.Replace(": ", "").Replace(",", "");
        
        // 解析目标X、Y坐标
        double targetX = 0, targetY = 0;
        // 提取X值
        int xPos = item.IndexOf('X');
        if (xPos != -1)
        {
            int xEnd = item.IndexOfAny(new char[] { 'Y', 'G', 'M' }, xPos + 1);
            xEnd = xEnd == -1 ? item.Length : xEnd;
            double.TryParse(item.Substring(xPos + 1, xEnd - xPos - 1), out targetX);
        }
        // 提取Y值
        int yPos = item.IndexOf('Y');
        if (yPos != -1)
        {
            int yEnd = item.IndexOfAny(new char[] { 'X', 'G', 'M' }, yPos + 1);
            yEnd = yEnd == -1 ? item.Length : yEnd;
            double.TryParse(item.Substring(yPos + 1, yEnd - yPos - 1), out targetY);
        }

        string command;
        if (isFirstRun)
        {
            // 第一次发送绝对坐标,定位到初始位置
            command = $"G90 {item}";
            isFirstRun = false;
        }
        else
        {
            // 计算相对移动量,生成相对坐标指令
            double deltaX = targetX - currentX;
            double deltaY = targetY - currentY;
            command = $"G91 X{deltaX:F2} Y{deltaY:F2}";
        }

        serialPort1.WriteLine(command);
        textBox3.Text = command;

        // 更新当前位置记录
        currentX = targetX;
        currentY = targetY;

        currentIndex++;
    }
    else
    {
        // 循环时回到第二个点,继续执行路径
        currentIndex = 1;
        // 如果需要形成闭环(最后一个点回到第一个点),将上面的1改为0即可
    }
}

补充说明

  • 方案一适合不需要平滑衔接、仅需重复路径主体的场景;
  • 方案二更适合需要连续平滑循环运动的场景,需要确保Arduino端支持G90(绝对坐标)和G91(相对坐标)指令。

内容的提问来源于stack exchange,提问作者Ozzie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 23:00:55