Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5

Python API - Set multiple approach/retract as in GUI, Program events

#1
Hello everyone,

I am trying to configure a Machining item via Python API but I struggle to

1. set multiple approach/retract values as it is possible in the GUI
2. set Program Events like in https://robodk.com/doc/en/Robot-Machinin...vents.html

The .getParam() method on the name does only return b"", even if can be set.
I already tried different naming conventions (e.g. "ProgramStart", "PathApproach").
Is there a list of all the parameters and the expected formatting

Thank you and kind regards

Transformer

My current implementation
Code:
from pydantic import BaseModel, Field
from typing import List, Tuple, Optional
from enum import Enum

class SelectAlgorithm(Enum):
    MINIMUM_TOOL_ORIENTATION_CHANGE = 0
    TOOL_ORIENTATION_FOLLOWS_PATH = 1
    ROBOT_HOLDS_OBJECT = 3

class ProgramEvents(BaseModel):
    fast_move_speed: float = Field(1000.0, description="Fast move speed in mm/s")
    change_tool_id: Optional[str] = Field(None, description="Command to change tool ID")
    on_start: Optional[str] = Field(None, description="Action to take at program start")
    on_approach: Optional[str] = Field(None, description="Action to take during path approach")
    on_path_start: Optional[str] = Field(None, description="Action to take at the start of the path")
    on_point: Optional[str] = Field(None, description="Action to take on a specific point")
    on_path_finish: Optional[str] = Field(None, description="Action to take at the end of the path")
    on_retract: Optional[str] = Field(None, description="Action to take during path retraction")
    on_finish: Optional[str] = Field(None, description="Action to take at program finish")


class MachiningConfiguration(BaseModel):
    name: str = Field(..., description="Name of the machining project")
    approach: List[Tuple[str, float]] = Field(
        [("Tangent", 10.0)],
        description="List of approach types and their corresponding values (e.g., [('Tangent', 10.0), ('Normal', 100.0)])"
    )
    retract: List[Tuple[str, float]] = Field(
        [("Tangent", 10.0)],
        description="List of retract types and their corresponding values (e.g., [('Tangent', 10.0), ('Normal', 100.0)])"
    )
    select_algorithm: SelectAlgorithm = Field(SelectAlgorithm.MINIMUM_TOOL_ORIENTATION_CHANGE, description="Algorithm selection")
    program_events: ProgramEvents = Field(default_factory=ProgramEvents, description="Program events and commands")

    def configure_curve_follow(self, curve_follow):
        """
        Configure the curve_follow object using the current MachiningConfiguration parameters.

        Args:
            curve_follow: The curve_follow object to configure.
        """
        # Combine approach types and values into a single string
        approach_string = ", ".join(f"{atype} {avalue}" for atype, avalue in self.approach)
        curve_follow.setParam("Approach", approach_string)

        # Combine retract types and values into a single string
        retract_string = ", ".join(f"{rtype} {rvalue}" for rtype, rvalue in self.retract)
        curve_follow.setParam("Retract", retract_string)

        # Set the algorithm selection
        curve_follow.setParam("SelectAlgorithm", str(self.select_algorithm.value))

        # Configure machining settings, including optional parameters
        machining_settings = {"AutoUpdate": 0}

        # Add program events if they are set
        program_event_params = {
            "on_start": self.program_events.on_start,
            "on_approach": self.program_events.on_approach,
            "on_path_start": self.program_events.on_path_start,
            "on_point": self.program_events.on_point,
            "on_path_finish": self.program_events.on_path_finish,
            "on_retract": self.program_events.on_retract,
            "on_finish": self.program_events.on_finish,
        }
        for key, value in program_event_params.items():
            if value:  # Only include parameters with non-None values
                machining_settings[key] = value

        # Set the machining settings as a JSON string
        curve_follow.setParam("Machining", str(machining_settings))



