Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem: how to home at hold state (by config file or programmatically) #1226

Closed
zengfanfan opened this issue May 19, 2024 · 12 comments
Closed

Comments

@zengfanfan
Copy link

zengfanfan commented May 19, 2024

FluidNC version

release v3.7.17

Wiki Search Terms

Homing at Hold state

Controller Board

not listed but quite simple: (and the problem is irrelevant with hardware)

  1. mcu: ESP32-WROOM-32 see https://github.com/SmartArduino/SZDOITWiKi/wiki/ESP8266---ESP32
  2. oled using I2C bus [shown function tested]
  3. sd card using SPI bus [read/write function tested]
  4. three steppers (and driver) for X/Y/Z axes [3d motion tested with G01 X275 Y275 Z0 f3000 and G01 X0 Y0 Z80 f3000]
  5. four buttons using gpio 34,35,36,39 with external pull-down 10kΩ resistors. [trigger function tested]
    each hardware part is tested basically.

and pin usage:
image

Machine Description

irrelevant ....

  1. a Y motor at buttom;
  2. a X motor at gantry;
  3. a Z motor carried by X

something like bambu lab a1 mini

Input Circuits

No response

Configuration file

name: xyz

stepping:
  engine: RMT
  idle_ms: 255
  pulse_us: 4
  dir_delay_us: 0
  disable_delay_us: 0
start:
  check_limits: true
  must_home: true
axes:
  x:
    steps_per_mm: 400
    max_rate_mm_per_min: 6000
    acceleration_mm_per_sec2: 1000
    max_travel_mm: 275
    soft_limits: true
    homing:
      cycle: 2
      mpos_mm: 0
      seek_mm_per_min: 5000
      feed_mm_per_min: 60
      positive_direction: false
    motor0:
      limit_neg_pin: gpio.12:pd:high
      hard_limits: true
      pulloff_mm: 2
      standard_stepper:
        step_pin: gpio.4:pd
        direction_pin: gpio.15:high
  y:
    steps_per_mm: 400
    max_rate_mm_per_min: 6000
    acceleration_mm_per_sec2: 1000
    max_travel_mm: 275
    soft_limits: true
    homing:
      cycle: 2
      mpos_mm: 0
      seek_mm_per_min: 5000
      feed_mm_per_min: 60
      positive_direction: false
    motor0:
      limit_neg_pin: gpio.16:pd:high
      hard_limits: true
      pulloff_mm: 2
      standard_stepper:
        step_pin: gpio.17:pd
        direction_pin: gpio.5:low
  z:
    steps_per_mm: 400
    max_rate_mm_per_min: 6000
    acceleration_mm_per_sec2: 1000
    max_travel_mm: 80
    soft_limits: true
    homing:
      cycle: 1
      mpos_mm: 80
      seek_mm_per_min: 5000
      feed_mm_per_min: 60
      positive_direction: true
    motor0:
      limit_pos_pin: gpio.2:pd:high
      hard_limits: true
      pulloff_mm: 2
      standard_stepper:
        step_pin: gpio.18:pd
        direction_pin: gpio.19:low

i2c0:
  scl_pin: gpio.14
  sda_pin: gpio.13
spi:
  miso_pin: gpio.23
  mosi_pin: gpio.22
  sck_pin: gpio.21
oled:
  i2c_num: 0
  i2c_address: 60
  width: 128
  height: 64
  radio_delay_ms: 0
sdcard:
  card_detect_pin: NO_PIN
  # the cs pin of sd card is connected to GND (always selected),
  # and gpio.0 is unconnected to avoid potential boot problem.
  cs_pin: gpio.0:pu
  frequency_hz: 8000000

macros:
  macro0: $SD/Run=0.nc
  macro1: $SD/Run=1.nc
  macro2: $SD/Run=2.nc
  macro3: $SD/Run=3.nc

control:
  macro1_pin: gpio.36:high
  macro2_pin: gpio.39:high
  z_pause_pin: gpio.34:high
  z_origin_pin: gpio.35:high

Startup Messages

