Toolchanger HAL Component project

More
13 Jan 2023 20:03 #261827 by smc.collins
Replied by smc.collins on topic Toolchanger HAL Component project
removed watchdog timers form execution blocks as they were superfolous, streamlining the logic of the blocks a lot, removed excess variables and bits etc to simply the logic. working on duplicating the logic for all 10 blocks now. figured out how to enable and disable the carousel with caveman logic. added some checks and changes some arguments. Cleaned up and streamlined the logic. file is truncated to 2 ready to start testing blocks, need to finish the other 8. 
Attachments:

Please Log in or Create an account to join the conversation.

More
20 Jan 2023 04:58 #262456 by smc.collins
Replied by smc.collins on topic Toolchanger HAL Component project
I am in the redesign stage, and I am actually considering standing up a small TI Dev MCU with a c++ code base that will talk to hal over serial. But it's one of many design paths I am considering, offloading the toolchanger to a micro controller using the TI RTOS on a dedicate card would solve a lot of the code complexity issues with trying to build this in a hal component.

I am open to all kinds of ideas, but this one may be the best long term.

Please Log in or Create an account to join the conversation.

More
20 Jan 2023 05:22 #262458 by spumco
Replied by spumco on topic Toolchanger HAL Component project
Just stumbled on this thread. About 90% of what you've written is over my head, but it sounds interesting.

I've got a home-made ATC I'm trying to get working and appear to be on the home stretch.  What problems have you had converting your toolchanger to LCNC that would prompt you to dive in the deep end of creating what sounds like a complicated solution?

You mentioned wanting some input or feedback?

 

Please Log in or Create an account to join the conversation.

More
20 Jan 2023 13:47 #262490 by smc.collins
Replied by smc.collins on topic Toolchanger HAL Component project
I've already written a tool changer component for my lathe, i am trying to create a universal toolchanger system inside of hal as a component orrr it may be easier to do outside of hal and Linux cnc as a stand alone device.

i have 3 mills to retrofit right now, they all have the same tool changer, i can easily build the hal component for my situation out of code I've already written and debugged.
.the issue is how to reduce the pain for myself and anyone else trying to do this, and make it universal in design.

there needs to be a better alternative than plc, gcode remapping etc

I'm also generally thinking about porting the core Linuxcnc software to a c++ library, that can be compiled anywhere..

that's another discussion for another day

Please Log in or Create an account to join the conversation.

More
10 Mar 2023 02:37 #266255 by smc.collins
Replied by smc.collins on topic Toolchanger HAL Component project
So, my plan is to create a tool changer configuration and program for each type of Mill that I own, and to slowly work towards a more universal design.

First up is my hurco slv40, I will post the files as I make progress. the only real difference between this machine and my other 2 mills is that on those machines the umbrella goes up and down, on this machine the Z goes up and down. So I have already written the macros to position it, and set up the calls to use the macros in the ini and hal file. I am working towards the rest of the program currently.

If anyone has a better way to move the Z up and down outside of a macro, I am all ears.

Please Log in or Create an account to join the conversation.

More
10 Mar 2023 05:36 - 10 Mar 2023 05:41 #266262 by spumco
Replied by spumco on topic Toolchanger HAL Component project


If anyone has a better way to move the Z up and down outside of a macro, I am all ears.
 

 

Maybe exteral offsets?  I think those can be set with hal pins, which in turn could be controlled via ladder or something else...

EDIT - not having used them, I don't know if external offsets can actually move an axis or joint.  But maybe in combination with other hal pins, perhaps something like a jog-to-position could be done.
Last edit: 10 Mar 2023 05:41 by spumco.

Please Log in or Create an account to join the conversation.

More
10 Mar 2023 05:51 #266266 by rodw
Replied by rodw on topic Toolchanger HAL Component project
External offsets works on axes 
linuxcnc.org/docs/2.9/html/motion/external-offsets.html

Have a look in detail how  QTplasmac (sim included by default with 2.9 and above) as it uses EO's to move the tool on a plasma table to the side to change consumables and return to the original position.

Please Log in or Create an account to join the conversation.

More
10 Mar 2023 20:45 - 10 Mar 2023 20:47 #266334 by smc.collins
Replied by smc.collins on topic Toolchanger HAL Component project
that's seems like a really long way around where a macro will do. the other option is to route the servo control loop through the tool change program and overide the position and encoder data when performing a toolchange, stoting the last know Z and reverting back to g28 at the end of the program.
Last edit: 10 Mar 2023 20:47 by smc.collins.
The following user(s) said Thank You: rodw

Please Log in or Create an account to join the conversation.

More
16 Dec 2024 23:59 #316822 by smc.collins
Replied by smc.collins on topic Toolchanger HAL Component project
OK, so i know a long time since my last update. I have been mega swamped with work and changed careers, finally finding some free time. I spent some time getting Chatgpt to write a bunch of boiler plate design concepts over the last few months. I know what I want to accomplish it's been a matter of How to accomplish it. I think I finally have a design concept that should work pretty much universally. where I will need help is with implementation, virtual methods are like magic to me, no idea how to use them lol. anyways here is the design concept. thoughts, feedback wanted. this is the entire conversation from chatgpt just getting it to spit out boiler plate and operational theory, do not think any of those code works it has some obvious errors but I think outlines a strong plan and method going forward for a universal tool changer program that should work for damn near anything. 


create a orchestrator program to manage multiple hal programs, considering how we can call them in a hal configuration.
ChatGPT said:ChatGPTTo create an orchestrator program that can manage multiple HAL programs dynamically (i.e., handling multiple tool changer designs like umbrella, chain, and arm types), we need to ensure the orchestrator loads the necessary HAL components and calls them in a specified order.Key Features:
  1. Modular HAL Components: Each tool changer type is implemented as a small, self-contained HAL component.
  2. Dynamic Loading: The orchestrator will load the required components based on configuration.
  3. Completion Callbacks: The orchestrator waits for a "completed" signal from each component to move on to the next one.
  4. HAL Configuration: The user can configure which tool changer types and components are used, and specify the sequence of operations.
Steps:
  1. Create a HAL component for each tool changer type (e.g., umbrella, chain, arm).
  2. Orchestrator manages the sequence and triggers the components in the correct order.
  3. Callbacks in each component signal when an operation is complete, which triggers the next step in the sequence.
