RSI-PI/src/RSIPI/krl_api.py
Adam a131ba4df8 Implement Phase 1 & Phase 5: Code quality improvements and namespaced API architecture
Major refactoring to improve code quality, maintainability, and API organization
for publication-quality research software.

Phase 1 - Code Quality Foundation:
- Add comprehensive type hints across all core modules (500+ annotations)
- Create custom exception hierarchy with 20+ specialized exceptions
- Replace all print() statements with proper logging (debug, info, warning, error, critical)
- Enhance all docstrings with Args/Returns/Raises sections
- Improve error handling with exception chaining

Modified core modules:
- rsi_client.py: State machine with typed exceptions, full type hints
- network_handler.py: CSV logging and UDP communication with typed interfaces
- config_parser.py: XML parsing with proper exception handling
- safety_manager.py: Safety validation with typed limits
- __init__.py: Clean exports for all public APIs

Phase 5 - Namespaced API Architecture:
- Restructure RSIAPI as orchestrator providing 9 specialized namespaces
- Create clean separation of concerns with dedicated API classes

New namespace APIs:
- motion_api.py: Motion control (Cartesian, joints, trajectories)
- io_api.py: Digital I/O control
- krl_api.py: KRL program manipulation utilities
- safety_api.py: Safety management and limits
- monitoring_api.py: Live data access and monitoring
- logging_api.py: CSV data logging
- diagnostics_api.py: Network diagnostics (Phase 2 placeholder)
- viz_api.py: Static and live visualization
- tools_api.py: Utilities, debugging, inspection

Breaking Changes:
- No backward compatibility - clean slate API design
- Old: api.start_rsi() → New: api.start()
- Old: api.update_cartesian(...) → New: api.motion.update_cartesian(...)
- See migration guide in PHASE_5_SUMMARY.md

Benefits:
- Organized and discoverable API structure
- Scalable architecture for future enhancements
- Type-safe with full IDE autocomplete support
- Easier testing and maintenance
- Professional industry-standard design pattern

Files changed: 6 modified, 9 new (net -37 lines, improved organization)
2026-01-16 23:49:45 +00:00

134 lines
4.7 KiB
Python

"""KRL program manipulation API namespace for RSIPI."""
import logging
from typing import Optional, TYPE_CHECKING
if TYPE_CHECKING:
from .rsi_client import RSIClient
class KRLAPI:
"""
KUKA Robot Language (KRL) program manipulation interface.
Provides utilities for parsing KRL programs, extracting coordinate data,
and injecting RSI control commands into existing KRL workflows.
"""
def __init__(self, client: 'RSIClient') -> None:
"""
Initialize KRLAPI namespace.
Args:
client: RSIClient instance (currently unused, reserved for future features)
"""
self.client = client
@staticmethod
def parse_to_csv(src_file: str, dat_file: str, output_file: str) -> str:
"""
Parse KRL source and data files, extract coordinates to CSV.
Reads .src (program logic) and .dat (position data) files, extracts
point definitions and movement commands, and exports to CSV format.
Args:
src_file: Path to KRL .src program file
dat_file: Path to KRL .dat data file
output_file: Path for output CSV file
Returns:
Status message indicating success or failure
Raises:
FileNotFoundError: If source or data files don't exist
Exception: If parsing fails
Example:
>>> api.krl.parse_to_csv('robot_prog.src', 'robot_prog.dat', 'output.csv')
'KRL data successfully exported to output.csv'
Note:
The parser extracts position data (E6POS, E6AXIS, FRAME) from the
.dat file and matches them with movement commands (PTP, LIN, CIRC)
from the .src file.
"""
try:
from .krl_to_csv_parser import KRLParser
parser = KRLParser(src_file, dat_file)
parser.parse_src()
parser.parse_dat()
parser.export_csv(output_file)
logging.info(f"KRL data exported to {output_file}")
return f"KRL data successfully exported to {output_file}"
except Exception as e:
logging.error(f"KRL parsing failed: {e}")
return f"Error parsing KRL files: {e}"
@staticmethod
def inject_rsi(input_krl: str, output_krl: Optional[str] = None, rsi_config: str = "RSIGatewayv1.rsi") -> str:
"""
Inject RSI control commands into a KRL program.
Automatically modifies a KRL .src file to include RSI initialization,
sensor communication, and cleanup code. This allows adding real-time
external control to existing robot programs.
Args:
input_krl: Path to input KRL .src file
output_krl: Optional output path (defaults to overwriting input)
rsi_config: RSI configuration file name (default: 'RSIGatewayv1.rsi')
Returns:
Status message indicating success or failure
Raises:
FileNotFoundError: If input KRL file doesn't exist
Exception: If injection fails
Example:
>>> # Modify in place
>>> api.krl.inject_rsi('robot_prog.src')
'RSI successfully injected into robot_prog.src'
>>> # Create new file
>>> api.krl.inject_rsi('robot_prog.src', 'robot_prog_rsi.src')
'RSI successfully injected into robot_prog_rsi.src'
Note:
The injection adds:
- RSI_CREATE() at program start
- RSI_ON() before motion commands
- RSI_MOVECORR() during movement
- RSI_OFF() after motion
This allows Python to send corrections during program execution.
"""
try:
from .inject_rsi_to_krl import inject_rsi_to_krl
inject_rsi_to_krl(input_krl, output_krl, rsi_config)
output_path = output_krl if output_krl else input_krl
logging.info(f"RSI injected into {output_path}")
return f"RSI successfully injected into {output_path}"
except Exception as e:
logging.error(f"RSI injection failed: {e}")
return f"RSI injection failed: {e}"
# TODO (Phase 3): Implement KRL coordination helpers
# def wait_for_signal(self, channel: int, timeout: float = 5.0) -> bool:
# """Wait for KRL to set a specific I/O signal."""
# pass
#
# def signal_complete(self, channel: int) -> None:
# """Signal to KRL that Python-side operation is complete."""
# pass
#
# def write_param(self, slot: str, value: float) -> str:
# """Write parameter to Tech.C variable for KRL to read."""
# pass
#
# def read_param(self, slot: str) -> float:
# """Read parameter from Tech.T variable written by KRL."""
# pass