$ss
[MSG:INFO: FluidNC v3.0.x (13_16M)  (http://holyryzen/svn/FluidNC)]]
[MSG:INFO: Compiled with ESP32 SDK:v4.4.4 @ 2024-05-19 22:35:01]]
[MSG:INFO: Local filesystem type is littlefs]]
[MSG:INFO: Configuration file:xyz.yaml]]
[MSG:INFO: Machine xyz]]
[MSG:INFO: Board None]]
[MSG:INFO: SPI SCK:gpio.21 MOSI:gpio.22 MISO:gpio.23]]
[MSG:INFO: SD Card cs_pin:gpio.0:pu detect:NO_PIN freq:8000000]]
[MSG:INFO: I2C SDA: gpio.13, SCL: gpio.14, Freq: 100000, Bus #: 0]]
[MSG:INFO: OLED I2C address: 0x3c width: 128 height: 64]]
[MSG:INFO: Stepping:RMT Pulse:4us Dsbl Delay:0us Dir Delay:0us Idle Delay:255ms]]
[MSG:INFO: Axis count 3]]
[MSG:INFO: Axis X (0.000,275.000)]]
[MSG:INFO:   Motor0]]
[MSG:INFO:     standard_stepper Step:gpio.4:pd Dir:gpio.15 Disable:NO_PIN]]
[MSG:INFO:  X Neg Limit gpio.12:pd]]
[MSG:INFO: Axis Y (0.000,275.000)]]
[MSG:INFO:   Motor0]]
[MSG:INFO:     standard_stepper Step:gpio.17:pd Dir:gpio.5:low Disable:NO_PIN]]
[MSG:INFO:  Y Neg Limit gpio.16:pd]]
[MSG:INFO: Axis Z (0.000,80.000)]]
[MSG:INFO:   Motor0]]
[MSG:INFO:     standard_stepper Step:gpio.18:pd Dir:gpio.19:low Disable:NO_PIN]]
[MSG:INFO:  Z Pos Limit gpio.2:pd]]
[MSG:INFO: macro1_pin gpio.36]]
[MSG:INFO: macro2_pin gpio.39]]
[MSG:INFO: z_origin_pin gpio.35]]
[MSG:INFO: z_pause_pin gpio.34]]
[MSG:INFO: Kinematic system: Cartesian]]
[MSG:INFO: Using spindle NoSpindle]]
[MSG:INFO: STA SSID is not set]]
[MSG:INFO: AP SSID FluidNC IP 192.168.0.1 mask 255.255.255.0 channel 1]]
[MSG:INFO: AP started]]
[MSG:INFO: WiFi on]]
[MSG:INFO: Captive Portal Started]]
[MSG:INFO: HTTP started on port 80]]
[MSG:INFO: Telnet started on port 23]]
ok

User Interface Software

FluidTerm

What happened?

my goal

do homing when a button is pressed at idle or hold state.
(homing at idle or alarm state is tested fine.)

what i did

  1. run file 1.nc in sd card by pressing button (gpio.36) at state idle.
  2. pause by pressing button (gpio.34)
  3. do homing by pressing button (gpio.35)

what i expected

state changed: hold -> home
do homing

what happended instead

the state changed: hold -> idle, and nothing else.

GCode File

the file 1.nc in sd card:

G01 X275 Y275 Z0 f3000
G01 X0 Y0 Z80 f3000

Other Information

i look at wiki for a long time but can't find what i want.
i can do Ctrl+X and then run cmd $Home at console, but how can i do it programmatically?

i change some source code to add 2 new pin z_pause_pin and z_origin_pin.
the z_pause_pin works fine (pause when state=idle, resume when state=hold).
the handler of z_origin_pin is:

static void protocol_do_origin() {
    if (state_is(State::Homing) || state_is(State::Cycle) || state_is(State::Jog) || state_is(State::ConfigAlarm)) {
        log_warn("Ignore home event at state " << (uint8_t)sys.state);
        return;
    }

    // [bug] press home btn when paused
    if (!state_is(State::Idle) && !state_is(State::Alarm)) {
        log_warn("Reset before homing at state " << (uint8_t)sys.state);
        protocol_do_rt_reset();
        // why it doesn't do homing after ?
    }

    // works fine at `Idle` state
    log_info("Do homing by pin at state " << (uint8_t)sys.state);
    static char cmd[] = "$Home";
    settings_execute_line(cmd, allChannels, WebUI::AuthenticationLevel::LEVEL_ADMIN);
}