Example Orchestrator Program1. Base Component InterfaceEach component (e.g., for umbrella, chain, or arm type) should have a
completed
pin, which signals the orchestrator when the operation is done. The orchestrator will look for these signals to determine when to proceed.2. Component (Move, Load, etc.) ExampleLet's define the basic HAL component (e.g.,
move
,
load
).
 c
Copy code
#include "hal.h" #include <rtapi.h> #include <rtapi_app.h> #include <string.h> // Move Component HAL Data typedef struct { hal_bit_t *start; // Input: Start the move operation hal_bit_t *done; // Output: Done signal hal_bit_t *busy; // Output: Indicate that the operation is ongoing } hal_move_t; static hal_move_t *hal_data; static void move_update(void *arg) { static int in_progress = 0; if (*(hal_data->start) && !in_progress) { rtapi_print_msg(RTAPI_MSG_INFO, "Starting move\n"); in_progress = 1; *(hal_data->busy) = 1; *(hal_data->done) = 0; rtapi_delay(1000000); // Simulated time for move (1 second) } if (in_progress) { rtapi_print_msg(RTAPI_MSG_INFO, "Move completed\n"); in_progress = 0; *(hal_data->busy) = 0; *(hal_data->done) = 1; *(hal_data->start) = 0; // Reset the start signal } } int rtapi_app_main(void) { int retval; retval = hal_init("move_block"); if (retval < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to initialize HAL component\n"); return retval; } hal_data = hal_malloc(sizeof(hal_move_t)); if (!hal_data) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to allocate HAL memory\n"); hal_exit(retval); return -1; } // Create HAL Pins retval = hal_pin_bit_new("move_block.start", HAL_IN, &(hal_data->start), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("move_block.done", HAL_OUT, &(hal_data->done), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("move_block.busy", HAL_OUT, &(hal_data->busy), hal_id()); if (retval < 0) goto error; // Register the update function retval = hal_export_funct("move_block.update", move_update, NULL, 0, 0, hal_id()); if (retval < 0) goto error; rtapi_print_msg(RTAPI_MSG_INFO, "Move Component Loaded\n"); return 0; error: hal_exit(retval); return retval; } void rtapi_app_exit(void) { hal_exit(0); }
This is a simple move block. You can similarly create other blocks (e.g., for loading a tool, moving an arm, etc.), each with its own logic and
done
signal.3. Orchestrator ProgramThe orchestrator will handle the sequence of operations, waiting for
done
signals from each component before



4o miniYou said:hold on, the orchestrator is the toolchanger program, but what we need to be able to do is have custom function blocks. for instance, the orchstrator calls a macro when it recieves a m6 tool change command, the calls a macro to move the Z axis to a specific position, once that position is reached, the macro signals that this step is completed. Now the next step is to move the tool changed umbrella under the spindle and a stop switch indicates this is complete and it signsl to the orchestrator, then the orchestrator unlocks the tool from the spindle, then a macro is called, then the umbrella rotates to position, then when it is in position, the z axis comes back to the tool insertion height, then the tool is relocked by releasing the tool lock, and on and on
ChatGPT said:ChatGPT
Memory updatedGot it! You want to create an orchestrator that manages complex tool change sequences in a tool changer system, where each step involves calling custom macros and waiting for signals (e.g., stop switches, position feedback) to indicate completion before moving to the next step.Design Breakdown
  1. Tool Change Sequence: The orchestrator manages the flow of tool change operations by calling macros and waiting for completion signals before proceeding.
  2. Steps in Sequence:
    • M6 Tool Change: Trigger a macro to initiate the tool change process.
    • Z-Axis Movement: Move the Z-axis to a specific position.
    • Move Tool Changer: Position the umbrella (or other type) under the spindle.
    • Unlock Tool: Release the tool from the spindle.
    • Rotate Tool Changer: Rotate the umbrella or tool holder to the correct position.
    • Return Z-Axis: Return the Z-axis to the tool insertion height.
    • Lock Tool: Lock the tool back into the spindle.
  3. Completion Signals: Each step is completed when a signal (e.g., stop switch, position reached, etc.) is received, or when a macro finishes execution.
Key Concept
  1. Orchestrator: The main program that handles the sequence of tool change steps. It manages the order of operations by triggering macros and waiting for completion signals.
  2. Function Blocks: Each operation (e.g.,
    move_z_axis
    ,
    rotate_umbrella
    ,
    unlock_tool
    ) is a custom block that signals completion when done.
Orchestrator Program SkeletonHere's a basic skeleton for the orchestrator program that calls macros and checks for completion signals before moving to the next step:
 c
