Advanced Search

Search Results (Searched for: )

  • kjlty
  • kjlty
17 Dec 2024 04:55
Replied by kjlty on topic Large File Memory

Large File Memory

Category: Other User Interfaces

AXIS also takes a long time to open it, plus (AXIS, stop) is the same (BUG?), tklinuxcnc response is positive, whether it is loading G-CODE or artifact coordinate offset, but it only has 3 axes.
  • digiex_chris
  • digiex_chris
17 Dec 2024 04:34 - 17 Dec 2024 04:36

LinuxCNC-RIO - RealtimeIO for LinuxCNC based on FPGA (ICE40 / ECP5)

Category: Computers and Hardware

@meister Here is a python version of spiflash.sh that works on either the rpi4 or rpi5, except the resetting the target afterwards isn't quite working.

github.com/digiexchris/6x11-sg-grinder-l...reconfig/spiflash.py

Unloading and reloading the spi modules on the pi5 image doesn't bring /dev/spidev0,0 device back again on the pi5, so I removed that, and am just power cycling the board to reset the fpga after flashing (sudo halt, wait for it to stop, power cycle). Also it's not possible to manually toggle the state of gpio 7, becaues it's controlled by the spidev0,1 automatically. Is that why you unload and load the spi modules again on the 4, to allow you to manually control the flash chip select pin? It seems that the only thing needed for flashrom to work is just pulling the reset pin low. Not sure how to reset afterwards though. I wonder if I need to set active-low instead, and set it high to reset?

I think on a new version of the board I'm going to put a reset button to interrupt the power to the board in order to manually reset it, and perhaps put a dip switch to set it into flash mode.
  • electrosteam
  • electrosteam
17 Dec 2024 03:19
Replied by electrosteam on topic MDI and Keyboard

MDI and Keyboard

Category: Gmoccapy

Turned mill on today and now it will both jog and enter from the keyboard.
My lack of understanding may have got things wrong.

The problem tracked down to selecting Keyboard Shortcuts on the Systems Page.
If left unchecked, jog and MDI work as they should.

Keep well,
John.
  • rodw
  • rodw's Avatar
17 Dec 2024 02:45
Replied by rodw on topic Problem with homing on dual axis y

Problem with homing on dual axis y

Category: General LinuxCNC Questions

Usually when you have issues as you describe, one side is travelling the wrong way during homing.
Changing the sign on the homing velocities to negative (or posiitve) usually fixes this. Probably latch velocity.
Also slowing the homing velocities right down helps you to see what is going on.
  • Hakan
  • Hakan
17 Dec 2024 02:39
Replied by Hakan on topic AX58100

AX58100

Category: EtherCAT

I think so.
Is there anything suspicuous?

Comments.
appTimePeriod must match the SERVO_CYCLE setting in the ini file. If you go for a SERVO_CYCLE of 2ms, change appTimePeriod to 2000000 as well.
The dcConf line says the Ethercat device is running its own loop at 1 ms, synchronized by ethercat"s own internal clock. Sync0Shift says when, inside that 1 ms, the sync event takes place. 1000000 means right at the end of that 1 ms.
  • cmorley
  • cmorley
17 Dec 2024 02:38
Replied by cmorley on topic qtdragon additonal buttons

qtdragon additonal buttons

Category: Qtvcp

Did you see this:
linuxcnc.org/docs/devel/html/gui/qtvcp.h..._sheet_custom_screen
Panels are mostly the same process.

Chris
  • rodw
  • rodw's Avatar
17 Dec 2024 02:37
Replied by rodw on topic TB 6600 getting hot

TB 6600 getting hot

Category: Driver Boards

Yes, poor placemnet and lack of ventilation will casue the  driver to overheat.
Here is a drawing from Lam Technologies
 
Drives at the top of the enclosure with fan above it.

and a real install of the same drivers.
 
  • cmorley
  • cmorley
17 Dec 2024 02:21
Replied by cmorley on topic Large File Memory

Large File Memory

Category: Other User Interfaces

Could be the gcode text preview. The high lighting can be cpu intensive.
Could you post a sample large file that shows the problem?
  • rodw
  • rodw's Avatar
17 Dec 2024 02:17
Replied by rodw on topic LinuxCNC on Raspberry Pi 5

LinuxCNC on Raspberry Pi 5

Category: Installing LinuxCNC

Our image on the downloads page is already pre-shrunk, just like a well fitting pair of jeans :)
It does make a big difference in the image size
  • Cant do this anymore bye all
  • Cant do this anymore bye all's Avatar
17 Dec 2024 02:03
Replied by Cant do this anymore bye all on topic Error getting packages on fresh install on Raspberry Pi 5

Error getting packages on fresh install on Raspberry Pi 5

Category: QtPyVCP

Remember the Linuxcnc RPi images are not meant to be the same as the Official RPi images. They are not to be used as a "daily driver OS", they are solely implemented to drive a cnc machine, and if you are inclined to do some Linuxcnc development.

menu-config will do most of the same stuff as the RPi utils except for setting up the various hardware related stuff. Enabling the various hardware overlays is done by config.txt, which is really really simple as it is very well documented within the file.

There really should be a "sticky" concerning the configuring of these images, without the need to add any RPi tools. And reminding users that the images are NOT related to other RPi OS's/images and such.
  • Cant do this anymore bye all
  • Cant do this anymore bye all's Avatar
17 Dec 2024 01:56
Replied by Cant do this anymore bye all on topic LinuxCNC on Raspberry Pi 5

LinuxCNC on Raspberry Pi 5

Category: Installing LinuxCNC

I guess there's a lot of people that don't use Linux as a daily driver.

dd works fine on Linux for writing the images, or if you like the GUI route Ubuntu based distro have USB image writer which works fine every time.

Another thing I've noticed, which boils down to understanding things. The Linuxcnc images for the RPi are not related to the Official Raspberry Pi images and are not meant to be used as a "daily driver" OS, they are solely for running a CNC machine and maybe for those that want or need to building Linuxcnc.

So to use these images without any issues, don't assume that they have or need the same tools that the images from the Raspberry Pi foundation.

For reference this is the tool I've used for archiving images (one caveat I'm not a windows or mac user, I'm soley a Linux user):
github.com/Drewsif/PiShrink
  • aikiaviator
  • aikiaviator
17 Dec 2024 01:50
Replied by aikiaviator on topic To Probe Basic from Gmoccapy

To Probe Basic from Gmoccapy

Category: QtPyVCP

Fantastic. Will do. Thanks.
  • smc.collins
  • smc.collins
16 Dec 2024 23:59
Replied by smc.collins on topic Toolchanger HAL Component project

Toolchanger HAL Component project

Category: HAL Examples

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!
  • rodw
  • rodw's Avatar
16 Dec 2024 23:58
Replied by rodw on topic Homing speed slow

Homing speed slow

Category: General LinuxCNC Questions

Add a slower HOME_LATCH_VEL so you find the home switch at a high speed, then slow down for the actual homng.
  • tommylight
  • tommylight's Avatar
16 Dec 2024 23:57
Replied by tommylight on topic Linux CNC auf Virtualbox Simulation

Linux CNC auf Virtualbox Simulation

Category: Deutsch

@Agima2,
Do not report users for no reason.
Thank you.
Displaying 21541 - 21555 out of 22082 results.
Time to create page: 0.409 seconds
Powered by Kunena Forum