开源改变世界!!

建议:始终在启动/重置时触发状态更改 #45

推推 grbl 2年前 (2023-02-08) 171次浏览
关闭
5ocworkshop 开了这个issue 2021 年 7 月 26 日 · 14条评论
关闭

建议:始终在启动/重置时触发状态更改#45

5ocworkshop 开了这个issue 2021 年 7 月 26 日 · 14条评论

评论

建议:始终在启动/重置时触发状态更改 #45

我正在为我的机器处理状态灯,如果机器进入 STATE_IDLE,它似乎不会触发 onStateChanged 事件。

但是,如果它出现在 STATE_ALARM(需要归位)状态,它就会触发。在启动和重置事件期间触发状态更改会很好,因此链接到该触发器的任何东西都有机会在启动/重置时执行功能。

建议:始终在启动/重置时触发状态更改 #45
作者

拥有 STATE_BOOT 或 STATE_RESET 标志(或两者都有?)甚至可能很有用。

建议:始终在启动/重置时触发状态更改 #45
贡献者

但是,如果它出现在 STATE_ALARM(需要归位)状态,它就会触发。在启动和重置事件期间触发状态更改会很好,因此链接到该触发器的任何东西都有机会在启动/重置时执行功能。

我看看我是否可以在不进行太多更改的情况下添加它。你也可以在你的插件中本地处理这个,见下文。

拥有 STATE_BOOT 或 STATE_RESET 标志(或两者都有?)甚至可能很有用。

hal.driver_reset这些事件已经是可捕获的,插件初始化函数在启动期间被调用一次,您可以通过向链中添加一个函数来订阅重置事件。ioports 模板中的代码显示了如何添加重置处理程序。

建议:始终在启动/重置时触发状态更改 #45
作者

hal.driver_reset这些事件已经是可捕获的,插件初始化函数在启动期间被调用一次,您可以通过向链中添加一个函数来订阅重置事件。ioports 模板中的代码显示了如何添加重置处理程序。

谢谢,我会检查一下。

另一个关于入口点的想法。我仍然对代码很熟悉,但我希望能够在某些状态下闪烁灯光,例如 ALARM。要以非阻塞方式执行此操作,我需要循环,但是对于事件驱动的回调,我不能保证我会在可靠的时间间隔内被调用。

现在我将闪烁代码切换到报告更新回调中,但这仅在发送方已连接并可靠地请求更新时才有效。诚然,这是预期的操作,大多数发件人都遵守,但间隔有所不同。CNCjs 的当前稳定/官方版本在 ALARM 状态期间停止查询(这可能不是预期/期望的情况,但它就是这样),这会干扰循环。

除了已经存在的更经典的触发事件之外,是否有可能在主循环的末尾有一个入口点,它不是由事件触发,而是在到达循环末尾时触发?

建议:始终在启动/重置时触发状态更改 #45
贡献者

除了已经存在的更经典的触发事件之外,是否有可能在主循环的末尾有一个入口点,它不是由事件触发,而是在到达循环末尾时触发?

我在管道中有几个例子,一个是眨眼的:

/*

  my_plugin.c - user defined plugin that blinks the LED on a STM32F411 Blackpill

  Part of grblHAL

  Public domain

*/

#include "driver.h"

static on_report_options_ptr on_report_options;
static on_execute_realtime_ptr on_execute_realtime;

// Add info about our plugin to the $I report.
static void on_report_my_options (bool newopt)
{
    on_report_options(newopt);

    if(!newopt)
        hal.stream.write("[PLUGIN:Blink LED v1.00]" ASCII_EOL);
}

static void blink_led (sys_state_t state)
{
    static bool led_on = false;
    static uint32_t ms = 0;

    if(hal.get_elapsed_ticks() >= ms) {
        ms = hal.get_elapsed_ticks() + 500; //ms
        led_on = !led_on;
        if(led_on)
            GPIOC->ODR |= GPIO_PIN_13;
        else
            GPIOC->ODR &= ~GPIO_PIN_13;
    }

    on_execute_realtime(state);
}