Copy code
#include "hal.h" #include <rtapi.h> #include <rtapi_app.h> #include <string.h> typedef struct { hal_bit_t *start_tool_change; // Input: Start the tool change operation hal_bit_t *z_axis_done; // Output: Z-axis reached position hal_bit_t *tool_changed_done; // Output: Tool change completed hal_bit_t *umbrella_done; // Output: Umbrella moved to position hal_bit_t *tool_unlocked_done; // Output: Tool unlocked hal_bit_t *tool_locked_done; // Output: Tool relocked hal_bit_t *move_z_done; // Output: Z-axis return to tool change height hal_bit_t *rotate_done; // Output: Rotation completed hal_bit_t *lock_done; // Output: Lock tool in place } orchestrator_t; static orchestrator_t *hal_data; static int current_step = 0; // Tracks which step we are on // Function to simulate waiting for completion signals static void check_completion(void *arg) { switch (current_step) { case 0: // Start tool change if (*(hal_data->start_tool_change)) { rtapi_print_msg(RTAPI_MSG_INFO, "Starting tool change\n"); // Call macro for tool change initiation // wait for completion current_step++; } break; case 1: // Move Z-axis if (*(hal_data->z_axis_done)) { rtapi_print_msg(RTAPI_MSG_INFO, "Z-axis move completed\n"); current_step++; } break; case 2: // Move umbrella to position if (*(hal_data->umbrella_done)) { rtapi_print_msg(RTAPI_MSG_INFO, "Umbrella moved to position\n"); current_step++; } break; case 3: // Unlock tool if (*(hal_data->tool_unlocked_done)) { rtapi_print_msg(RTAPI_MSG_INFO, "Tool unlocked\n"); current_step++; } break; case 4: // Rotate umbrella to position if (*(hal_data->rotate_done)) { rtapi_print_msg(RTAPI_MSG_INFO, "Umbrella rotated\n"); current_step++; } break; case 5: // Return Z-axis to tool change position if (*(hal_data->move_z_done)) { rtapi_print_msg(RTAPI_MSG_INFO, "Z-axis returned to tool change height\n"); current_step++; } break; case 6: // Lock tool back in spindle if (*(hal_data->tool_locked_done)) { rtapi_print_msg(RTAPI_MSG_INFO, "Tool relocked in spindle\n"); current_step = 0; // Reset to the start *(hal_data->start_tool_change) = 0; // Reset the tool change signal } break; default: break; } } int rtapi_app_main(void) { int retval; retval = hal_init("toolchanger_orchestrator"); if (retval < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to initialize HAL component\n"); return retval; } hal_data = hal_malloc(sizeof(orchestrator_t)); if (!hal_data) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to allocate HAL memory\n"); hal_exit(retval); return -1; } // Create HAL Pins retval = hal_pin_bit_new("toolchanger_orchestrator.start_tool_change", HAL_IN, &(hal_data->start_tool_change), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("toolchanger_orchestrator.z_axis_done", HAL_OUT, &(hal_data->z_axis_done), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("toolchanger_orchestrator.tool_changed_done", HAL_OUT, &(hal_data->tool_changed_done), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("toolchanger_orchestrator.umbrella_done", HAL_OUT, &(hal_data->umbrella_done), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("toolchanger_orchestrator.tool_unlocked_done", HAL_OUT, &(hal_data->tool_unlocked_done), hal_id()); if (retval < 0)



4o miniYou said:ok, this needs to be a user definable program and each function block needs to be outside of the main program, this allows for customer tool changers and offers modulatrity. for instance. orchstrator recieves m6, then step 1 is it calls hal component #1 and that hal component is move z via macro, then when that completes it calls hal program 2, move umbrella under spindle and on and on. So we need a way to order the sub programs that are each a indepenet sub program
ChatGPT said:ChatGPTFor your tool changer orchestrator system, where each function block is a modular, user-defined program that is independent, we will structure it so that:
  1. Each Function Block is Independent: Each tool changer action (e.g., Z-axis movement, umbrella rotation, tool unlocking) will be implemented as a separate HAL component.
  2. Sequencing: The orchestrator will determine the order of these actions based on the tool changer logic and ensure each sub-program (HAL component) completes before moving on to the next.
  3. Modular & User-Definable: New tool changers can be added or existing ones modified by creating new HAL components, without changing the orchestrator.
Key Concepts
  • Main Orchestrator: Manages the flow of tool change steps. It checks completion signals from each HAL component before proceeding to the next.
  • Sub-Programs (HAL Components): Independent HAL components that implement specific actions, such as moving the Z-axis, rotating the umbrella, or unlocking a tool.
  • Ordering of Steps: The orchestrator can be configured to load and execute HAL components in a specific sequence, which can be dynamically defined by the user.
Example Structure
  1. Orchestrator: The orchestrator program reads the sequence of actions, calls each corresponding HAL component (sub-program), and waits for a completion signal before moving on to the next step.
  2. HAL Components: Each sub-program (e.g.,
    move_z
    ,
    move_umbrella
    ) is a HAL component, which handles a specific task and signals completion.
  3. Sequencer Configuration: The user can define which HAL components to load and in what order.
High-Level Flow
  1. Orchestrator Receives M6 Command:
    • Orchestrator calls HAL component #1 (e.g.,
      move_z
      ).
    • Waits for completion signal from
      move_z
      component.
    • Once
      move_z
      completes, calls HAL component #2 (e.g.,
      move_umbrella
      ).
    • Continues in this manner until all steps in the tool change sequence are completed.
  2. Each HAL Component:
    • Executes its task (e.g., move Z, move umbrella).
    • Signals completion when the task is done (via a completion signal or callback).
    • The orchestrator listens for these signals to proceed with the next step.
Example HAL Component (e.g.,
move_z
)
 c
Copy code
#include "hal.h" #include <rtapi.h> #include <rtapi_app.h> #include <string.h> // Move Z-axis HAL Data typedef struct { hal_bit_t *start; // Input: Start the move operation hal_bit_t *done; // Output: Done signal hal_bit_t *busy; // Output: Indicate that the operation is ongoing } hal_move_z_t; static hal_move_z_t *hal_data; static void move_z_update(void *arg) { static int in_progress = 0; if (*(hal_data->start) && !in_progress) { rtapi_print_msg(RTAPI_MSG_INFO, "Starting move Z\n"); in_progress = 1; *(hal_data->busy) = 1; *(hal_data->done) = 0; rtapi_delay(1000000); // Simulated time for move (1 second) } if (in_progress) { rtapi_print_msg(RTAPI_MSG_INFO, "Move Z completed\n"); in_progress = 0; *(hal_data->busy) = 0; *(hal_data->done) = 1; *(hal_data->start) = 0; // Reset the start signal } } int rtapi_app_main(void) { int retval; retval = hal_init("move_z_block"); if (retval < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to initialize HAL component\n"); return retval; } hal_data = hal_malloc(sizeof(hal_move_z_t)); if (!hal_data) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to allocate HAL memory\n"); hal_exit(retval); return -1; } // Create HAL Pins retval = hal_pin_bit_new("move_z_block.start", HAL_IN, &(hal_data->start), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("move_z_block.done", HAL_OUT, &(hal_data->done), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("move_z_block.busy", HAL_OUT, &(hal_data->busy), hal_id()); if (retval < 0) goto error; // Register the update function retval = hal_export_funct("move_z_block.update", move_z_update, NULL, 0, 0, hal_id()); if (retval < 0) goto error; rtapi_print_msg(RTAPI_MSG_INFO, "Move Z Component Loaded\n"); return 0; error: hal_exit(retval); return retval; } void rtapi_app_exit(void) { hal_exit(0); }
Orchestrator Program (Calling HAL Components in Sequence)The orchestrator will load the necessary HAL components in the correct order and check completion signals before moving to the next component.
 c