NoArgEvent originPinEvent { protocol_do_origin };
@MitchBradley
Copy link
Collaborator

The only way with the current code is to first issue $X to go from home state to idle state, then issue $H

@zengfanfan
Copy link
Author

no, it's not home state, it's hold state (on feed_hold_pin)
and $x do nothing but stuck the console.

actually i can reset the state to idle by pressing Ctrl+X, and then run $Home.
but how can i do it programmatically? why the code below doesnt work:

static void protocol_do_origin() {
    if (state_is(State::Homing) || state_is(State::Cycle) || state_is(State::Jog) || state_is(State::ConfigAlarm)) {
        log_warn("Ignore home event at state " << (uint8_t)sys.state);
        return;
    }

    // [bug] press home btn when paused
    if (!state_is(State::Idle) && !state_is(State::Alarm)) {
        log_warn("Reset before homing at state " << (uint8_t)sys.state);
        protocol_do_rt_reset();
        // why it doesn't do homing after ?
    }

    // works fine at `Idle` state
    log_info("Do homing by pin at state " << (uint8_t)sys.state);
    static char cmd[] = "$Home";
    settings_execute_line(cmd, allChannels, WebUI::AuthenticationLevel::LEVEL_ADMIN);
}

@MitchBradley
Copy link
Collaborator

Sorry, there were lots of mistakes in my post above. I just woke up and haven't had my coffee yet. I meant to say ctrl-x to get from hold to idle.

The reason your code doesn't work is probably related to the timing of the event processing. protocol_do_rt_reset() ends by sending restartEvent to be executed later. Your code is running as an event handler, so the event dispatch cannot run until your code returns.

One way to fix it might be to use the event system instead of trying to run the event handlers directly. Instead of calling protocol_do_rt_reset(), call protocol_send_event(&rtResetEvent) , Also create a event that does the homing step and send it. Then the event handler will run all the steps in sequence.

@zengfanfan
Copy link
Author

Oh, wish you a good day, Mr. Bradley .
It's midnight here.
Thank you for responding, I will try it later.

@MitchBradley
Copy link
Collaborator

I am not guaranteeing that my proposed approach will work without problems. What you are trying to do is complicated because of the historical design of the Grbl state machine. The problem is the use of reset to exit from Hold state. Grbl uses reset to do several things that have conflicting requirements:

  1. Set up the system for initial use and issue a signon message for the sender to see
  2. Immediately stop a job that is running
  3. Stop a job that is in hold state
  4. Exit from critical state after a limit alarm

Reset is a very "heavyweight" operation that reinitialized many variables - perhaps too many for some uses. I have often wanted to fix this problem, but the chances of breaking something is very high.

@zengfanfan
Copy link
Author

It's ok, any suggestion will be appreciated.
The problem is driving me crazy.

@zengfanfan
Copy link
Author

zengfanfan commented May 19, 2024

It do homing (state=home) but goes the wrong directions (all three axes wrong),
and says a few seconds later: ALARM: Homing Fail Approach.
—— the limit switch is at the other side...

Any idea?

new code:

static void protocol_do_home() {
    log_info("Handle home event at state " << (uint8_t)sys.state);
    static char cmd[] = "$Home";
    settings_execute_line(cmd, allChannels, WebUI::AuthenticationLevel::LEVEL_ADMIN);
}

static NoArgEvent homeEvent { protocol_do_home };

static void protocol_do_origin() {
    if (state_is(State::Homing) || state_is(State::Cycle) || state_is(State::Jog) || state_is(State::ConfigAlarm)) {
        log_warn("Ignore home event at state " << (uint8_t)sys.state);
        return;
    }

    // [bug] press home btn when paused
    if (!state_is(State::Idle) && !state_is(State::Alarm)) {
        log_warn("Reset before homing at state " << (uint8_t)sys.state);
        protocol_send_event(&rtResetEvent);
        // why it goes wrong direction when homing ?
    }

    // works fine at `Idle` state
    log_info("Do homing by pin at state " << (uint8_t)sys.state);
    protocol_send_event(&homeEvent);
}