void my_plugin_init (void)
{
    // Add info about our plugin to the $I report.
    on_report_options = grbl.on_report_options;
    grbl.on_report_options = on_report_my_options;

    // Add blink LED function to grblHAL foreground process
    on_execute_realtime = grbl.on_execute_realtime;
    grbl.on_execute_realtime = blink_led;

    // Enable PC13 as output
    GPIO_InitTypeDef GPIO_InitStructure = {
        .Mode      = GPIO_MODE_OUTPUT_PP,
        .Speed     = GPIO_SPEED_FREQ_VERY_HIGH,
        .Pin       = GPIO_PIN_13,
    };
    HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
}
建议:始终在启动/重置时触发状态更改 #45
作者

太好了,这正是我要找的。这在今天可用还是在您“在不久的将来承诺”堆栈中可用?

建议:始终在启动/重置时触发状态更改 #45
作者
5oc工作坊 评论了 2021 年 7 月 27 日  

这是我现在正在为闪烁部分所做的。

是否有 HAL 调用会返回当前警报子代码?我还没有找到一个。

另外,是否有通过 hal.spindle.get_state 调用读取主轴状态的示例?主轴开启是我想要跟踪的关键事项之一。

我还没有尝试优化代码(而且我是一个相对的新手),仍在尝试制定我的核心逻辑。

我希望能够做这样的事情:对于限位开关触发的警报,闪烁红色,但在序列中添加一个轴颜色的快速脉冲,这样你就可以得到 Z 的蓝色脉冲、Y 的绿色脉冲和 X 的红色脉冲传感器。我只需要弄清楚如何从 hal 调用中提取这些细节。


void rgb_set_state (reqcolor) {
    hal.port.digital_out(red_port, RGB_MASKS[reqcolor].R);
    hal.port.digital_out(green_port, RGB_MASKS[reqcolor].G);
    hal.port.digital_out(blue_port, RGB_MASKS[reqcolor].B);    
}

static void onRealtimeReport (stream_write_ptr stream_write, report_tracking_flags_t report)
{
    static sys_state_t local_state;  // For STATE_* 
    static alarm_code_t alarm_code; // For Alarm_*  Only present it STATE_ALARM is asserted?

    currentMS = hal.get_elapsed_ticks();

    local_state = state_get();

    // Alarm states
    if ((local_state == STATE_ALARM || local_state == STATE_ESTOP) && rgb_flash_state == 0 && ( currentMS - startMS >= RGB_FAST)) {
    //if (alarm_code == Alarm_HardLimit && rgb_flash_state == 0 && ( currentMS - startMS >= RGB_FAST)) {
        rgb_set_state(RGB_RED);
        rgb_flash_state = 1;
        startMS = hal.get_elapsed_ticks();
    }
    if ((local_state == STATE_ALARM || local_state == STATE_ESTOP) && rgb_flash_state == 1 && ( currentMS - startMS >= RGB_FAST)) {
        ///if ((alarm_code == Alarm_HardLimit) && rgb_flash_state == 1 && ( currentMS - startMS >= RGB_FAST)) {
        rgb_flash_state = 0;
        rgb_set_state(RGB_OFF);
        startMS = hal.get_elapsed_ticks();
    }

    // Other events with that involve flashing lights - used to indicate immediate human attention required
    // Door ajar, Hold, Tool Change etc.

    if ((local_state == STATE_HOLD ) && rgb_flash_state == 0 && ( currentMS - startMS >= RGB_FAST)) {
        rgb_set_state(RGB_YELLOW);
        rgb_flash_state = 1;
        startMS = hal.get_elapsed_ticks();
    }
    if ((local_state == STATE_HOLD) && rgb_flash_state == 1 && ( currentMS - startMS >= RGB_SLOW)) {
        rgb_flash_state = 0;
        rgb_set_state(RGB_OFF);
        startMS = hal.get_elapsed_ticks();
    }

    if(on_realtime_report)
        on_realtime_report(stream_write, report);
}
建议:始终在启动/重置时触发状态更改 #45
作者

您的示例效果很好。我要把我的代码移到那个回调中。

建议:始终在启动/重置时触发状态更改 #45
作者

另外,是否有通过 hal.spindle.get_state 调用读取主轴状态的示例?主轴开启是我想要跟踪的关键事项之一。

也发现了这个:

(!(hal.spindle.get_state().on))

