### Set and Get Registers with MotionController Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/communication.md This example demonstrates how to connect to a servo drive using its IP address and a dictionary file, then set a register value and retrieve another. It utilizes the MotionController class from the ingeniamotion library. Ensure the correct IP address and dictionary path are provided. ```python import argparse from ingeniamotion import MotionController def main(args): mc = MotionController() mc.communication.connect_servo_eoe(args.ip, args.dictionary_path) mc.communication.set_register("DRV_PROT_USER_OVER_VOLT", 60) volt = mc.communication.get_register("DRV_PROT_VBUS_VALUE") print("Current voltage is", volt) mc.communication.disconnect() def setup_command(): parser = argparse.ArgumentParser(description="Disturbance example") parser.add_argument("--dictionary_path", help="Path to drive dictionary", required=True) parser.add_argument("--ip", help="Drive IP address", required=True) return parser.parse_args() if __name__ == "__main__": args = setup_command() main(args) ``` -------------------------------- ### Save and Load Drive Configuration with Python Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/configuration.md This Python script shows how to save the current configuration of an IngeniaMotion drive to a file and then load it back. It utilizes the MotionController to establish an EtherCAT connection and then calls save_configuration and load_configuration methods. Ensure the 'ingeniamotion' library is installed. ```python from ingeniamotion import MotionController def main() -> None: mc = MotionController() # Modify these parameters to connect a drive interface_index = 3 slave_id = 1 dictionary_path = "parent_directory/dictionary_file.xdf" mc.communication.connect_servo_ethercat_interface_index( interface_index, slave_id, dictionary_path ) # Save the configuration of your drive in a file config_path = "configuration.xcf" mc.configuration.save_configuration(config_path) print("The configuration is saved.") # Load the configuration file made previously mc.configuration.load_configuration(config_path) mc.communication.disconnect() if __name__ == "__main__": main() ``` -------------------------------- ### Install Project Dependencies with Poetry Source: https://github.com/ingeniamc/ingeniamotion/blob/master/README.md Installs all the dependencies required for the project, including optional extras like 'fsoe'. The '--all-groups' flag ensures all defined dependency groups are installed. ```bash poetry install --all-groups ``` -------------------------------- ### Save, Modify, and Load Configuration with Python Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/configuration.md This Python example demonstrates saving an initial drive configuration, modifying a specific parameter (maximum velocity), saving the modified configuration, and then loading both configurations to verify changes. It requires the 'ingeniamotion' library and establishes an EtherCAT connection. ```python from ingeniamotion import MotionController def main() -> None: mc = MotionController() # Modify these parameters to connect a drive interface_index = 3 slave_id = 1 dictionary_path = "parent_directory/dictionary_file.xdf" mc.communication.connect_servo_ethercat_interface_index( interface_index, slave_id, dictionary_path ) # Save the initial configuration of your drive in a file initial_config_path = "initial_configuration.xcf" mc.configuration.save_configuration(initial_config_path) print("The initial configuration is saved.") # Get the initial max. velocity and set it with a new value new_max_velocity = 20.0 initial_max_velocity = mc.configuration.get_max_velocity() if new_max_velocity == initial_max_velocity: print("This max. velocity value is already set.") mc.communication.disconnect() return mc.configuration.set_max_velocity(new_max_velocity) # Save the configuration with changes in a file modified_config_path = "configuration_example.xcf" mc.configuration.save_configuration(modified_config_path) print("The configuration file is saved with the modification.") # Load the initial configuration and check the max. velocity register has its initial value mc.configuration.load_configuration(initial_config_path) print( f"Max. velocity register should be set to its initial value ({initial_max_velocity}). " f"Current value: {mc.configuration.get_max_velocity()}" ) # Load the modified configuration and check the max. velocity value is changed again mc.configuration.load_configuration(modified_config_path) print( f"Max. velocity register should now be set to the new value ({new_max_velocity}). " f"Current value: {mc.configuration.get_max_velocity()}" ) mc.communication.disconnect() if __name__ == "__main__": main() ``` -------------------------------- ### Install Ingeniamotion with FSoE Extra using Poetry Source: https://github.com/ingeniamc/ingeniamotion/blob/master/README.md Installs the Ingeniamotion library with the 'FSoE' (Fail-Safe over EtherCAT) extra dependencies. This is an optional installation for specific functionalities. ```bash poetry install --extras fsoe ``` -------------------------------- ### Install Ingeniamotion Library using Pip Source: https://github.com/ingeniamc/ingeniamotion/blob/master/README.md This command installs the Ingeniamotion library using pip, the standard Python package installer. Ensure you have Python 3.9 or higher installed. ```bash pip install ingeniamotion ``` -------------------------------- ### Monitoring Example: Capture Triggered Data with IngeniaMotion Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/capture.md This example demonstrates how to set up and capture data using the monitoring feature of IngeniaMotion. It allows capturing data around a specific trigger event, with configurable parameters for prescaler, total time, and trigger mode. It requires drive connection details and plots the captured data. ```python import argparse import logging import numpy as np import matplotlib.pyplot as plt from ingeniamotion import MotionController from ingeniamotion.enums import MonitoringSoCType, MonitoringSoCConfig logging.basicConfig(level=logging.DEBUG) logging.getLogger("matplotlib.font_manager").disabled = True def main(args): mc = MotionController() mc.communication.connect_servo_eoe(args.ip, args.dictionary_path) # Monitoring registers registers = [{"axis": 1, "name": "CL_POS_FBK_VALUE"}, {"axis": 1, "name": "CL_VEL_FBK_VALUE"}] # Servo frequency divisor to set monitoring frequency monitoring_prescaler = 25 total_time_s = 1 # Total sample time in seconds trigger_delay_s = 0.0 # Trigger delay time in seconds trigger_mode = MonitoringSoCType.TRIGGER_EVENT_AUTO # trigger_mode = MonitoringSoCType.TRIGGER_EVENT_EDGE trigger_config = None # trigger_config = MonitoringSoCConfig.TRIGGER_CONFIG_RISING # trigger_config = MonitoringSoCConfig.TRIGGER_CONFIG_FALLING # Trigger signal register if trigger_mode is TRIGGER_CYCLIC_RISING_EDGE or TRIGGER_CYCLIC_FALLING_EDGE # else, it does nothing trigger_signal = {"axis": 1, "name": "CL_POS_FBK_VALUE"} # Trigger value if trigger_mode is TRIGGER_CYCLIC_RISING_EDGE or TRIGGER_CYCLIC_FALLING_EDGE # else, it does nothing trigger_value = 0 monitoring = mc.capture.create_monitoring( registers, monitoring_prescaler, total_time_s, trigger_delay=trigger_delay_s, trigger_mode=trigger_mode, trigger_config=trigger_config, trigger_signal=trigger_signal, trigger_value=trigger_value, ) # Enable Monitoring mc.capture.enable_monitoring() print("Waiting for trigger") # Blocking function to read monitoring values data = monitoring.read_monitoring_data() print("Triggered and data read!") # Calculate abscissa values with total_time_s and trigger_delay_s x_start = -total_time_s / 2 + trigger_delay_s x_end = total_time_s / 2 + trigger_delay_s x_values = np.linspace(x_start, x_end, len(data[0])) # Plot result fig, axs = plt.subplots(2) for index in range(len(axs)): ax = axs[index] ax.plot(x_values, data[index]) ax.set_title(registers[index]["name"]) plt.autoscale() if args.close: plt.show(block=False) plt.pause(5) plt.close() else: plt.show() plt.show() mc.communication.disconnect() def setup_command(): parser = argparse.ArgumentParser(description="Disturbance example") parser.add_argument("--dictionary_path", help="Path to drive dictionary", required=True) parser.add_argument("--ip", help="Drive IP address", required=True) parser.add_argument("--close", help="Close plot after 5 seconds", action="store_true") return parser.parse_args() if __name__ == "__main__": args = setup_command() main(args) ``` -------------------------------- ### Integer Bit Length Example (Python) Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/configuration.md Demonstrates how to get the number of bits necessary to represent an integer in binary using the `bit_length()` method. This is useful for understanding the binary representation of numbers. ```python >>> bin(37) '0b100101' >>> (37).bit_length() 6 ``` -------------------------------- ### Load Firmware to EtherCAT Interface with MotionController Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/communication.md This example demonstrates how to load firmware onto an EtherCAT interface using the MotionController. It requires the network interface index, the slave ID of the device, and the path to the firmware file. The script first prints available interface names to help the user identify the correct index. ```python import argparse import ingeniamotion def main(args): # Create MotionController instance mc = ingeniamotion.MotionController() # Print infame list to get ifname index print(mc.communication.get_interface_name_list()) # Load firmware mc.communication.load_firmware_ecat_interface_index( args.interface_index, # ifname index args.firmware_file, # FW file args.slave_id, ) # Slave index def setup_command(): parser = argparse.ArgumentParser(description="Disturbance example") parser.add_argument("--interface_index", help="Network adapter inteface index", required=True) parser.add_argument("--slave_id", help="Drive slave ID", required=True) parser.add_argument("--firmware_file", help="Firmware file to be loaded", required=True) return parser.parse_args() if __name__ == "__main__": args = setup_command() main(args) ``` -------------------------------- ### Position Ramp Control with IngeniaMotion (Python) Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/motion.md This example demonstrates how to control motor position using IngeniaMotion with a trapezoidal profiler. It connects to a motion controller via EtherCAT, sets the operation mode to PROFILE_POSITION, configures maximum velocity and acceleration/deceleration, enables the motor, and then moves the motor to a series of target positions. The example includes printing the actual position after each move and disabling the motor before disconnecting. It requires the `ingeniamotion` library. ```python from ingeniamotion import MotionController from ingeniamotion.enums import OperationMode def main() -> None: mc = MotionController() ip = "192.168.2.1" slave_id = 1 dictionary_path = "parent_directory/dictionary_file.xdf" mc.communication.connect_servo_ethercat_interface_ip(ip, slave_id, dictionary_path) # Select the position mode and trapezoidal profiler mc.motion.set_operation_mode(OperationMode.PROFILE_POSITION) # Set all registers needed before activating the trapezoidal profiler mc.configuration.set_max_profile_velocity(5.0) max_acceleration_deceleration = 2.0 mc.configuration.set_max_profile_acceleration(max_acceleration_deceleration) mc.configuration.set_max_profile_deceleration(max_acceleration_deceleration) # Enable the motor mc.motion.motor_enable() target_positions = [1500, 3000, 0] for current_target in target_positions: mc.motion.move_to_position(current_target, blocking=True, timeout=2.0) actual_position = mc.motion.get_actual_position() print(f"Actual position: {actual_position}") # Disable the motor mc.motion.motor_disable() mc.communication.disconnect() if __name__ == "__main__": # Make sure the drive is properly configured and connected to a motor main() ``` -------------------------------- ### STO Example with Ingeniamotion FSoE Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/fsoe.md This Python script demonstrates how to use the Ingeniamotion library to establish an FSoE connection, configure safety mappings, and perform a Safety Torque Off (STO) sequence. It includes error handling, communication setup, and motor control operations. Dependencies include the ingeniamotion library and standard Python modules like argparse and contextlib. ```python import argparse import contextlib from ingeniamotion import MotionController from ingeniamotion.enums import OperationMode from ingeniamotion.exceptions import IMTimeoutError from ingeniamotion.fsoe import FSOE_MASTER_INSTALLED if FSOE_MASTER_INSTALLED: from ingeniamotion.fsoe_master import ( FSoEMasterHandler, SafeInputsFunction, SS1Function, STOFunction, ) def _error_callback(error): print(error) def _set_default_mapping(handler: "FSoEMasterHandler") -> None: sto = handler.get_function_instance(STOFunction) safe_inputs = handler.get_function_instance(SafeInputsFunction) ss1 = handler.get_function_instance(SS1Function) handler.process_image.inputs.clear() handler.process_image.inputs.add(sto.command) handler.process_image.inputs.add(ss1.command) handler.process_image.inputs.add_padding(6) handler.process_image.inputs.add(safe_inputs.value) handler.process_image.inputs.add_padding(7) handler.process_image.outputs.clear() handler.process_image.outputs.add(sto.command) handler.process_image.outputs.add(ss1.command) handler.process_image.outputs.add_padding(6) def main(ifname, slave_id, dict_path, config_file=None): """Establish a FSoE connection, deactivate the STO and move the motor.""" mc = MotionController() # Configure error channel mc.fsoe.subscribe_to_errors(_error_callback) # Connect to the servo drive mc.communication.connect_servo_ethercat(ifname, slave_id, dict_path) # Load configuration if provided if config_file is not None: try: mc.configuration.load_configuration(config_file) except Exception as e: print(f"There was an error loading the configuration: {e}") mc.communication.disconnect() return current_operation_mode = mc.motion.get_operation_mode() # Set the Operation mode to Velocity mc.motion.set_operation_mode(OperationMode.VELOCITY) # Create and start the FSoE master handler handler = mc.fsoe.create_fsoe_master_handler(use_sra=True) # Set default mapping if editable if handler.process_image.editable: _set_default_mapping(handler=handler) if handler.sout_function(): handler.sout_disable() try: mc.fsoe.configure_pdos(start_pdos=True, start_master=True) # Wait for the master to reach the Data state mc.fsoe.wait_for_state_data(timeout=5) # Remove fail-safe mode. Output commands will be applied by the slaves mc.fsoe.set_fail_safe(False) # Deactivate the SS1 mc.fsoe.ss1_deactivate() # Deactivate the STO mc.fsoe.sto_deactivate() # Wait for the STO to be deactivated while mc.fsoe.check_sto_active(): pass # Enable the motor mc.motion.motor_enable() # Wait for the motor to reach a certain velocity (10 rev/s) target_velocity = 10 mc.motion.set_velocity(target_velocity) with contextlib.suppress(IMTimeoutError): mc.motion.wait_for_velocity(velocity=target_velocity, timeout=10) # Disable the motor mc.motion.motor_disable() # Activate the SS1 mc.fsoe.ss1_activate() # Activate the STO mc.fsoe.sto_activate() # Restore fail safe mc.fsoe.set_fail_safe(True) except Exception as e: print(e) finally: try: # Stop the FSoE master handler if mc.capture.pdo.is_active: mc.fsoe.stop_master(stop_pdos=True) finally: # Restore the operation mode mc.motion.set_operation_mode(current_operation_mode) # Disconnect from the servo drive mc.communication.disconnect() if __name__ == "__main__": # Modify these parameters according to your setup parser = argparse.ArgumentParser(description="Safety Torque Off Example") parser.add_argument( "--ifname", help="Interface name ``\Device\NPF_[...]``", required=True, type=str ) parser.add_argument( "--slave_id", help="Path to drive dictionary", required=False, default=1, type=int ) parser.add_argument( "--dictionary_path", help="Path to drive dictionary", required=True, type=str ) parser.add_argument( "--configuration_file", help="Path to configuration file", required=False, type=str, default=None, ) args = parser.parse_args() main(args.ifname, args.slave_id, args.dictionary_path, args.configuration_file) ``` -------------------------------- ### Install Poetry for Virtual Environment Management Source: https://github.com/ingeniamc/ingeniamotion/blob/master/README.md Installs Poetry, a tool for dependency management and packaging in Python. This is used to manage project dependencies and virtual environments. ```bash pip install poetry ``` -------------------------------- ### Connect to CANopen Drive with MotionController Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/communication.md This example shows how to connect to a CANopen drive using the MotionController. It includes scanning for available node IDs on a specified CAN bus and then connecting to a specific node. The code requires the path to the drive dictionary, node ID, CAN transceiver type, baud rate, and channel. ```python import argparse from ingeniamotion import MotionController from ingeniamotion.enums import CanBaudrate, CanDevice def main(args): # Create MotionController instance mc = MotionController() # Get list of all node id available can_device = CanDevice(args.can_transceiver) can_baudrate = CanBaudrate(args.can_baudrate) can_channel = args.can_channel node_id_list = mc.communication.scan_servos_canopen(can_device, can_baudrate, can_channel) if len(node_id_list) > 0: # Connect to servo with CANOpen mc.communication.connect_servo_canopen( can_device, args.dictionary_path, args.node_id, can_baudrate, can_channel ) print("Servo connected!") # Disconnect servo, this lines is mandatory mc.communication.disconnect() else: print("No node id available") def setup_command(): parser = argparse.ArgumentParser(description="Canopen example") parser.add_argument("--dictionary_path", help="Path to drive dictionary", required=True) parser.add_argument("--node_id", default=32, type=int, help="Node ID") parser.add_argument( "--can_transceiver", default="ixxat", choices=["pcan", "kvaser", "ixxat"], help="CAN transceiver", ) parser.add_argument( "--can_baudrate", default=1000000, type=int, choices=[50000, 100000, 125000, 250000, 500000, 1000000], help="CAN baudrate", ) parser.add_argument("--can_channel", default=0, type=int, help="CAN transceiver channel") return parser.parse_args() if __name__ == "__main__": args = setup_command() main(args) ``` -------------------------------- ### Start PDOPoller in Python Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/capture.md Initiates the polling process for a PDOPoller instance. This method is crucial for beginning the collection of process data. Ensure the PDOPoller is properly configured before calling start. ```python from ingeniamotion.pdo import PDOPoller # Assuming poller is an instance of PDOPoller poller.start() ``` -------------------------------- ### Polling Example: Capture and Plot Data with IngeniaMotion Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/capture.md This example demonstrates how to continuously poll data from specified registers using the MotionController and visualize it in real-time using Matplotlib. It requires a drive IP address and the path to the drive dictionary. The plot can be optionally closed after a delay. ```python import argparse import matplotlib.pyplot as plt import matplotlib.animation as animation from ingeniamotion import MotionController def main(args): mc = MotionController() mc.communication.connect_servo_eoe(args.ip, args.dictionary_path) # List of registers registers = [ { "name": "CL_POS_FBK_VALUE", # Register name "axis": 1, # Register axis }, ] # Create Poller with our registers poller = mc.capture.create_poller(registers) # PLOT DATA fig, ax = plt.subplots() global x_values, y_values x_values = [] y_values = [] (line,) = ax.plot(x_values, y_values) def animate(i): timestamp, registers_values, _ = poller.data # Read Poller data global x_values, y_values x_values += timestamp y_values += registers_values[0] line.set_data(x_values, y_values) ax.relim() ax.autoscale_view() return (line,) ani = animation.FuncAnimation(fig, animate, interval=100) plt.autoscale() if args.close: plt.show(block=False) plt.pause(5) plt.close() else: plt.show() poller.stop() mc.communication.disconnect() def setup_command(): parser = argparse.ArgumentParser(description="Disturbance example") parser.add_argument("--dictionary_path", help="Path to drive dictionary", required=True) parser.add_argument("--ip", help="Drive IP address", required=True) parser.add_argument("--close", help="Close plot after 5 seconds", action="store_true") return parser.parse_args() if __name__ == "__main__": args = setup_command() main(args) ``` -------------------------------- ### Velocity and Torque Ramp Control with IngeniaMotion (Python) Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/motion.md This example demonstrates how to control motor velocity and torque using IngeniaMotion. It includes functions for setting up command-line arguments, performing velocity ramps, and executing torque ramps. The code connects to a motion controller, sets operation modes, enables the motor, and then executes either a velocity or torque demo based on user input. It requires the `ingeniamotion` and `ingentialink` libraries. ```python import time import logging import argparse from ingeniamotion import MotionController from ingeniamotion.enums import OperationMode from ingentialink.exceptions import ILError # Set your motor torque constant TORQUE_CONSTANT = 0.0376 def setup_command(): parser = argparse.ArgumentParser(description="Run feedback test") parser.add_argument("demo", help="Run demo", choices=["velocity", "torque"]) parser.add_argument("dictionary_path", help="path to drive dictionary") parser.add_argument("-ip", default="192.168.2.22", help="drive ip address") parser.add_argument("-target_torque", default=0.706, help="Target torque", type=float) return parser.parse_args() def velocity_ramp(final_velocity, acceleration, mc): """ Creates a velocity ramp from current velocity to ``final_velocity`` with ``acceleration`` as a ramp slope. Args: final_velocity: target velocity in rev/s. acceleration: acceleration in rev/s^2. mc: MotionController instance. """ done = False mc.configuration.set_max_profile_acceleration(acceleration) mc.motion.set_velocity(final_velocity) while not done: try: mc.motion.wait_for_velocity(final_velocity) done = True except ILError: pass def torque_ramp(final_torque, rotatum, torque_constant, mc): """ Creates a torque ramp from 0 to ``final_torque`` with ``rotatum`` as a ramp slope. Args: final_torque: target torque in Nm. rotatum: torque derivative in Nm/s. torque_constant: motor torque constant. mc: MotionController instance. """ torque = 0 torque_constant = torque_constant init_time = time.time() while torque < final_torque: try: torque = (time.time() - init_time) * rotatum current = torque / torque_constant mc.motion.set_current_quadrature(current) except ILError: pass def velocity_demo(mc): wait_in_seconds = 40 target_velocity = [16.667, 66.667, 0] acceleration = [0.1667, 0.8333, 20] mc.motion.set_operation_mode(OperationMode.PROFILE_VELOCITY) mc.configuration.set_max_velocity(70) mc.motion.motor_enable() velocity_ramp(target_velocity[0], acceleration[0], mc) velocity_ramp(target_velocity[1], acceleration[1], mc) time.sleep(wait_in_seconds) velocity_ramp(target_velocity[2], acceleration[2], mc) mc.motion.motor_disable() def torque_demo(mc, target_torque): rotatum = 0.0035 mc.motion.set_operation_mode(OperationMode.CURRENT) mc.motion.motor_enable() torque_ramp(target_torque, rotatum, TORQUE_CONSTANT, mc) mc.motion.set_current_quadrature(0) mc.motion.motor_disable() def main(args): mc = MotionController() mc.communication.connect_servo_eoe(args.ip, args.dictionary_path) if args.demo == "velocity": velocity_demo(mc) elif args.demo == "torque": torque_demo(mc, args.target_torque) else: logging.error("Demo {} does not exist".format(args.demo)) mc.communication.disconnect() if __name__ == "__main__": logging.basicConfig(level=logging.INFO) args = setup_command() main(args) ``` -------------------------------- ### Start PDOs with PDONetworkManager in Python Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/capture.md Initiates the transmission and reception of Process Data Objects (PDOs) across the network using the PDONetworkManager. This method typically starts the PDO communication cycle for configured networks. ```python from ingeniamotion.pdo import PDONetworkManager # Assuming manager is an instance of PDONetworkManager manager.start_pdos() ``` -------------------------------- ### Start PDO Exchange Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/capture/pdo.md Initiates the PDO exchange process for servos on a specified network. This action affects all servos connected to the same network. ```APIDOC ## POST /ingeniamc/ingeniamotion/start_pdos ### Description Starts the PDO exchange process for servos on a specified network. This action affects all servos connected to the same network. ### Method POST ### Endpoint /ingeniamc/ingeniamotion/start_pdos ### Parameters #### Query Parameters - **network_type** (CommunicationType) - Optional - Network type (EtherCAT or CANopen) on which to start the PDO exchange. - **refresh_rate** (float) - Optional - Determines how often (seconds) the PDO values will be updated. - **watchdog_timeout** (float) - Optional - The PDO watchdog time. If not provided it will be set proportional to the refresh rate. - **servo** (str) - Optional - Servo alias to reference it. `DEFAULT_SERVO` by default. If network_type is provided, servo must be connected to that network. ### Request Example ```json { "network_type": "EtherCAT", "refresh_rate": 0.01, "watchdog_timeout": 0.1, "servo": "servo1" } ``` ### Response #### Success Response (200) - **None** - Indicates successful initiation of PDO exchange. #### Response Example ```json null ``` ### Errors - **ValueError**: If the MotionController is not connected to any Network. - **ValueError**: If there is a type mismatch retrieving the network object. ``` -------------------------------- ### Create PDO Poller Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/capture/pdo.md Creates a Poller instance that utilizes PDOs for efficient register data retrieval. It allows specifying registers, sampling time, buffer size, and watchdog timeout. The poller can be started immediately or configured to start later. Requires a list of registers and accepts optional parameters for servo, sampling time, buffer size, watchdog timeout, and start behavior. ```python def create_poller(registers, servo='default', sampling_time=0.125, buffer_size=100, watchdog_timeout=None, start=True): """Create a register Poller using PDOs. :param registers: list of registers to add to the Poller. :param servo: servo alias to reference it. `default` by default. :param sampling_time: period of the sampling in seconds. :param watchdog_timeout: The PDO watchdog time. :param buffer_size: number maximum of sample for each data read. :param start: if `True`, function starts poller, if `False` poller should be started after. :return: The poller instance. """ pass ``` -------------------------------- ### Start PDO Exchange (Python) Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/capture/pdo.md Initiates the PDO (Process Data Object) exchange process for a servo. Optional parameters include network type, refresh rate, and watchdog timeout. This function is essential for enabling real-time data communication. ```python def start_pdos(network_type=None, refresh_rate=None, watchdog_timeout=None, servo='default'): """Start the PDO exchange process. """ pass ``` -------------------------------- ### Poll Servo Drive Data using PDOs Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/capture.md This example demonstrates how to poll specific registers (Actual Position and Actual Velocity) from a servo drive using Process Data Objects (PDOs). It sets up a PDO poller, retrieves data, and then stops the poller. The 'ingeniamotion' library is required. The function takes a MotionController object as input and outputs the polled data to the console. ```python import time from typing import Union from ingeniamotion.motion_controller import MotionController def set_up_pdo_poller(mc: MotionController) -> None: """Set-up a PDO poller. Read the Actual Position and the Actual Velocity registers using the PDO poller. Args: mc: The controller where there are all functions to perform a PDO poller. """ registers: list[dict[str, Union[int, str]]] = [ { "name": "CL_POS_FBK_VALUE", "axis": 1, }, { "name": "CL_VEL_FBK_VALUE", "axis": 1, }, ] poller = mc.capture.pdo.create_poller(registers=registers) # Waiting time for generating new samples time.sleep(1) time_stamps, data = poller.data poller.stop() print(f"Time: {time_stamps}") print(f"Actual Position values: {data[0]}") print(f"Actual Velocity values: {data[1]}") def main() -> None: mc = MotionController() # Modify these parameters to connect a drive interface_ip = "192.168.2.1" slave_id = 1 dictionary_path = "parent_directory/dictionary_file.xdf" mc.communication.connect_servo_ethercat_interface_ip(interface_ip, slave_id, dictionary_path) set_up_pdo_poller(mc) mc.communication.disconnect() print("The drive has been disconnected.") if __name__ == "__main__": main() ``` -------------------------------- ### Generate Disturbance Signal for Servo Drive Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/capture.md This example demonstrates how to create and apply a disturbance signal to a servo drive. It calculates a Simple Harmonic Motion (SHM) signal and configures the drive to apply this disturbance. Dependencies include the 'ingeniamotion' library and standard Python libraries like 'math', 'time', and 'argparse'. The function takes drive IP and dictionary path as input and outputs the disturbance application to the drive. ```python import math import time import argparse from ingeniamotion import MotionController from ingeniamotion.enums import OperationMode def main(args): mc = MotionController() mc.communication.connect_servo_eoe(args.ip, args.dictionary_path) # Disturbance register target_register = "CL_POS_SET_POINT_VALUE" # Frequency divider to set disturbance frequency divider = 25 # Calculate time between disturbance samples sample_period = divider / mc.configuration.get_position_and_velocity_loop_rate() # The disturbance signal will be a simple harmonic motion (SHM) with frequency 0.5Hz and 2000 counts of amplitude signal_frequency = 0.5 signal_amplitude = 2000 # Calculate number of samples to load a complete oscillation n_samples = int(1 / (signal_frequency * sample_period)) # Generate a SHM with the formula x(t)=A*sin(t*w) where: # A = signal_amplitude (Amplitude) # t = sample_period*i (time) # w = signal_frequency*2*math.pi (angular frequency) data = [ int(signal_amplitude * math.sin(sample_period * i * signal_frequency * 2 * math.pi)) for i in range(n_samples) ] # Call function create_disturbance to configure a disturbance dist = mc.capture.create_disturbance(target_register, data, divider) # Set profile position operation mode and enable motor to enable motor move mc.motion.set_operation_mode(OperationMode.PROFILE_POSITION) # Enable disturbance mc.capture.enable_disturbance() # Enable motor mc.motion.motor_enable() # Wait 10 seconds time.sleep(10) # Disable motor mc.motion.motor_disable() # Disable disturbance mc.capture.clean_disturbance() mc.communication.disconnect() def setup_command(): parser = argparse.ArgumentParser(description="Disturbance example") parser.add_argument("--dictionary_path", help="Path to drive dictionary", required=True) parser.add_argument("--ip", help="Drive IP address", required=True) return parser.parse_args() if __name__ == "__main__": args = setup_command() main(args) ``` -------------------------------- ### get_available_canopen_devices Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/communication.md Returns a list of available CANopen devices. This includes devices that are connected and have the necessary drivers installed. ```APIDOC ## get_available_canopen_devices ### Description Return the list of available CAN devices (those connected and with drivers installed). ### Method GET ### Endpoint /ingeniamc/ingeniamotion/get_available_canopen_devices ### Parameters None ### Request Example None ### Response #### Success Response (200) - **can_devices** (dict) - A dictionary mapping CAN device types to a list of their available channels. #### Response Example ```json { "can_devices": { "KVASER": [0, 1], "PCAN": [0] } } ``` ``` -------------------------------- ### Get Product Name in Python Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/info.md Fetches the product name of the connected servo drive. Accepts an optional servo alias. Returns product names like 'EVE-NET-E' or 'CAP-NET-E'. ```python information.get_product_name(servo='default') ``` -------------------------------- ### Create and Subscribe to PDONetwork in Python Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/capture.md Creates a new PDONetwork and subscribes to its data or events. This is a high-level method that likely handles the underlying setup and connection process. It simplifies the initialization of a PDO network. ```python from ingeniamotion.pdo import PDONetwork # Assuming network_manager is an instance of PDONetworkManager # Assuming network_config contains the configuration details new_network = network_manager.create_and_subscribe(network_config) ``` -------------------------------- ### Configure FSoE PDOs Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/fsoe.md Configures the PDOs used for Safety PDUs. This method allows for starting the PDO exchange and/or starting the FSoE master handlers after configuration. It provides flexibility in managing the communication setup. ```python fsoe_master.configure_pdos(start_pdos=True, start_master=True) ``` -------------------------------- ### Load Drive Firmware via Multiple Protocols (Python) Source: https://context7.com/ingeniamc/ingeniamotion/llms.txt This example shows how to update the firmware on a drive using different communication protocols: EtherCAT, Ethernet, and CANopen. It includes options for specifying network interfaces, firmware files, slave IDs, and boot modes. For CANopen, it also demonstrates the use of status and progress callbacks. Ensure the correct firmware files and connection parameters are provided. ```python from ingeniamotion import MotionController mc = MotionController() # Load firmware via EtherCAT (drive does not need to be connected first) mc.communication.load_firmware_ecat_interface_index( if_index=0, # Network interface index fw_file="firmware.lfu", # Firmware file path slave=1, # Slave ID boot_in_app=True # Bootloader in application ) # Or via Ethernet (requires existing connection) mc.communication.connect_servo_ethernet("192.168.2.22", "dictionary.xdf") mc.communication.boot_mode_and_load_firmware_ethernet("firmware.sfu") # Or via CANopen with progress callback def progress_callback(progress: int) -> None: print(f"Progress: {progress}%") def status_callback(status: str) -> None: print(f"Status: {status}") mc.communication.connect_servo_canopen( can_device=CanDevice.KVASER, dict_path="dictionary.xdf", node_id=32, baudrate=CanBaudrate.Baudrate_1M, channel=0 ) mc.communication.load_firmware_canopen( fw_file="firmware.lfu", status_callback=status_callback, progress_callback=progress_callback ) mc.communication.disconnect() ``` -------------------------------- ### Load Firmware via FTP using Python Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/communication.md This Python script loads firmware onto an IngeniaMotion device using the FTP protocol. It requires the ingeniamotion library and takes the drive's IP address, dictionary path, and firmware file path as arguments. ```python import argparse import ingeniamotion def main(args): # Create MotionController instance mc = ingeniamotion.MotionController() # Connect drive mc.communication.connect_servo_ethernet(args.ip, args.dictionary_path) # Load firmware mc.communication.boot_mode_and_load_firmware_ethernet(args.firmware_file) def setup_command(): parser = argparse.ArgumentParser(description="Disturbance example") parser.add_argument("--dictionary_path", help="Path to drive dictionary", required=True) parser.add_argument("--ip", help="Drive IP address", required=True) parser.add_argument("--firmware_file", help="Firmware file to be loaded", required=True) return parser.parse_args() if __name__ == "__main__": args = setup_command() main(args) ``` -------------------------------- ### Load Firmware via CAN using Python Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/communication.md This Python script loads firmware onto an IngeniaMotion device using the CANopen protocol. It utilizes the ingenialink and ingeniamotion libraries and requires specifying CAN device, channel, baudrate, node ID, dictionary path, and firmware file path. It includes callbacks for status and progress logging. ```python from ingenialink import CanBaudrate, CanDevice from ingenialink.exceptions import ILFirmwareLoadError from ingeniamotion.motion_controller import MotionController def status_log(current_status: str) -> None: print(f"Load firmware status: {current_status}") def progress_log(current_progress: int) -> None: print(f"Load firmware progress: {current_progress}%") def load_firmware_canopen( device: CanDevice, channel: int, baudrate: CanBaudrate, node_id: int, dictionary_path: str, fw_path: str, ) -> None: mc = MotionController() # Find available nodes node_id_list = mc.communication.scan_servos_canopen(device, baudrate, channel) if node_id not in node_id_list: print(f"Node {node_id} is not detected.") return else: print(f"Found nodes: {node_id_list}") print("Starts to establish a communication.") mc.communication.connect_servo_canopen( device, dictionary_path, node_id, baudrate, channel, ) print("Drive is connected.") print("Starts to load the firmware.") try: mc.communication.load_firmware_canopen( fw_path, status_callback=status_log, progress_callback=progress_log, ) print("Firmware is uploaded successfully.") except ILFirmwareLoadError as e: print(f"Firmware loading failed: {e}") mc.communication.disconnect() print("Drive is disconnected.") if __name__ == "__main__": # Remember to replace all parameters here device = CanDevice.KVASER channel = 0 baudrate = CanBaudrate.Baudrate_1M node_id = 32 dictionary_path = "parent_directory/full_dictionary_path.xdf" fw_path = "parent_directory/full_firmware_file_path.lfu" load_firmware_canopen(device, channel, baudrate, node_id, dictionary_path, fw_path) ``` -------------------------------- ### Start FSoE Master Handler Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/fsoe.md Starts an FSoE Master handler. Optionally, it can also start the Process Data Object (PDO) exchange simultaneously. This method is crucial for initiating communication with the safety devices. ```python fsoe_master.start_master(start_pdos=True) ``` -------------------------------- ### Configure Monitoring with Trigger Conditions Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/capture.md This example shows how to configure advanced monitoring with trigger conditions. It includes setting a trigger delay, specifying the trigger mode (e.g., auto, rising edge), and defining the trigger signal and its value. This allows for conditional data capture based on specific events or signal thresholds. ```python from ingeniamotion.monitoring import create_monitoring from ingeniamotion.enums import MonitoringSoCType, MonitoringSoCConfig registers_to_monitor = [ {"name": "CL_POS_FBK_VALUE", "axis": 1} ] monitoring_instance = create_monitoring( registers=registers_to_monitor, prescaler=5, sample_time=0.005, trigger_delay=0.001, trigger_mode=MonitoringSoCType.TRIGGER_EVENT_RISING_EDGE, trigger_signal={"name": "DI_1", "axis": 1}, trigger_value=1, start=True ) ``` -------------------------------- ### Run Feedback Tests with IngeniaMotion Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/examples/drive_tests.md This Python script allows running feedback tests (HALLS, QEI, QEI2) for a drive. It connects to the drive using a MotionController, performs the specified feedback test, and logs the result. It requires the 'ingeniamotion' library and takes feedback type, dictionary path, IP address, axis, and a debug flag as arguments. ```python import logging import argparse from ingeniamotion import MotionController def setup_command(): parser = argparse.ArgumentParser(description="Run feedback test") parser.add_argument("feedback", help="feedback to test", choices=["HALLS", "QEI", "QEI2"]) parser.add_argument("dictionary_path", help="path to drive dictionary") parser.add_argument("-ip", default="192.168.2.22", help="drive ip address") parser.add_argument("--axis", default=1, help="drive axis") parser.add_argument( "--debug", action="store_true", help="with this flag test doesn't apply any change" ) return parser.parse_args() def main(args): # Create MotionController instance mc = MotionController() # Connect Servo with MotionController instance mc.communication.connect_servo_eoe(args.ip, args.dictionary_path) result = None if args.feedback == "HALLS": # Run Digital Halls feedback tests result = mc.tests.digital_halls_test(axis=args.axis, apply_changes=not args.debug) if args.feedback == "QEI": # Run Incremental Encoder 1 feedback tests result = mc.tests.incremental_encoder_1_test(axis=args.axis, apply_changes=not args.debug) if args.feedback == "QEI2": # Run Incremental Encoder 2 feedback tests result = mc.tests.incremental_encoder_2_test(axis=args.axis, apply_changes=not args.debug) logging.info(result["result_message"]) mc.communication.disconnect() if __name__ == "__main__": logging.basicConfig(level=logging.INFO) args = setup_command() main(args) ``` -------------------------------- ### Create Poller Instance with Registers Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/capture.md Creates and optionally starts a Poller instance configured with specified registers. It allows customization of servo, sampling time, buffer size, and initial start state. The function returns a Poller object that can be used to read register data, start, stop, and access collected data, including timestamps, values, and data loss indicators. It may raise IMRegisterNotExistError if a register is not found or TypeError for incorrect parameter types. ```python def create_poller(registers, servo='default', sampling_time=0.125, buffer_size=100, start=True): """ Returns a Poller instance with target registers. Parameters: registers (list[dict[str, Union[int, str]]]): list of registers to add to the Poller. Dicts should have the follow format: [ { # Poller register one "name": "CL_POS_FBK_VALUE", # Register name. "axis": 1 # Register axis. # If it has no axis field, by default axis 1. }, { # Poller register two "name": "CL_VEL_FBK_VALUE", # Register name. "axis": 1 # Register axis. # If it has no axis field, by default axis 1. } ] servo (str): servo alias to reference it. `default` by default. sampling_time (float): period of the sampling in seconds. By default `0.125` seconds. buffer_size (int): number maximum of sample for each data read. `100` by default. start (bool): if `True`, function starts poller, if `False` poller should be started after. `True` by default. Returns: Poller object with chosen registers. Raises: IMRegisterNotExistError: If register does not exist in dictionary. TypeError: If some parameter has a wrong type. """ pass ``` -------------------------------- ### Create Monitoring Instance with Registers Source: https://github.com/ingeniamc/ingeniamotion/blob/master/docs/ingeniamotion/capture.md This snippet demonstrates how to create a monitoring instance by specifying the registers to track. The `registers` parameter is a list of dictionaries, where each dictionary defines a register's name and its associated axis. This is crucial for collecting specific data points from the servo. ```python from ingeniamotion.monitoring import create_monitoring registers_to_monitor = [ {"name": "CL_POS_FBK_VALUE", "axis": 1}, {"name": "CL_VEL_FBK_VALUE", "axis": 1} ] monitoring_instance = create_monitoring( registers=registers_to_monitor, prescaler=10, sample_time=0.01 ) ```