Copy code
#include "hal.h" #include <rtapi.h> #include <rtapi_app.h> #include <string.h> #define NUM_STEPS 5 // Define number of steps in the sequence typedef struct { hal_bit_t *start; // Input: Start the sequence hal_bit_t *done; // Output: Sequence completed hal_bit_t *block_done[NUM_STEPS]; // Inputs: Done signals from blocks hal_bit_t *block_start[NUM_STEPS]; // Outputs: Start signals for blocks } hal_orchestrator_t; static hal_orchestrator_t *hal_data; static int current_step = 0; static void orchestrator_update(void *arg) { if (*(hal_data->start)) { if (current_step < NUM_STEPS) { *(hal_data->block_start[current_step]) = 1; // Activate current block if (*(hal_data->block_done[current_step])) { // If block is done *(hal_data->block_start[current_step]) = 0; // Deactivate block current_step++; // Move to the next step } } else { *(hal_data->done) = 1; // Sequence completed *(hal_data->start) = 0; // Reset start signal current_step = 0; // Reset sequence } } } int rtapi_app_main(void) { int retval; retval = hal_init("orchestrator_block"); if (retval < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to initialize HAL component\n"); return retval; } hal_data = hal_malloc(sizeof(hal_orchestrator_t)); if (!hal_data) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to allocate HAL memory\n"); hal_exit(retval); return -1; } // Create HAL Pins retval = hal_pin_bit_new("orchestrator.start", HAL_IN, &(hal_data->start), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("orchestrator.done", HAL_OUT, &(hal_data->done), hal_id()); if (retval < 0) goto error; // Connect block pins (example for 5 steps) for (int i = 0; i < NUM_STEPS; i++) { char pin_name[64]; snprintf(pin_name, sizeof(pin_name), "orchestrator.block-start-%d", i); retval = hal_pin_bit_new(pin_name, HAL_OUT, &(hal_data->block_start[i]), hal_id()); if (retval < 0) goto error; snprintf(pin_name, sizeof(pin_name), "orchestrator.block-done-%d", i); retval = hal_pin_bit_new(pin_name, HAL_IN, &(hal_data->block_done[i]), hal_id()); if (retval < 0) goto error; } // Register the update function retval = hal_export_funct("orchestrator.update", orchestrator_update, NULL, 0, 0, hal_id()); if (retval < 0) goto error; rtapi_print_msg(RTAPI_MSG_INFO, "Orchestrator Component Loaded\n"); return 0; error: hal_exit(retval); return retval; } void rtapi_app_exit(void) { hal_exit(0); }
HAL ConfigurationIn your HAL configuration, you can define the sequence by connecting each block's
start
and
done
signals:
 hal
Copy code
# Define sequence control signals net orchestrator-start orchestrator.start net orchestrator-done orchestrator.done # Connect blocks net move-z-start orchestrator.block-start-0 move_z_block.start net move-z-done move_z_block.done orchestrator.block-done-0 # Continue defining the rest of the blocks (e.g., umbrella, unlock tool)
Key Points:
  1. User-defined HAL components: Each tool changer action is a separate HAL component, making the design highly modular.
  2. Orchestrator: Coordinates the sequence of steps, triggering each component and waiting for completion signals before proceeding.
  3. HAL Configuration: The user defines the sequence and configures the steps directly in the HAL file.
This setup ensures flexibility and allows users to define their tool changer logic and extend it easily with custom components. Let me know if you need further adjustments or clarification!

2/2




4o miniYou said:so how can we easily define the block order, I was thinking of numbering the logic blocks, so each component is called in order by naming the component LogicBlock or some kind of simple easy name, and how do we get the blocks to execute in order
ChatGPT said:ChatGPTTo easily define the block order and execute components in a specific sequence, you can assign each block a unique identifier (such as
LogicBlock1
,
LogicBlock2
, etc.) and then manage the order through the orchestrator program. This way, you don't need to manually configure the exact order in the HAL configuration itself; instead, the orchestrator can load and trigger blocks based on their sequence.Key Concepts:
  1. Unique Block Identifiers: Each HAL component (block) has a unique identifier such as
    LogicBlock1
    ,
    LogicBlock2
    , etc., which corresponds to a specific function (e.g., move Z, move umbrella, unlock tool, etc.).
  2. Orchestrator Logic: The orchestrator is responsible for ensuring that each block is called in the correct order. It will iterate over the blocks, trigger each one, and wait for a completion signal before moving on to the next one.
  3. Dynamic Block Management: The orchestrator will dynamically load the blocks and execute them in sequence, based on the naming convention or order provided.
Design Approach for Dynamic Execution Order:1. Naming Convention:Each function block is named sequentially, like
LogicBlock1
,
LogicBlock2
, etc. The orchestrator program can use these names to call and execute the blocks in the correct order.2. HAL Configuration:In the HAL configuration, you can define the blocks by their names and ensure that the orchestrator can easily reference and manage them.3. Orchestrator Logic:The orchestrator will:
  • Load each
    LogicBlock
    based on its name.
  • Start the block (trigger its
    start
    signal).
  • Wait for its
    done
    signal (indicating completion).
  • Move to the next block when the current block is finished.
Example:1. Block Definition (e.g.,
move_z
,
move_umbrella
, etc.)Each component (block) will have a unique name and will export
start
and
done
signals.For example, for
move_z
:
 c
Copy code
// Move Z Component (move_z) #define BLOCK_NAME "LogicBlock1" typedef struct { hal_bit_t *start; hal_bit_t *done; } hal_move_z_t; static hal_move_z_t *hal_data; static void move_z_update(void *arg) { if (*(hal_data->start)) { rtapi_print_msg(RTAPI_MSG_INFO, "Starting move Z\n"); rtapi_delay(1000000); // Simulated delay for move (1 second) *(hal_data->done) = 1; // Indicate that the operation is complete } } int rtapi_app_main(void) { int retval = hal_init(BLOCK_NAME); if (retval < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to initialize HAL component\n"); return retval; } hal_data = hal_malloc(sizeof(hal_move_z_t)); if (!hal_data) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to allocate HAL memory\n"); hal_exit(retval); return -1; } // Create HAL Pins retval = hal_pin_bit_new("move_z_block.start", HAL_IN, &(hal_data->start), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("move_z_block.done", HAL_OUT, &(hal_data->done), hal_id()); if (retval < 0) goto error; // Register the update function retval = hal_export_funct("move_z_block.update", move_z_update, NULL, 0, 0, hal_id()); if (retval < 0) goto error; rtapi_print_msg(RTAPI_MSG_INFO, "Move Z Component Loaded\n"); return 0; error: hal_exit(retval); return retval; } void rtapi_app_exit(void) { hal_exit(0); }
2. Orchestrator Program (Managing Block Order)The orchestrator will load each block in order and trigger them one by one.
 c