建议:始终在启动/重置时触发状态更改 #45
贡献者
terjeio 评论了 2021 年 7 月 27 日  

这在今天可用还是在您“在不久的将来承诺”堆栈中可用?

昨天提交了更多示例。

是否有 HAL 调用会返回当前警报子代码?我还没有找到一个。

没有来电,可以从 中读取报警代码sys.alarm,该内容仅在报警状态下有效。

另外,是否有通过 hal.spindle.get_state 调用读取主轴状态的示例?主轴开启是我想要跟踪的关键事项之一。

你可以在 grbl/report.c 中找到一个:

核心/报告.c

第 1156 行 2068165

spindle_state_t sp_state = hal。主轴获取状态();

 

核心/报告.c

第 1249 至 1251 行 2068165

如果(sp_state.on
*追加++ = sp_state。逆时针 C S

 

您还可以将代码链接到 HAL 入口点,这样就不需要进行轮询。请参阅等离子插件以了解如何执行此操作。请注意,某些功能指针会在设置更改时重置,hal.spindle.set_state这是一个 – 您必须捕获设置更改并重新链接。

我只需要弄清楚如何从 hal 调用中提取这些细节。

将您自己的代码链接到 HAL 在某种程度上与订阅事件相同,您可以用它做各种奇特的事情。查看提供的插件中的代码以获取想法…

您的示例效果很好。我要把我的代码移到那个回调中。

我还没有尝试优化代码(而且我是一个相对的新手),仍在尝试制定我的核心逻辑。

提示:轮询grbl.on_execute_realtime事件处理程序中的所有内容并不是最好的方法,IMO 最好订阅事件(或链接到 HAL 调用)并处理它们。更多的代码但更少的开销。

建议:始终在启动/重置时触发状态更改 #45
作者

感谢您提供的出色反馈以及您对这个项目的所有工作和深入思考。我对您的布局了解得越多,我对结构和可扩展性的印象就越深刻。做得好!

建议:始终在启动/重置时触发状态更改 #45
作者

关于以下问题:

if(state != last_state) {
        last_state = state;
        hal.port.digital_out(port, state == STATE_HOLD);
    }

这是一种优雅的表达方式吗?“如果状态为 == STATE_HOLD,则只执行 hal.port.digital_out(port) 调用?如果是这样,你能不能连续有多个这样的东西,它们几乎就像一个 if 链statements or a case statement?我没有意识到你可以在函数调用中进行测试,这很有帮助。

建议:始终在启动/重置时触发状态更改 #45
贡献者

这是一种优雅的表达方式吗?“仅在状态为 == STATE_HOLD 时才执行 hal.port.digital_out(port) 调用?

不 – 这是一种通过一次状态更改调用来打开或关闭输出的方法。您还可以像这样编写 hal.port.digital_out() 调用:

if(state == STATE_HOLD)
    hal.port.digital_out(port, true);
else
    hal.port.digital_out(port, false);

或者像这样:
hal.port.digital_out(port, state == STATE_HOLD ? true : false);

当参数值不是布尔值时,最后一个很有用。

如果是这样,您是否可以连续使用多个这样的语句,它们几乎就像一串 if 语句或 case 语句?

这取决于,它会导致一些开销,因为函数调用将始终被执行。

我没有意识到您可以在函数调用中进行测试,这非常有帮助。

您甚至可以将函数调用用作参数,只要它返回正确的类型即可。无需使用临时变量。一个例子:
memcpy(&hal.stream, serialInit(), sizeof(io_stream_t));

建议:始终在启动/重置时触发状态更改 #45
贡献者

我忘了你上面提到的这个:

if(!hal.spindle.get_state().on)
...

这可以这样写(大多数人会这样做?):

spindle_state_t state = hal.spindle.get_state();
if(!state.on)
...

如果只需要引用结构/联合返回值中的一个元素,这是一个巧妙的技巧。同样,不需要临时变量。

建议:始终在启动/重置时触发状态更改 #45
作者

如果只需要引用结构/联合返回值中的一个元素,这是一个巧妙的技巧。同样,不需要临时变量。

这是一个非常巧妙的技巧。这些都是很棒的细节。

非常感谢所有提示。我将广泛地注释我的插件。当我准备好分享时,我很乐意得到你的想法/代码审查。