# Example usage
machining_config = MachiningConfiguration(
    name="CurveFollowProject",
    approach=[("Tangent", 10.0), ("Normal", 100.0)],
    retract=[("Tangent", 10.0), ("Normal", 50.0)],
    select_algorithm=SelectAlgorithm.TOOL_ORIENTATION_FOLLOWS_PATH,
    program_events=ProgramEvents(
        fast_move_speed=1000.0,
        change_tool_id="SetTool(%2)",
        on_start="onStart",
        on_approach="onApproach",
        on_path_start="onPathStart",
        on_point="onPoint",
        on_path_finish="onPathFinish",
        on_retract="onRetract",
        on_finish="onFinish"
    )
)


Attached Files Thumbnail(s)
Screenshot 2025-01-16 132829.png   
Image(s)
   
#2
RoboDK will automatically convert your parameters as a dictionary into a JSON string when using setParam in Python. I recommend you to take a look at this example that gets and sets the robot machining parameters:
https://robodk.com/doc/en/PythonAPI/exam...g-settings

You should not convert the dictionary to a string as this will not format the parameters properly.

The same link has an example to set your desired approach/retract path strategy.
#3
Thank you, that did work. The updated script using pydantic BaseModels to make easier to do validation on the settings if one is interested.

Code:
from enum import Enum
from pydantic import BaseModel, Field, RootModel
from typing import Optional, List


# Enum for algorithm selection
class SelectAlgorithm(int, Enum):
    MINIMUM_TOOL_ORIENTATION_CHANGE = 0
    TOOL_ORIENTATION_FOLLOWS_PATH = 1
    ROBOT_HOLDS_OBJECT = 3


# Model for Approach and Retract settings
class ApproachRetractSetting(BaseModel):
    type: Optional[str] = Field(
        None, description="Approach or Retract type (e.g., 'Tangent', 'XYZ', 'ArcN')"
    )
    values: Optional[List[float]] = Field(
        None,
        description="Values associated with the type (e.g., [50] for Tangent or [50, 60, 70] for XYZ)",
    )

    def to_string(self) -> str:
        """Convert to RoboDK-compatible string format."""
        return f"{self.type} {' '.join(map(str, self.values))}"

# Model for Approach and Retract settings
class ApproachRetractSettings(RootModel):
    root: List[ApproachRetractSetting]

    def to_string(self) -> str:
        """Convert to RoboDK-compatible string format."""
        approachretrect_robodkformat:str = ""
        for approachretrect in self.root:
            approachretrect_robodkformat += approachretrect.to_string()
            approachretrect_robodkformat += ";"
        return approachretrect_robodkformat


# Machining Settings Model
class MachiningSettings(BaseModel):
    algorithm: Optional[SelectAlgorithm] = Field(
        None, alias="Algorithm", description="Algorithm selection"
    )
    approach_retract_all: Optional[int] = Field(
        None,
        alias="ApproachRetractAll",
        description="Apply approach/retract to all paths",
    )
    auto_update: Optional[int] = Field(
        None, alias="AutoUpdate", description="Enable auto-update"
    )
    avoid_collisions: Optional[int] = Field(
        None, alias="AvoidCollisions", description="Enable collision avoidance"
    )
    follow_angle: Optional[int] = Field(
        None, alias="FollowAngle", description="Angle to follow for tool orientation"
    )
    follow_angle_on: Optional[int] = Field(
        None, alias="FollowAngleOn", description="Enable follow angle"
    )
    follow_realign: Optional[int] = Field(
        None, alias="FollowRealign", description="Realign distance"
    )
    follow_realign_on: Optional[int] = Field(
        None, alias="FollowRealignOn", description="Enable follow realign"
    )
    follow_step: Optional[int] = Field(
        None, alias="FollowStep", description="Step for following"
    )
    follow_step_on: Optional[int] = Field(
        None, alias="FollowStepOn", description="Enable follow step"
    )
    join_curves_tol: Optional[float] = Field(
        None, alias="JoinCurvesTol", description="Tolerance for joining curves"
    )
    orient_xaxis_x: Optional[float] = Field(
        None, alias="OrientXaxis_X", description="X-axis orientation vector X component"
    )
    orient_xaxis_y: Optional[float] = Field(
        None, alias="OrientXaxis_Y", description="X-axis orientation vector Y component"
    )
    orient_xaxis_z: Optional[float] = Field(
        None, alias="OrientXaxis_Z", description="X-axis orientation vector Z component"
    )
    orient_xaxis2_x: Optional[float] = Field(
        None,
        alias="OrientXaxis2_X",
        description="Secondary X-axis orientation vector X component",
    )
    orient_xaxis2_y: Optional[float] = Field(
        None,
        alias="OrientXaxis2_Y",
        description="Secondary X-axis orientation vector Y component",
    )
    orient_xaxis2_z: Optional[float] = Field(
        None,
        alias="OrientXaxis2_Z",
        description="Secondary X-axis orientation vector Z component",
    )
    point_approach: Optional[float] = Field(
        None, alias="PointApproach", description="Point approach distance"
    )
    rapid_approach_retract: Optional[int] = Field(
        None, alias="RapidApproachRetract", description="Enable rapid approach/retract"
    )
    rotz_range: Optional[float] = Field(
        None, alias="RotZ_Range", description="Z-axis rotation range"
    )
    rotz_step: Optional[float] = Field(
        None, alias="RotZ_Step", description="Z-axis rotation step"
    )
    speed_operation: Optional[float] = Field(
        None, alias="SpeedOperation", description="Operation speed"
    )
    speed_rapid: Optional[float] = Field(
        None, alias="SpeedRapid", description="Rapid speed"
    )
    track_active: Optional[int] = Field(
        None, alias="TrackActive", description="Enable track"
    )
    track_offset: Optional[float] = Field(
        None, alias="TrackOffset", description="Track offset"
    )
    track_vector_x: Optional[float] = Field(
        None, alias="TrackVector_X", description="Track vector X component"
    )
    track_vector_y: Optional[float] = Field(
        None, alias="TrackVector_Y", description="Track vector Y component"
    )
    track_vector_z: Optional[float] = Field(
        None, alias="TrackVector_Z", description="Track vector Z component"
    )
    turntable_active: Optional[int] = Field(
        None, alias="TurntableActive", description="Enable turntable"
    )
    turntable_offset: Optional[float] = Field(
        None, alias="TurntableOffset", description="Turntable offset"
    )
    turntable_rzcomp: Optional[int] = Field(
        None, alias="TurntableRZcomp", description="Enable turntable RZ compensation"
    )
    visible_normals: Optional[int] = Field(
        None, alias="VisibleNormals", description="Enable visible normals"
    )

    class Config:
        populate_by_name = True


# Program Events Model
class ProgramEvents(BaseModel):
    call_action: Optional[str] = Field(
        None, alias="CallAction", description="Action for specific points"
    )
    call_action_on: Optional[int] = Field(
        None, alias="CallActionOn", description="Enable action for specific points"
    )
    call_approach: Optional[str] = Field(
        None, alias="CallApproach", description="Action at approach"
    )
    call_approach_on: Optional[int] = Field(
        None, alias="CallApproachOn", description="Enable approach action"
    )
    call_path_finish: Optional[str] = Field(
        None, alias="CallPathFinish", description="Action at path finish"
    )
    call_path_finish_on: Optional[int] = Field(
        None, alias="CallPathFinishOn", description="Enable path finish action"
    )
    call_path_start: Optional[str] = Field(
        None, alias="CallPathStart", description="Action at path start"
    )
    call_path_start_on: Optional[int] = Field(
        None, alias="CallPathStartOn", description="Enable path start action"
    )
    call_prog_finish: Optional[str] = Field(
        None, alias="CallProgFinish", description="Action at program finish"
    )
    call_prog_finish_on: Optional[int] = Field(
        None, alias="CallProgFinishOn", description="Enable program finish action"
    )
    call_prog_start: Optional[str] = Field(
        None, alias="CallProgStart", description="Action at program start"
    )
    call_prog_start_on: Optional[int] = Field(
        None, alias="CallProgStartOn", description="Enable program start action"
    )
    call_retract: Optional[str] = Field(
        None, alias="CallRetract", description="Action at retract"
    )
    call_retract_on: Optional[int] = Field(
        None, alias="CallRetractOn", description="Enable retract action"
    )
    extruder: Optional[str] = Field(
        None, alias="Extruder", description="Extruder command"
    )
    io_off: Optional[str] = Field(None, alias="IO_Off", description="IO off command")
    io_off_motion: Optional[str] = Field(
        None, alias="IO_OffMotion", description="IO off motion command"
    )
    io_on: Optional[str] = Field(None, alias="IO_On", description="IO on command")
    io_on_motion: Optional[str] = Field(
        None, alias="IO_OnMotion", description="IO on motion command"
    )
    mcode: Optional[str] = Field(None, alias="Mcode", description="M-code command")
    rapid_speed: Optional[float] = Field(
        None, alias="RapidSpeed", description="Rapid speed for motion"
    )
    rounding: Optional[float] = Field(
        None, alias="Rounding", description="Blending radius"
    )
    rounding_on: Optional[int] = Field(
        None, alias="RoundingOn", description="Enable rounding"
    )
    spindle_ccw: Optional[str] = Field(
        None, alias="SpindleCCW", description="Spindle CCW command"
    )
    spindle_cw: Optional[str] = Field(
        None, alias="SpindleCW", description="Spindle CW command"
    )
    spindle_rpm: Optional[str] = Field(
        None, alias="SpindleRPM", description="Set spindle RPM"
    )
    tool_change: Optional[str] = Field(
        None, alias="ToolChange", description="Tool change command"
    )

    class Config:
        populate_by_name = True


# Configure machining and program events
def configure_curve_follow(
    curve_follow,
    *,
    machining_settings: Optional[MachiningSettings],
    program_events: Optional[ProgramEvents],
    approach_settings: Optional[ApproachRetractSettings],
    retract_settings: Optional[ApproachRetractSettings]
):
    """
    Configure the curve follow process with machining and program event settings.

    Args:
        curve_follow: The curve follow object to configure.
        machining_settings (MachiningSettings): The machining settings model instance.
        program_events (ProgramEvents): The program events model instance.
    """
    # Configure machining settings
    if machining_settings:
        machining_dict = machining_settings.model_dump(by_alias=True, exclude_none=True)
        curve_follow.setParam("Machining", machining_dict)

    # Configure program events
    if program_events:
        program_events_dict = program_events.model_dump(by_alias=True, exclude_none=True)
        curve_follow.setParam("ProgEvents", program_events_dict)

    # Configure approach and retract
    if approach_settings:
        curve_follow.setParam("Approach", approach_settings.to_string())
   
    if retract_settings:
        curve_follow.setParam("Retract", retract_settings.to_string())

To Test ist out:
Code:
# Create machining settings and program events
machining_settings = MachiningSettings(
    algorithm=1, speed_operation=100.0, visible_normals=1
)
program_events = ProgramEvents(
    call_prog_start="ChangeTool(%TOOL%)",
    call_prog_start_on=1,
    call_path_start="SpindleOn",
    call_path_start_on=1,
    call_path_finish="SpindleOff",
    call_path_finish_on=1,
    RapidSpeed=50.0,
    Rounding=1.0,
    RoundingOn=1,
)

# Configure approach/retract settings
approach_settings = ApproachRetractSettings(root=[ApproachRetractSetting(type="Normal", values=[50]), ApproachRetractSetting(type="Tangent", values=[50])])
retract_settings = ApproachRetractSettings(root=[ApproachRetractSetting(type="Normal", values=[50]), ApproachRetractSetting(type="Tangent", values=[50])])
#4
Great, thank you for letting us know!
  




Users browsing this thread:
1 Guest(s)