开源改变世界

GRBL 响应格式缺乏一致性 #342

推推 grbl 2年前 (2023-01-22) 208次浏览

关闭
Dandiee 打开了这个问题 2018 年 1 月 3 日 · 7条评论
关闭

GRBL 响应格式缺乏一致性#342

Dandiee 打开了这个问题 2018 年 1 月 3 日 · 7条评论

注释

GRBL 响应格式缺乏一致性 #342

免责声明:这没什么大不了的,在任何其他方面使用 GRBL 都很棒,但它仍然让我感到烦恼——而且非常让我烦恼,正是因为 GRBL 在任何其他方面都非常一致。

我们有很多不同类型的状态/设置/配置/选项/参数,所有这些都是独一无二的并且绝对是必需的,但是您可以识别和解析它们的方式非常不同,有时不合逻辑,有很多例外。

让我总结一下最重要的:

  1. StatusReport
    请求-响应:一个实时命令 => 一行没有“ok”的响应(完美!)
    检测:简单。第一个字符是<.
    解析:两个级别:键值对按管道拆分,键值对按 拆分:。(但这不是真的,请参阅关注点)
    关注点:
  • 状态本身(作为枚举)是一个例外。为什么这个值不只有一个键字符?像 S:Alarm 或 S:Idle。是的,它是额外的内存,但您可以摆脱字符串状态标签,使用简单的整数(参见错误和警报代码,或设置键)。
  • 但是状态中有一个二级异常,因为它有时(但不总是)有一个子状态(Hold:0)。为什么它们不是一种特定的状态?或者为什么我们不以一致性的名义为其他状态设置子状态(默认为 0)?如果所有状态都只是整数,那么您可以有很多状态/子状态。
  • WCO 是一个棘手的问题,因为它在这里有点例外,但无论如何 WCO 都是冗余数据,因为您可以从 ParserState ($G) 获取当前坐标系并从 GcodeParameters ($#) 获取该 coosys 的偏移量。但是没关系,有它很好,而且由于键值对格式,当长度是动态的时,您可以轻松地解析响应。
  • BufferState (Bf)、Speed (FS)、OverrideValues (Ov):所有这些都是例外,因为您对一个键有更多的值。更糟糕的是,它们是按特定顺序排列的。有时我们有键值对和动态响应长度,但有时没有。在这种情况下,在一件事情(状态报告)中,我们看到了两种不同的方法。当然我可以看到它们背后的逻辑,GRBL 的内存量非常有限,额外的键会使情况变得更糟,但老实说:使用整数作为键(而不是 2 个字符键)就可以了。您可以使用精确的密钥轻松识别所有数据,并且占用更少的内存。

想法:<key_integer:single_value | >,例如:<0:2|1:1,2,3|2:35| … > 严格一致的格式,更少的内存消耗,界面编写者可以使用枚举作为键,以获得更具可读性的代码。是的,对人类不友好…

  1. 设置
    请求-响应:一个流命令 => 多行响应“确定”(最坏情况)
    检测:一行容易,完整设置列表非常困难且有风险。
    解析:和检测一样,一行容易,全图难。
    关注点
  • 这里我们有一个非常一致的键值对列表,带有整数键(正如我为上面的状态报告所建议的),但我们有一个新的分隔符:’=’。这是键值分隔符为“=”的唯一情况。是的,这没什么大不了的,就像整个话题一样,但仍然值得一提。这些只是我的小顾虑。这只是额外的复杂性,没有任何好处。
  • 这是我最大的问题:整个一行请求,多行响应的东西让我很难受。是的,我们在列表末尾有一个“ok”,就像我们在 GRBL 接受 $$ 请求时有一个一样,但这意味着,您不能拥有像通用 ResponseProcessor 这样的东西来接受响应并处理它。在这种情况下,读取和写入部分紧密耦合,CQRS 解决方案可能非常棘手。看起来,此时我有两个选择:忽略列表末尾的 OK 消息并使用以 $ 开头的易于识别的行,在这种情况下,我不知道什么时候所有设置都为我所知,或选项#2:只为设置打印输出编写一个迷你状态机,它知道开始和结束 ok。如果它在其他任何地方都有用,那就太好了,但事实并非如此。它’ 这只是一次额外的大复杂性。在我列出设置的同时也有可能发生一些可怕的事情,例如触发了限位开关,这将在我的状态机中间发送即时推送消息。

想法

  • 首先也是最重要的:摆脱多行解决方案。每个请求应该只有一行响应。使用标准的“:”键值分隔符和它们之间的管道。是的,又是人类可读性,但我不确定在接口方面它有多重要,而且由于行尾在我们的交流中起着重要作用,所以应该非常小心地使用它,而不是像这样。$0:1|1:123.456|2:3 …长得丑?是的,就像状态报告一样,但 UI 编写者仍然可以以他们希望的任何花哨格式显示它。如果可读性是一个问题,或者在 config.h 中为此格式进行配置。

但它变得更糟:

  1. GCode 参数:
    请求-响应:一个流命令 => 多行响应“ok”(最坏情况)
    检测:噩梦。没有简单的方法来识别参数响应只有当你确切地知道你期望什么(再次:读取和写入紧密耦合,或者响应是硬编码的)
    解析:不一致。键值分隔符是“:”,但只有一个没有任何充分理由的例外(PRB 有两个值,具有完全相同的分隔符)
    问题
  • 一个请求 => 多行响应在这里更糟糕,因为您甚至无法轻松识别单行。第一个字符在其他地方很常用(所有反馈消息都以“[”开头)。唯一的解决方案是硬编码列表,其中包含所有可选键(G54、G28 G92、TLO、PRB 等)。这是唯一的情况,当您无法一眼识别出一条线时。没有特殊的起始字符,没有静态键。没有。如果我们有一个特殊字符来标识一行作为参数响应,它至少与设置相同。但不是。这是第三种情况,没有一个很好的理由。
  • PRB 参数使情况变得更糟,因为我们有一个键的 2 个值,但具有完全相同的分隔符。

想法:还有什么。那太愚蠢了。所有键都应该有一个且只有一个值。所有行都必须易于识别为参数响应。多线情况使情况变得更糟。与往常一样,解决方案与往常一样(这正是一致性的关键所在):一个请求 => 一行响应,带有键值对(其中键是整数)。’:’ 作为键值分隔符,管道作为对分隔符。

  1. GCode 解析器状态:
    请求-响应:一个流命令 => 具有多个数据的一行响应。
    检测:可能会好得多,因为第一个字符在这里不占主导地位,您需要读取行的开头以将该行识别为解析器状态。使用这样的东西是不可能的: https ://i.imgur.com/WmcjIRR.png你必须在没有任何反馈消息的情况下编写子处理器。
    解析:不好玩,但还不错。我喜欢它的工作方式。T/S/F 参数是例外,但我没有更好的主意。这是有道理的,T/S/F 是解析器状态的一部分,它们是数字,所以是的。我可以忍受它。仅针对这 3 个参数的单独解析器状态响应我猜会太多了吧?
    关注点
  • 第一个字符不显性(反馈信息,但它是一种特殊的反馈信息)。为什么我们必须多次重复使用反馈消息?解析器状态是一个非常重要的信息,UI 大量使用它。它值得一个专用的启动字符(就像所有的响应一样)。我的意思是,我可以没有独特的第一个字符,但看起来我们有一些,为什么我们没有所有的回应?再次一致性。
  • T/S/F 参数也是例外,但我没有更好的主意,所以让我们跳过这个。

想法:将 [GC: 替换为一个独特的字符,我是一个快乐的人(谁在乎,我知道)

我还有很多其他类似的担忧/想法,但我已经太长了。我很乐意就这些进行讨论。

是的,我的英语很糟糕,我可能犯了数百个错误。我正在努力,请原谅我。

GRBL 响应格式缺乏一致性 #342
贡献者

我没有注意到你的英语有什么糟糕的地方。您使用的格式以及建设性的建议很容易理解。

  1. StatusReport
    WCO 是一个棘手的问题,因为它在这里有点异常,但无论如何 WCO 都是冗余数据,因为您可以从 ParserState ($G) 获取当前坐标系并从 GcodeParameters ($#) 获取该 coosys 的偏移量.

我有点同意你的看法,但 WCO 数据并非严格冗余,原因有一个:它在更改后包含在下一条状态消息中。与请求相比,您更有可能发送状态$#请求。

  1. 设置
    首先也是最重要的:去掉多行解决方案

我们要求的第一个故障排除步骤之一是“将输出发送到‘$$’”,因此此建议会使支持变得更加困难。许多 GUI 还通过CSV 翻译来增强单行响应,这使得这在支持期间更有帮助。

虽然使用的建议$0:1|1:123.456|2:3很有趣,但我确实喜欢一致性,但不确定它是否超过可用性成本。

  1. GCode 参数:
    唯一的解决方案是硬编码列表,其中包含所有可选键(G54、G28 G92、TLO、PRB 等)

你在某种程度上回答了你自己的问题。特殊的启动器模式是[G54,等等。它们在文档中被这样调用。

虽然[PRB评论有点令人担忧,但我没有意识到它在那里,如果用户$#在某些操作期间发送,它可能是某些发件人中的错误。

  1. GCode 解析器状态:

看来这又是一个单字的问题。我认为将所有状态排成一行是一项具有历史意义的 CNC 公约,这可能就是 GRBL 以这种方式完成的原因。

这里的主题似乎是多行响应,你不喜欢多字符模式。但是在这两种情况下,您都声称这会阻止您为 GRBL 响应使用无状态解释器。那不是真的(也许[PRB:情况除外)。确实,如果您想使用 <char, callback> 字典来实现您的解析器,那么我建议您寻找替代设计。

如果您好奇,可以在 GitHub 上找到许多示例,但根据您的评论中的详细信息,我确信您不需要它。它们可能不严格匹配 Martin Fowlers 设计模式之一,但许多也不是特别复杂。这是我的,5 年前写的,那时我还不知道 CQRS 是什么。它不仅一次解析一行 GRBL 响应,而且可以处理从 0.7 到 1.1 的任何 GRBL 消息。我什至将其命名为类似于ResponseProcessor您想要的通用名称:rawResponseHandler。为了完整起见,状态解析代码也是如此,在我的代码中,我认为这是最复杂的部分(对于 GRBL 1.1):getStatusFromStatusString

我最担心的是这些单位没有明确包含在状态消息中,即使是间歇性的WCO也可以。虽然它们通过计算小数位数隐式包含在内,但我不喜欢依赖于这种未记录的行为。

GRBL 响应格式缺乏一致性 #342
作者

首先,我很高兴有一位贡献者选择了我的话题并给了我一个直接的答案。

[…] 这会阻止您对 GRBL 响应使用无状态解释器。那不是真的(也许 [PRB: 案例除外)。确实,如果您想使用 <char, callback> 字典来实现您的解析器,那么我建议您寻找替代设计。

您刚刚用一句话完美地总结了我的主要目标:“为 GRBL 响应提供无状态解释器”。是的,现在有可能,我刚刚做了一个,我只是不喜欢它,让我向您展示我解析答案的方式:

  1. 高级识别:在大多数情况下,第一个字符足以识别答案,如果您使用字典,这是最干净、最快的解决方案:https ://i.imgur.com/WmcjIRR.png

  2. 反馈级别:对于反馈,我需要先获取消息的密钥。与1.级别识别非常相似,但还是有区别:https ://i.imgur.com/TqOlMDn.png

  3. Gcode 参数级别:没有花哨/快速的方法来做到这一点,只是一个预编译的选项列表:https ://i.imgur.com/Cwq6Qw8.png

它在恭敬上是可行的,但您将需要 3 种不同的方法,而且我看不出额外复杂性的意义/好处,当我们谈论可维护性时,它会强烈反击,但这只是冰山一角。

让我们假设 2+1 事物:

  1. 我们有一个完全实现的 GRBL GUI。每个小功能都至少以一种方式得到支持。对此最重要的要求之一是直观/用户友好的可视化。为此,您需要 GRBL 可以提供的所有信息。所有偏移量、参数、小设置(甚至来自 config.h)。

  2. 新版本的 GRBL 即将到来。一些代码中断,也许并非所有内容都向后兼容,这不是问题,因为您已经预料到这一点,因此您围绕易于修改的配置编写了 GUI。新的设置开始了吗?只需在您的 Settings.xml/json 中添加一个包含详细信息的新行,然后使用您的(比方说)T4 模板生成新代码。系统命令或覆盖功能,甚至状态报告和 gcode 参数也是如此。以您的 GUI 可以与所有现有 GRBL 版本一起运行的方式编写您的代码是一种儿童游戏。它们只是配置中的小额外信息。TLO参数是新的?让我们添加一个 version=”>1.1″。

  3. 无状态解释器

现在,我们需要尽快获得所有信息。可视化需要了解 CNC 的大小,因此首先您必须查询连接设置(我们不信任首次启动时的缓存数据)。但是最好向用户显示保存的坐标(例如 G28)。因此,您还需要 GCodeParameters。当前模态状态是另一个非常重要的信息。也拿那个。

你从哪里知道 – 比方说 – 设置已加载?通信的基石是 \r\n,但您不能使用它。一行不是完整的图片,只是完整请求数据的一个片段。’Ok’ 是一种回应,$132=0 是另一种。我可以发布一个事件说,嘿,ZMaxTravel 信息已准备好使用,但您不能确定 XMaxTravel 数据是否也是如此。我真的不想触及 SettingPrintoutParser 中的“确定”响应,因此我不得不添加一个中间层来捕获来自 SettingParser 的所有已发布事件并监视它们。它基本上是一个检查列表,可确保您拥有一个完全加载的设置模型,现在您的 GUI 可以决定使用哪些功能,哪些不使用。一个请求 => 多个答案 =>

你的解析器可以是无状态的唯一方法,如果你在通信层的顶部添加一个有状态的服务 – 如果你愿意的话,一个聚合器。在一天结束时,您将必须知道以前的响应以确保请求得到满足。您可以将问题推到更高的层次,并说解析器本身是无状态的,但这只是问题的一方面。问题还是一样,只是你把它隐藏起来了。

我怎么强调都不为过:我们都知道,为 GRBL 编写一个非常复杂的 GUI 非常容易,如果一个小组件不能以无状态方式编写:谁在乎呢?但另一方面:这看起来像是一个设计缺陷,很容易修复,并且与现有 GUI 的向后兼容性只是 config.h 中标志的问题。

GRBL 响应格式缺乏一致性 #342
贡献者

@dani88: 一个建议。如果你写了一篇很长的文章,不要指望立即回复。尽量让你的问题简短。否则它变成 TL; DR。直到今天早上我才有时间坐下来仔细研究你的观点。

  • Status report state:在界面wiki中声明state值永远在前。所以你不需要标识符。消息会占用大量时间和带宽,尤其是在流媒体传输量大且需要高速率请求状态报告时。标识符是多余的,已被删除以减少消息长度。

  • 子状态:这是语义。你可以争辩说拥有子状态更复杂。例如,“Hold:1”将是“Holding”,而“Hold:0”将是“Hold Complete”。再次这样做是为了尽量减少消息长度而不会使事情过于复杂。

  • WCO:这是绝对必要的。“$#”消息只能在 Grbl 空闲时调用。这是由于访问 EEPROM 的方式所致。Grbl 没有内存空间来保留所有内容,因此它必须获取它。此外,WCO 可以在作业期间动态更改。例如,刀具长度偏移将执行此操作。为了减少冗余,WCO 是间歇性的,在发生变化时自动发送,并且可以设置为每 255 个状态报告刷新一次。这也是以这种方式完成的,以帮助提示用户存在机器和工作坐标。如果 WCO 不一直存在,这将不会很明显。

  • ‘Bf:’, ‘FS’, ‘Ov’ :同样是语义。很抱歉您对此感到恼火,但这很容易解决。我好的解析器不应该关心顺序是什么或标签。不使用整数标识符,因为它们不是人类可读的。我更喜欢简单的字符标识符,这样我可以快速查看发生了什么。当您从终端实时查看数据流时,如果它们处于固定顺序,则更容易辨别状态消息。如果它们总是出问题,你就会一直在寻找。

至于你关于“想法”的帖子的后半部分,我很难理解。如果你的意思是你想改进通信协议以包括发送多条线路,我已经在着手解决这个问题。很难让它像当前协议一样简单,但我认为它会起作用。

我首先承认 Grbl 的通信协议并不完美,但一旦你处理了它的怪癖,它就会起作用。有很多依赖关系使得很难显着改变事情。你会破坏所有现有的图形用户界面并激怒很多人。从 v0.9 到 v1.1 风格协议的转换是非常谨慎的。我得到了所有主要 GUI 开发人员和 OEM 的意见,看看他们是否对新的 v1.1 协议有任何问题。花了很长时间才把事情整理好。然而,它并不完美,但已经足够好了。

使用新的 ARM 版本,我有足够的闪存和内存来尝试一些东西,并且仍然支持 v1.1 协议。当事情发布时,我很乐意讨论改进它的方法。

GRBL 响应格式缺乏一致性 #342
作者

谢谢。我真的没想到会很快得到答复,我认为这应该更像是一次讨论,而不是错误报告或帮助请求。即使需要两周的时间,我也会很感激你的回答。但是你一天之内就回复了。谢谢你。

根据您的回答,我觉得 GRBL 似乎在沟通方面存在严重问题,必须加以解决。那不是真的。没有错误或错误,通信已经在许多不同的 GUI 中工作,文档完整,没有漏洞。

您在回答中多次提到语义,这正是我所说的。是的,status 是状态报告响应中的第一个字段,正如文档中所说的那样,这很清楚。文档是准确的,没有未记录的行为等等。
我的观点是,我在语义上看到了很多不一致之处。有些问题很容易解决,有些则不然。如果你这样说的话有点模糊,这就是为什么我创建了一个简单的列表,其中包含示例和“想法”,这些示例和“想法”是有建设性的,而不是某种主张。对不起,如果它是模棱两可的。

状态报告不是完美的例子,但你的答案是基于状态报告本身,所以我会继续这个,即使状态报告有点太具体而且我的整篇文章都是关于所有的语义的一致性反应不只是在一个。

首先:感谢世界海关组织的澄清。完全有道理,它不是重复的数据。
我会根据您的回答强调我的担忧。

这正是语义

state 值总是第一个
好吧,所以我们有一个顺序,比如 State 先出现。或者在 Ov/Fs/Bf 字段中我们有一个订单。这远非全貌,因为我们有大量带有标签/键但没有确切顺序的字段。

好的解析器不应该关心顺序是什么或者标签
同时,解析器不应该关心顺序。好的,这越来越难了。有时它应该关心有时它不应该。
解析器必须关心其中之一,并且只关心其中之一。我们有订单或有钥匙。是的,我们可以同时拥有两者,就像我们现在拥有的那样,但这只是无缘无故的额外复杂性。有用?是的。只有一种方法会更优雅吗?我想是的,是的。

标识符是多余的,已被删除以减少消息长度
但是,我们仍然有:{MPos, WPos, WCO, Pn, Ov, … } 带有标签/键。有一个很好的理由:它甚至在终端上也是可读的。这完全有道理,也解释了为什么状态没有相同的键:因为状态本身是可读的并且很容易识别。

可能它让你了解我的观点。我通过易于阅读的回复理解您的想法,所以让我从以下方式着手:

如果有一种机器友好的方式与 GRBL 进行通信,那就太好了。在“好的解析器”再次出现之前:一个好的解析器本身是微不足道的,而且很容易实现。您可以按照您希望的任何格式向我发送回复,虽然所有消息都保持一致,但我会很高兴。让我们使用人类可读的字符串标签、结构布局或整数键。不要紧。但要让语义严格一致,无 L’art pour L’art 例外。

顺便说一句,正如我上面所说,我主要关心的仍然是多行响应,这可以再次用人类可读性来解释,在这种情况下我可以重复我自己:例如,一个机器友好的解决方案在 ARM 版本上会很好,当然是在遥远的未来。

由于现在所有的响应都是人类友好的,是否可以为机器通信添加替代响应格式,而我们不必对边缘情况和异常进行硬编码?

例如,将 $$ 作为人类友好的设置打印输出请求,但添加任何 ascii 代码请求以在一行中以非常可靠的格式获取设置。GUI 不需要花哨的键或标签,或状态字符串,它们只会让事情变得更糟。有了这个解决方案,GUI 可能会更健壮,并且由于消息会更小,通信甚至会更快。如果我们谈论机器通信,一条规则优于 42 条规则,但有 35 条例外。

GRBL 响应格式缺乏一致性 #342
贡献者

@dani88: 您的担忧已被听到并且已经在处理中。328p 上的 Grbl 只能提供一个协议的空间。该协议必须是人类可读的。它还必须保持与先前 GUI 的兼容性,以防止完全重写。您陈述的很多问题都可以追溯到我第一次在 Grbl v0.7 中安装的东西。这些决定和错误在今天的 v1.1 中得到了延续。启动消息和多行就是其中的例子。

正如我之前提到的,我打算在 ARM 版本中试验其他通信协议,因为我有足够的空间来这样做。您的多行问题很容易消除。可以完成其他事情,例如将所有东西都放入漂亮的隔间盒中,但我发现并不是所有东西都可以有效地放入一个方案中。最大的限制因素是消息长度和开销的最小化。如果您尝试将所有内容都放入 JSON,消息很快就会变得巨大,充满冗余字符。如果你以预定义的方式编码信息,就像深空卫星那样,你可以塞进更多的数据。

然而,事情可能会保持最低限度的人类可读性。如果您必须不断地在表格中查找内容,那只会阻碍采用。另外,如果您使用 ASCII 字符作为值,人类可读的缩写在消息大小上不会大很多。

二进制或 ASCII 基本压缩消息也是可能的。我们将看看结果如何。

GRBL 响应格式缺乏一致性 #342

@chamnit 请问ARM版Grbl的发布时间?

GRBL 响应格式缺乏一致性 #342
贡献者

即将发布 Beta 版。自去年六月以来,我有一个刚刚完成的 NASA 项目。这花了我所有的时间。我一直在重新熟悉代码,但还有很多工作要做。

喜欢 (0)