Copy code
#include "hal.h" #include <rtapi.h> #include <rtapi_app.h> #include <string.h> #define NUM_BLOCKS 5 // Define the total number of blocks (LogicBlock1, LogicBlock2, etc.) typedef struct { hal_bit_t *start; // Input: Start the sequence hal_bit_t *done; // Output: Sequence completed hal_bit_t *block_done[NUM_BLOCKS]; // Inputs: Done signals from blocks hal_bit_t *block_start[NUM_BLOCKS]; // Outputs: Start signals for blocks } hal_orchestrator_t; static hal_orchestrator_t *hal_data; static int current_step = 0; static void orchestrator_update(void *arg) { // Check if the sequence has started if (*(hal_data->start)) { if (current_step < NUM_BLOCKS) { // Trigger the current block *(hal_data->block_start[current_step]) = 1; // Wait for the current block to complete if (*(hal_data->block_done[current_step])) { *(hal_data->block_start[current_step]) = 0; // Deactivate current block current_step++; // Move to the next block } } else { *(hal_data->done) = 1; // Sequence completed *(hal_data->start) = 0; // Reset the start signal current_step = 0; // Reset step counter } } } int rtapi_app_main(void) { int retval; retval = hal_init("orchestrator_block"); if (retval < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to initialize HAL orchestrator\n"); return retval; } hal_data = hal_malloc(sizeof(hal_orchestrator_t)); if (!hal_data) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to allocate HAL memory\n"); hal_exit(retval); return -1; } // Create HAL Pins for orchestrator control retval = hal_pin_bit_new("orchestrator.start", HAL_IN, &(hal_data->start), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("orchestrator.done", HAL_OUT, &(hal_data->done), hal_id()); if (retval < 0) goto error; // Connect blocks by index (LogicBlock1, LogicBlock2, etc.) for (int i = 0; i < NUM_BLOCKS; i++) { char start_pin[64], done_pin[64]; // Define pins for starting blocks snprintf(start_pin, sizeof(start_pin), "orchestrator.block-start-%d", i); retval = hal_pin_bit_new(start_pin, HAL_OUT, &(hal_data->block_start[i]), hal_id()); if (retval < 0) goto error; // Define pins for block completion snprintf(done_pin, sizeof(done_pin), "orchestrator.block-done-%d", i); retval = hal_pin_bit_new(done_pin, HAL_IN, &(hal_data->block_done[i]), hal_id()); if (retval < 0) goto error; } // Register the orchestrator update function retval = hal_export_funct("orchestrator.update", orchestrator_update, NULL, 0, 0, hal_id()); if (retval < 0) goto error; rtapi_print_msg(RTAPI_MSG_INFO, "Orchestrator Component Loaded\n"); return 0; error: hal_exit(retval); return retval; } void rtapi_app_exit(void) { hal_exit(0); }
Execution Order Logic:
  1. The orchestrator calls each block in the order based on its sequence (
    LogicBlock1
    ,
    LogicBlock2
    , etc.).
  2. Each block (
    LogicBlock1
    ,
    LogicBlock2
    , etc.) has its own
    start
    and
    done
    pins.
  3. The orchestrator waits for the completion (
    done
    signal) of the current block before moving to the next.
  4. The blocks themselves will execute their functions and set the
    done
    pin when their task is completed.
Configuring the Blocks in HAL:In the HAL configuration, you can connect the components dynamically, such as:
 hal
Copy code
# Orchestrator control signals net orchestrator-start orchestrator.start net orchestrator-done orchestrator.done # Logic blocks connections net logicblock1-start orchestrator.block-start-0 move_z_block.start net logicblock1-done move_z_block.done orchestrator.block-done-0 net logicblock2-start orchestrator.block-start-1 move_umbrella_block.start net logicblock2-done move_umbrella_block.done orchestrator.block-done-1 # Continue for other blocks
Key Benefits:
  • Modular Design: New blocks (e.g.,
    LogicBlock3
    ,
    LogicBlock4
    ) can be added without modifying the orchestrator logic.
  • Easy Sequencing: Simply change the order of blocks in the orchestrator configuration, or dynamically control the sequence in the main program.
  • Scalability: New tool changers or functions can be added by defining additional blocks (e.g.,
    LogicBlockX
    ), and the orchestrator will manage their execution.
This approach provides a flexible, modular, and easily extendable system for managing complex tool changer sequences. Let me know if you need further refinements!



4o miniYou said:ok, so, we need to accomodate, no tool in spindle logic in a block, becuase if there is no tool in the spindle the machine needs to grab a tool, and we should eaither ask the user or rely on the sensor to detect empty spindle and we should ask the user at start up which tool is in the spindle
ChatGPT said:ChatGPT
Memory updatedTo accommodate the "no tool in spindle" logic, you can add an additional component or block in the orchestrator that checks for the presence of a tool in the spindle. If the spindle is empty, the system will prompt the user to select a tool or rely on a sensor to detect the tool status. Here's how you could structure the logic:Steps to Implement "No Tool in Spindle" Logic:
  1. Check for Tool Presence: Create a block that checks the tool status in the spindle. This can be done using a sensor or by prompting the user at the start to specify which tool is in the spindle.
  2. User Input at Startup: When the system starts up, ask the user to input which tool is in the spindle. If no tool is detected (or if the sensor shows an empty spindle), the system will initiate a tool change to fetch a tool.
  3. Handle Tool Change Logic: If there is no tool in the spindle, the orchestrator should handle the logic to call the necessary block to grab the tool from the tool changer.
Example Design for "No Tool in Spindle" Block:1. Tool Detection Block
 c
Copy code
// No Tool in Spindle Check (no_tool_in_spindle) #define BLOCK_NAME "LogicBlockNoToolInSpindle" typedef struct { hal_bit_t *start; hal_bit_t *done; hal_bit_t *no_tool_detected; } hal_no_tool_t; static hal_no_tool_t *hal_data; static void no_tool_in_spindle_update(void *arg) { if (*(hal_data->start)) { if (*(hal_data->no_tool_detected)) { rtapi_print_msg(RTAPI_MSG_INFO, "No tool detected in spindle. Initiating tool fetch...\n"); // Logic to initiate tool fetching sequence // This could be calling the next block (e.g., LogicBlockFetchTool) *(hal_data->done) = 1; // Signal completion of the no tool check } else { rtapi_print_msg(RTAPI_MSG_INFO, "Tool detected in spindle\n"); *(hal_data->done) = 1; // Signal completion if a tool is present } } } int rtapi_app_main(void) { int retval = hal_init(BLOCK_NAME); if (retval < 0) { rtapi_print_msg(R



4o miniYou said:the orchestrator must have this logic
ChatGPT said:ChatGPTTo integrate the "no tool in spindle" logic directly into the orchestrator, you would need to modify the orchestrator program to check for tool presence before continuing with the tool change steps. The orchestrator can then initiate the tool fetching logic if it detects that no tool is in the spindle.Here’s how you could implement this in the orchestrator, with the following logic flow:
  1. Orchestrator detects if there is no tool in the spindle (via a sensor or user input).
  2. If no tool is detected, the orchestrator will call a block to initiate the process of fetching a tool.
  3. Once the tool is fetched and inserted into the spindle, the orchestrator continues with the rest of the tool change steps.
Example Implementation:1. Define Tool Detection Logic in OrchestratorWe will modify the orchestrator to include the check for tool presence and initiate the tool-fetching sequence if necessary.Orchestrator Update Logic with Tool Detection:
 c
Copy code
#include "hal.h" #include <rtapi.h> #include <rtapi_app.h> #include <string.h> #define NUM_BLOCKS 5 // Define the total number of blocks (LogicBlock1, LogicBlock2, etc.) #define TOOL_SENSOR_PIN "tool_sensor" // The HAL pin to read tool presence (either a sensor or user-defined input) typedef struct { hal_bit_t *start; // Input: Start the sequence hal_bit_t *done; // Output: Sequence completed hal_bit_t *tool_present; // Input: Tool detection status (1 = tool present, 0 = no tool) hal_bit_t *block_done[NUM_BLOCKS]; // Inputs: Done signals from blocks hal_bit_t *block_start[NUM_BLOCKS]; // Outputs: Start signals for blocks } hal_orchestrator_t; static hal_orchestrator_t *hal_data; static int current_step = 0; // Function to check tool presence and handle the logic accordingly static void orchestrator_update(void *arg) { // If the sequence has started, proceed with the steps if (*(hal_data->start)) { if (*(hal_data->tool_present)) { // Tool detected in spindle, proceed with the tool change steps if (current_step < NUM_BLOCKS) { // Trigger the current block *(hal_data->block_start[current_step]) = 1; // Wait for the current block to complete if (*(hal_data->block_done[current_step])) { *(hal_data->block_start[current_step]) = 0; // Deactivate current block current_step++; // Move to the next block } } else { *(hal_data->done) = 1; // Sequence completed *(hal_data->start) = 0; // Reset the start signal current_step = 0; // Reset step counter } } else { // No tool in the spindle, trigger the tool fetching logic (e.g., call a specific block to fetch a tool) rtapi_print_msg(RTAPI_MSG_INFO, "No tool detected in spindle, fetching tool...\n"); // Here, you would initiate the block or logic to fetch the tool. // For example, initiate a block like LogicBlockFetchTool to handle the tool fetching process. // After fetching the tool, set tool_present to 1. *(hal_data->tool_present) = 1; // Assume tool fetching is successful after this step. *(hal_data->done) = 1; // Signal that tool fetching is complete *(hal_data->start) = 0; // Reset the start signal } } } int rtapi_app_main(void) { int retval; // Initialize HAL retval = hal_init("orchestrator_block"); if (retval < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to initialize HAL orchestrator\n"); return retval; } // Allocate memory for orchestrator data structure hal_data = hal_malloc(sizeof(hal_orchestrator_t)); if (!hal_data) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to allocate HAL memory\n"); hal_exit(retval); return -1; } // Create HAL Pins for orchestrator control retval = hal_pin_bit_new("orchestrator.start", HAL_IN, &(hal_data->start), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("orchestrator.done", HAL_OUT, &(hal_data->done), hal_id()); if (retval < 0) goto error; // Create HAL Pin for tool detection (sensor or user-defined input) retval = hal_pin_bit_new(TOOL_SENSOR_PIN, HAL_IN, &(hal_data->tool_present), hal_id()); if (retval < 0) goto error; // Connect blocks by index (LogicBlock1, LogicBlock2, etc.) for (int i = 0; i < NUM_BLOCKS; i++) { char start_pin[64], done_pin[64]; // Define pins for starting blocks snprintf(start_pin, sizeof(start_pin), "orchestrator.block-start-%d", i); retval = hal_pin_bit_new(start_pin, HAL_OUT, &(hal_data->block_start[i]), hal_id()); if (retval < 0) goto error; // Define pins for block completion snprintf(done_pin, sizeof(done_pin), "orchestrator.block-done-%d", i); retval = hal_pin_bit_new(done_pin, HAL_IN, &(hal_data->block_done[i]), hal_id()); if (retval < 0) goto error; } // Register the orchestrator update function retval = hal_export_funct("orchestrator.update", orchestrator_update, NULL, 0, 0, hal_id()); if (retval < 0) goto error; rtapi_print_msg(RTAPI_MSG_INFO, "Orchestrator Component Loaded\n"); return 0; error: hal_exit(retval); return retval; } void rtapi_app_exit(void) { hal_exit(0); }
Explanation:
  1. Tool Presence Pin: We define a HAL pin (
    tool_present
    ) that reads the tool status, either from a sensor or user input. This pin is checked at the start of the orchestrator update function.
  2. Tool Fetching Logic: If no tool is detected (
    tool_present == 0
    ), the orchestrator will initiate a tool fetching process. This could be done by calling another block (e.g.,
    LogicBlockFetchTool
    ) that handles the tool grabbing sequence.
  3. Execution Flow:
    • If a tool is present in the spindle, the orchestrator proceeds with the usual sequence of blocks (
      LogicBlock1
      ,
      LogicBlock2
      , etc.).
    • If no tool is present, the orchestrator fetches a tool, then continues with the rest of the steps once the tool is inserted into the spindle.
  4. Modular Block System: The orchestrator remains modular, with each step (e.g.,
    move_z
    ,
    move_umbrella
    ,
    tool_fetch
    ) being independent and potentially customer-defined. The order is controlled via the orchestrator's logic.
HAL Configuration:You can connect the
tool_present
input pin to the actual sensor or user-defined input in your HAL configuration.
 hal
Copy code
# Orchestrator control signals net orchestrator-start orchestrator.start net orchestrator-done orchestrator.done # Tool detection net tool-sensor-input tool_sensor tool_present # Logic blocks connections net logicblock1-start orchestrator.block-start-0 move_z_block.start net logicblock1-done move_z_block.done orchestrator.block-done-0 # Other logic blocks
Key Benefits:
  • Flexible Tool Detection: The tool presence can be managed through sensors or user input at the startup.
  • Modular and Scalable: Each block in the sequence is independent, so new tool changers or blocks can be easily added to the system.
  • Controlled Execution Flow: The orchestrator ensures that the tool is fetched if necessary before proceeding with the tool change sequence.
Let me know if you need further refinement or assistance with integration!



4o miniYou said:ok, we also need a way to communicate pocket to the orchstrator, IE the umbrella is at pocket 6 then we need a way for the orchstrator to get the current pocket, and if the pocket is unknown IE machine has started up then we must have it call a home tool changer function
ChatGPT said:ChatGPT
Memory updatedTo enable communication between the orchestrator and the umbrella tool changer regarding the current pocket, we can implement a mechanism that allows the orchestrator to query the current pocket, and if the pocket is unknown (e.g., after a machine startup), it will trigger a homing function for the tool changer.Approach:
  1. Current Pocket Detection: The orchestrator needs to get the current pocket position. This can be done by reading from a HAL pin or flag that holds the current pocket number. The value may be updated dynamically by the umbrella's position logic or set to an unknown state during startup.
  2. Home Tool Changer on Startup: If the current pocket is unknown (e.g., the system is restarted or the position is undefined), the orchestrator can call a home function for the tool changer. This function will perform a homing routine to determine the correct pocket.
Example Implementation:1. Orchestrator with Pocket Query Logic
 c
Copy code
#include "hal.h" #include <rtapi.h> #include <rtapi_app.h> #include <string.h> #define NUM_BLOCKS 5 // Define the total number of blocks (LogicBlock1, LogicBlock2, etc.) #define TOOL_SENSOR_PIN "tool_sensor" // The HAL pin to read tool presence (either a sensor or user-defined input) #define POCKET_PIN "current_pocket" // The HAL pin to read the current pocket #define HOME_TOOL_CHANGER_PIN "home_tool_changer" // The HAL pin to trigger the home function typedef struct { hal_bit_t *start; // Input: Start the sequence hal_bit_t *done; // Output: Sequence completed hal_bit_t *tool_present; // Input: Tool detection status (1 = tool present, 0 = no tool) hal_bit_t *current_pocket; // Input: Current pocket number (or unknown state) hal_bit_t *home_tool_changer; // Output: Trigger tool changer homing hal_bit_t *block_done[NUM_BLOCKS]; // Inputs: Done signals from blocks hal_bit_t *block_start[NUM_BLOCKS]; // Outputs: Start signals for blocks } hal_orchestrator_t; static hal_orchestrator_t *hal_data; static int current_step = 0; // Function to check tool presence and handle the logic accordingly static void orchestrator_update(void *arg) { // If the sequence has started, proceed with the steps if (*(hal_data->start)) { // Check if the current pocket is known if (*(hal_data->current_pocket) == 0) { // Assume 0 means unknown or uninitialized rtapi_print_msg(RTAPI_MSG_INFO, "Pocket unknown, homing tool changer...\n"); // Trigger homing function to find the pocket *(hal_data->home_tool_changer) = 1; } else { // Tool is present and pocket is known, proceed with the steps if (*(hal_data->tool_present)) { if (current_step < NUM_BLOCKS) { // Trigger the current block *(hal_data->block_start[current_step]) = 1; // Wait for the current block to complete if (*(hal_data->block_done[current_step])) { *(hal_data->block_start[current_step]) = 0; // Deactivate current block current_step++; // Move to the next block } } else { *(hal_data->done) = 1; // Sequence completed *(hal_data->start) = 0; // Reset the start signal current_step = 0; // Reset step counter } } else { // No tool in the spindle, trigger the tool fetching logic (e.g., call a specific block to fetch a tool) rtapi_print_msg(RTAPI_MSG_INFO, "No tool detected in spindle, fetching tool...\n"); // Initiate tool fetching process, then continue with tool change *(hal_data->tool_present) = 1; // Assume tool fetching is successful after this step. *(hal_data->done) = 1; // Signal that tool fetching is complete *(hal_data->start) = 0; // Reset the start signal } } } } int rtapi_app_main(void) { int retval; // Initialize HAL retval = hal_init("orchestrator_block"); if (retval < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to initialize HAL orchestrator\n"); return retval; } // Allocate memory for orchestrator data structure hal_data = hal_malloc(sizeof(hal_orchestrator_t)); if (!hal_data) { rtapi_print_msg(RTAPI_MSG_ERR, "Failed to allocate HAL memory\n"); hal_exit(retval); return -1; } // Create HAL Pins for orchestrator control retval = hal_pin_bit_new("orchestrator.start", HAL_IN, &(hal_data->start), hal_id()); if (retval < 0) goto error; retval = hal_pin_bit_new("orchestrator.done", HAL_OUT, &(hal_data->done), hal_id()); if (retval < 0) goto error; // Create HAL Pin for tool detection (sensor or user-defined input) retval = hal_pin_bit_new(TOOL_SENSOR_PIN, HAL_IN, &(hal_data->tool_present), hal_id()); if (retval < 0) goto error; // Create HAL Pin for current pocket retval = hal_pin_bit_new(POCKET_PIN, HAL_IN, &(hal_data->current_pocket), hal_id()); if (retval < 0) goto error; // Create HAL Pin for homing the tool changer retval = hal_pin_bit_new(HOME_TOOL_CHANGER_PIN, HAL_OUT, &(hal_data->home_tool_changer), hal_id()); if (retval < 0) goto error; // Connect blocks by index (LogicBlock1, LogicBlock2, etc.) for (int i = 0; i < NUM_BLOCKS; i++) { char start_pin[64], done_pin[64]; // Define pins for starting blocks snprintf(start_pin, sizeof(start_pin), "orchestrator.block-start-%d", i); retval = hal_pin_bit_new(start_pin, HAL_OUT, &(hal_data->block_start[i]), hal_id()); if (retval < 0) goto error; // Define pins for block completion snprintf(done_pin, sizeof(done_pin), "orchestrator.block-done-%d", i); retval = hal_pin_bit_new(done_pin, HAL_IN, &(hal_data->block_done[i]), hal_id()); if (retval < 0) goto error; } // Register the orchestrator update function retval = hal_export_funct("orchestrator.update", orchestrator_update, NULL, 0, 0, hal_id()); if (retval < 0) goto error; rtapi_print_msg(RTAPI_MSG_INFO, "Orchestrator Component Loaded\n"); return 0; error: hal_exit(retval); return retval; } void rtapi_app_exit(void) { hal_exit(0); }
Explanation:
  1. Current Pocket Detection:
    • The
      POCKET_PIN
      is used to get the current pocket number.
    • If the pocket is unknown (e.g., the value is
      0
      ), the orchestrator will trigger the homing process via the
      HOME_TOOL_CHANGER_PIN
      .
  2. Homing the Tool Changer:
    • The
      home_tool_changer
      pin is set when the orchestrator detects that the pocket is unknown. This triggers a homing sequence to determine the correct position of the umbrella tool changer.
    • Once homing is complete and the pocket is known, the orchestrator continues with the tool change sequence.
  3. Tool Detection:
    • The orchestrator checks if a tool is present in the spindle using the
      TOOL_SENSOR_PIN
      . If no tool is detected, it will initiate the tool-fetching logic.
  4. Modular Block System: The orchestrator continues to operate in a modular fashion, triggering and managing individual logic blocks (e.g., moving the Z-axis, rotating the umbrella, etc.).