NoArgEvent originPinEvent { protocol_do_origin };
NoArgEvent pausePinEvent { protocol_do_pause };

logs:

*** firmware uploaded and boot finish ***

Grbl 3.0 [FluidNC v3.0.x (noGit) (wifi) '$' for help]
[MSG:INFO: ALARM: Unhomed]
<Alarm|MPos:0.000,0.000,0.000|FS:0,0>
*** press Home button ***
[MSG:INFO: Do homing by pin at state 1]
[MSG:INFO: Handle home event at state 1]
[MSG:Homed:Z]
[MSG:Homed:XY]
*** press 1.nc button ***
[MSG:INFO: Running macro macro1: $SD/Run=1.nc]
[MSG:/sd/1.nc file job succeeded]
<Hold:0|MPos:103.198,103.198,49.980|FS:0,0>
[MSG:WARN: Reset before homing at state 5]
[MSG:INFO: Do homing by pin at state 5]
[MSG:INFO: Handle home event at state 0]

Grbl 3.0 [FluidNC v3.0.x (noGit) (wifi) '$' for help]
<Home|MPos:378.198,378.198,-30.020|FS:0,0>
[MSG:INFO: ALARM: Homing Fail Approach]
ALARM:9

@MitchBradley
Copy link
Collaborator

If you send $message/level=debug you will see more details of the homing process

@zengfanfan
Copy link
Author

zengfanfan commented May 20, 2024

It's still the timing.
If I add some delay (like 100ms), it goes the right direction.

But it stuck at settings_execute_line()->do_command_or_setting->Command::action->home_all->home->do{}while with state 'Home':

    do {
        protocol_execute_realtime();
    } while (state_is(State::Homing)); // It stuck in this loop

It never get to 'Idle' after homed xyz:

[MSG:WARN: Reset before homing at state 5]

Grbl 3.0 [FluidNC v3.0.x (16M) (wifi) '$' for help]
[MSG:INFO: Handle home event at state 0]

<Home|MPos:108.045,108.045,80.375|FS:60,0|Ov:100,100,100>
[MSG:Homed:Z]
[MSG:Homed:XY]

<Home|MPos:0.000,0.000,80.000|FS:0,0|Ov:100,100,100>

new code with delay:

static void protocol_do_home();
static NoArgEvent homeEvent { protocol_do_home };
static int64_t homeEventStart = 0;

static void protocol_do_home() {
    // wait at least 100ms, or it will home at the wrong direction.
    if (millis() - homeEventStart < 200) {
        protocol_send_event(&homeEvent);
        return;
    }

    log_info("Handle home event at state " << (uint8_t)sys.state);
    static char cmd[] = "$Home";
    settings_execute_line(cmd, allChannels, WebUI::AuthenticationLevel::LEVEL_ADMIN);
    log_info("Homed, state=" << (uint8_t)sys.state); // never get here when homing at hold state
}

static void protocol_do_origin() {
    if (state_is(State::Homing) || state_is(State::Cycle) || state_is(State::Jog) || state_is(State::ConfigAlarm)) {
        log_warn("Ignore home event at state " << (uint8_t)sys.state);
        return;
    }

    if (!state_is(State::Idle) && !state_is(State::Alarm)) {
        log_warn("Reset before homing at state " << (uint8_t)sys.state);
        protocol_send_event(&rtResetEvent);
        homeEventStart = millis();
        protocol_send_event(&homeEvent);
        return;
    }

    // log_info("Do homing by pin at state " << (uint8_t)sys.state);
    protocol_do_home();
}

NoArgEvent originPinEvent { protocol_do_origin };

@zengfanfan
Copy link
Author

I managed to fix it by creating another task with the same priority.
When button pressed, send event to the task, and the task will send event back, and do some delay between of course.

@MitchBradley
Copy link
Collaborator

MitchBradley commented May 22, 2024

You could probably do the same thing with a freertos timer. They use much less RAM than a task. There is an example in Motors/Servo.cpp

@zengfanfan
Copy link
Author

OK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants