如何调整C#代码让CNC电机以当前位置为起点重复发送G代码
解决方案
你的问题核心是循环时重置索引到0,导致电机回到初始绝对坐标位置。下面提供两种针对性修改方案:
方案一:跳过初始点循环路径(保持绝对坐标模式)
如果你的列表第一个项是初始位置,后续是运动路径,这个方案会在第一次走完所有点后,循环执行从第二个点到最后一个点的路径,避免回到初始位置。
修改步骤:
- 添加类级别的布尔变量,标记是否是第一次循环:
private bool isFirstLoop = true; private int currentIndex = 0; // 确保这个变量已在类中定义
- 修改
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("端口未打开或数据不足"); } }
- 修改
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; } } }
方案二:转为相对坐标模式(连续循环运动)
如果希望循环时电机从当前位置平滑衔接路径(而非跳转到某个绝对坐标),可以将绝对坐标转为相对移动指令,这样循环时自然保持连续运动。
修改步骤:
- 添加类级别的变量记录当前位置和运行状态:
private int currentIndex = 0; private double currentX = 0; private double currentY = 0; private bool isFirstRun = true;
- 修改
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("端口未打开或数据不足"); } }
- 修改
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
相关产品推荐
相关产品推荐