HAL Configuration:
 hal
Copy code
# Orchestrator control signals net orchestrator-start orchestrator.start net orchestrator-done orchestrator.done # Tool detection net tool-sensor-input tool_sensor tool_present # Current pocket reading net current-pocket-input toolchanger current_pocket # Home tool changer trigger net home-tool-changer-trigger toolchanger home_tool_changer # Logic blocks connections net logicblock1-start orchestrator.block-start-0 move_z_block.start net logicblock1-done move_z_block.done orchestrator.block-done-0 # Other logic blocks
This setup provides an easy way to manage the current pocket position and ensure that the tool changer is properly homed after a machine startup or during any unknown state. Let me know if you need further modifications!

Please Log in or Create an account to join the conversation.

More
23 Dec 2024 17:32 #317209 by smc.collins
Replied by smc.collins on topic Toolchanger HAL Component project
I would like some feedback on this design.

component dynamic_sequence_executor "Dynamically executes sequences based on string input";

# Input text string
param rw string sequence "Sequence of operations (e.g., move1,macro1,carousel,move2,unlock1,marco2)";
param rw u32 max_steps "Maximum number of steps in any sequence";

# Virtual pins - we'll use a large set of pins that can be dynamically assigned
pin out bit virtual_start[100];
pin out bit virtual_stop[100];
pin out bit virtual_estop[100];
pin in bit virtual_status[100];

# State management
param rw u32 current_step "Current step in the sequence";
param rw u32 sequence_length "Number of steps in the sequence";
param rw bit running "Is the sequence currently running?";

# Function to process the sequence
function _;
function init;

license "GPL";
;;

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_VIRTUAL_STEPS 100 // Matches the pin array size
#define MAX_STEP_NAME 20 // Longest possible step name

char steps[MAX_VIRTUAL_STEPS][MAX_STEP_NAME];
int steps_count = 0;

struct StepMapping {
char name[MAX_STEP_NAME];
int index;
} step_mappings[MAX_VIRTUAL_STEPS];

int step_mapping_count = 0;

FUNCTION(_) {
if (!running) return;

if (current_step >= sequence_length) {
// Sequence finished
running = 0;
current_step = 0;
return;
}

char *current_step_name = steps[current_step];
int step_index = -1;

// Find the index of the current step in our mappings
for (int i = 0; i < step_mapping_count; i++) {
if (strcmp(step_mappings.name, current_step_name) == 0) {
step_index = step_mappings.index;
break;
}
}

if (step_index == -1) {
// Error: Step not found in mappings, you might want to handle this or log it
return;
}

// Control the step
virtual_start[step_index] = 1;
virtual_stop[step_index] = 0;
virtual_estop[step_index] = 0;

if (virtual_status[step_index]) { // If this step is complete
virtual_start[step_index] = 0;
current_step++;
}

// Emergency stop handling - check all steps
for (int i = 0; i < max_steps; i++) {
if (virtual_estop) {
running = 0;
current_step = 0;
// Reset all components to stop state
for (int j = 0; j < max_steps; j++) {
virtual_stop[j] = 1;
virtual_start[j] = 0;
}
break;
}
}
}

FUNCTION(init) {
// Parse the sequence string
char *token = strtok(sequence, ",");
steps_count = 0;
while (token != NULL && steps_count < MAX_VIRTUAL_STEPS) {
strcpy(steps[steps_count], token);

// Check if this step is already mapped, if not, add it
int found = 0;
for (int i = 0; i < step_mapping_count; i++) {
if (strcmp(step_mappings.name, token) == 0) {
found = 1;
break;
}
}
if (!found) {
strcpy(step_mappings[step_mapping_count].name, token);
step_mappings[step_mapping_count].index = step_mapping_count;
step_mapping_count++;
}

steps_count++;
token = strtok(NULL, ",");
}
sequence_length = steps_count;
current_step = 0;
running = 0;

// Set max_steps based on the number of steps in the sequence or use a default if not set
if (max_steps < steps_count) max_steps = steps_count;
}

Please Log in or Create an account to join the conversation.

Time to create page: 0.112 seconds
Powered by Kunena Forum