1. Вступ: Розширення інтерпретатора RS274NGC шляхом перепризначення кодів
1.1. Визначення: Перепризначення кодів
Під «перепризначенням кодів» ми маємо на увазі одне з наступного:
-
Визначити семантику нових, тобто наразі нерозподілених, M- або G-кодів
-
Перевизначити семантику – наразі обмеженого – набору існуючих кодів.
1.2. Навіщо розширювати інтерпретатор RS274NGC?
Набір кодів (M, G, T, S, F), які наразі розуміє інтерпретатор RS274NGC, є фіксованим і не може бути розширений за допомогою параметрів конфігурації.
Зокрема, деякі з цих кодів реалізують фіксовану послідовність кроків, які необхідно виконати. Хоча деякі з них, наприклад M6, можна частково налаштувати, активуючи або пропускаючи деякі з цих кроків за допомогою опцій файлу INI, загалом поведінка є досить жорсткою. Отже, якщо вас влаштовує така ситуація, то цей розділ посібника не для вас.
У багатьох випадках це означає, що підтримка нестандартної конфігурації або машини є або громіздкою, або неможливою, або вимагає звернення до змін на рівні мови «C/C+\+». Останнє є непопулярним з поважних причин — зміна внутрішніх компонентів вимагає глибокого розуміння внутрішніх компонентів інтерпретатора, а крім того, створює власний набір проблем із підтримкою. Хоча можна припустити, що певні виправлення можуть потрапити до основного дистрибутива LinuxCNC, результатом такого підходу є мішанина рішень для особливих випадків.
Хорошим прикладом цього недоліку є підтримка зміни інструментів в LinuxCNC: хоча випадкові змінювачі інструментів добре підтримуються, практично неможливо розумно визначити конфігурацію для машини з ручною зміною інструментів, наприклад, з автоматичним перемикачем зміщення довжини інструменту, що відвідується після зміни інструменту, і відповідним налаштуванням зміщень. Крім того, хоча існує патч для дуже специфічного змінювача інструментів, він не знайшов свого місця в основній базі коду.
Однак багато з цих проблем можна вирішити, використовуючи процедуру O-word замість вбудованого коду — коли потрібно виконати вбудований код, який є недостатнім, замість цього викликайте процедуру O-word. Хоча це можливо, але це незручно — потрібно редагувати вихідний код програм NGC, замінюючи всі виклики недосконалого коду викликом процедури O-word.
У найпростішому вигляді перемапований код є не більше ніж спонтанним викликом процедури O-word. Це відбувається за лаштунками — процедура видима на рівні конфігурації, але не на рівні програми NGC.
Зазвичай, поведінку перепризначеного коду можна визначити такими способами:
-
Ви визначаєте підпрограму на літеру О, яка реалізує бажану поведінку
-
Або ж ви можете використовувати функцію Python, яка розширює поведінку інтерпретатора.
M- та G-коди, а також виклики підпрограм на основі O-слів мають дещо інший синтаксис.
Наприклад, процедури O-word приймають позиційні параметри зі специфічним синтаксисом, наприклад:
o<test> call [1.234] [4.65]
тоді як M- або G-коди зазвичай приймають обов’язкові або додаткові параметри типу «слово». Наприклад, G76 (різьблення) вимагає слів P, Z, I, J та K, а також додатково приймає слова R, Q, H, E та L.
Тому недостатньо просто сказати «коли ви зустрінете код X, запустіть процедуру Y» — необхідно принаймні перевірити та перетворити параметри. Для цього потрібен «клейовий код» між новим кодом та відповідною процедурою NGC, який виконується перед передачею контролю процедурі NGC.
Цей код-сполучна неможливо написати як процедуру O-word, оскільки мова RS274NGC не має інтроспективних можливостей та доступу до внутрішніх структур даних інтерпретатора для досягнення необхідного ефекту. Виконання коду-сполучної знову в «C/C+\+» було б негнучким і, отже, незадовільним рішенням.
Щоб зробити просту ситуацію легкою, а складну – вирішувальною, проблему з клеєм вирішують наступним чином:
-
Для простих ситуацій вбудована процедура склеювання (
argspec) охоплює найпоширеніші вимоги до передачі параметрів. -
Для перепризначення T, M6, M61, S, F існує стандартний клей Python, який має охопити більшість ситуацій, див. Standard Glue.
-
Для складніших ситуацій можна написати власний клейовий агент Python для реалізації нової поведінки.
Вбудовані функції Python в інтерпретаторі спочатку були лише допоміжним кодом, але виявилися дуже корисними і в інших сферах. Користувачам, знайомим з Python, буде простіше писати перемаповані коди, допоміжний код, процедури O-word тощо в чистому Python, не вдаючись до дещо громіздкої мови RS274NGC.
Багато людей знайомі з «розширенням» інтерпретатора Python за допомогою модулів «C/C++», і це широко використовується в LinuxCNC для доступу до внутрішніх компонентів Task, HAL та Interpreter зі скриптів Python. «Розширення Python» в основному означає: ваш скрипт Python виконується «як у водійському сидінні» і може отримувати доступ до коду, що не належить до Python, шляхом імпортування та використання модулів розширення, написаних на «C/C+\+». Прикладами цього є модулі LinuxCNC hal, gcode та emc.
Вбудований Python дещо відрізняється і є менш відомим: основна програма написана на C/C++ і може використовувати Python як підпрограму. Це потужний механізм розширення і основа для «розширень скриптів», які можна знайти в багатьох успішних програмних пакетах. Вбудований код Python може отримувати доступ до змінних і функцій «C/C+\+» за допомогою подібного методу модуля розширення.
2. Початок роботи
Визначення коду включає такі кроки:
-
Виберіть код – або використовуйте нерозподілений код, або перевизначте існуючий код.
-
Визначте, як обробляються параметри.
-
Вирішіть, чи будуть оброблені результати і як.
-
Визначтеся з послідовністю виконання.
2.1. Вбудовані перепризначення
Зверніть увагу, що наразі можна перевизначити лише деякі існуючі коди, тоді як існує багато «вільних» кодів, які можна перепризначити. При розробці перевизначеного існуючого коду рекомендується почати з не призначеного коду G або M, щоб можна було використовувати як існуючу, так і нову поведінку. Після завершення перевизначте існуючий код, щоб використовувати вашу конфігурацію перепризначення.
-
Поточний набір невикористаних M-кодів, доступних для визначення користувачем, можна знайти в розділі unallocated M-codes.
-
Щодо G-кодів див. unallocated G-codes.
-
Існуючі коди, які можна перепризначити, перелічені в розділі remappable codes.
Наразі у stdglue.py доступні два повні перепризначення лише для Python:
-
ignore_m6
-
index_lathe_tool_with_wear
Вони призначені для використання з токарним верстатом. Токарні верстати не використовують M6 для індексації інструментів, вони використовують команду T.
Це перемапування також додає зносові зміщення до зміщення інструменту, наприклад, T201 буде індексувати інструмент 2 (зі зміщенням інструменту 2) і додає зносове зміщення 1. У таблиці інструментів номери інструментів вище 10000 є зносовими зміщеннями, наприклад, у таблиці інструментів інструмент 10001 буде зносовим зміщенням 1.
Ось що потрібно в INI-файлі для їх використання:
[RS274NGC] REMAP=T python=index_lathe_tool_with_wear REMAP=M6 python=ignore_m6 [PYTHON] # де знайти код Python: # код, специфічний для цієї конфігурації PATH_PREPEND=./ # загальний код підтримки – переконайтеся, що він дійсно вказує на Python-stdglue PATH_APPEND=../../nc_files/remap_lib/python-stdglue/ # імпортуйте наступний модуль Python TOPLEVEL=toplevel.py # чим вище, тим детальніше трасування плагіна Python LOG_LEVEL = 0
Ви також повинні додати необхідний файл Python до папки конфігурації.
2.2. Вибір коду
Зверніть увагу, що на даний момент можна перевизначити лише декілька існуючих кодів, тоді як існує багато «вільних» кодів, які можна зробити доступними шляхом перепризначення. При розробці перевизначеного існуючого коду, можливо, варто почати з нерозподіленого коду G або M, щоб можна було реалізувати як існуючу, так і нову поведінку. Після завершення перевизначте існуючий код, щоб використовувати ваші налаштування перепризначення.
2.3. Обробка параметрів
Припустимо, що новий код буде визначений процедурою NGC і потребує деяких параметрів, деякі з яких можуть бути обов’язковими, а інші — необов’язковими. Ми маємо такі варіанти для введення значень у процедуру:
-
Вилучення слів з поточного блоку та передача їх процедурі як параметрів (наприклад,
X22.34абоP47), -
посилаючись на змінні файлу INI,
-
посилання на глобальні змінні (наприклад,
#2200 = 47.11або#<_global_param> = 315.2).
Перший метод є кращим для параметрів динамічного характеру, таких як позиції. Вам потрібно визначити, які слова в поточному блоці мають якесь значення для вашого нового коду, і вказати, як це передається до процедури NGC. Найпростіший спосіб — це використання оператора argspec. Налаштований пролог може надавати кращі повідомлення про помилки.
Використання змінних INI-файлу є найбільш корисним для посилання на інформацію про налаштування вашої машини, наприклад, на фіксоване положення, таке як положення датчика довжини інструменту. Перевага цього методу полягає в тому, що параметри є фіксованими для вашої конфігурації, незалежно від того, який NGC-файл ви виконуєте в даний момент.
Звернення до глобальних змінних завжди можливе, але їх легко пропустити.
Зверніть увагу, що кількість слів, які можна використовувати як параметри, обмежена, тому, якщо потрібно багато параметрів, може знадобитися повернутися до другого та третього методів.
2.4. Обробка результатів
Ваш новий код може працювати або не працювати, наприклад, якщо передано недійсну комбінацію параметрів. Або ви можете вирішити «просто виконати» процедуру і не зважати на результати, і в цьому випадку роботи буде небагато.
Обробники епілогів допомагають в обробці результатів процедур перепризначення - див. розділ з посиланнями.
2.5. Послідовність виконання
Виконувані слова G-коду класифікуються на modal groups, що також визначає їхню відносну поведінку під час виконання.
Якщо блок G-коду містить кілька виконуваних слів у рядку, ці слова виконуються у заздалегідь визначеному порядку order of execution, а не в порядку, в якому вони з’являються в блоці.
Коли ви визначаєте новий виконуваний код, інтерпретатор ще не знає, де ваш код вписується в цю схему. З цієї причини вам потрібно вибрати відповідну модальну групу для виконання вашого коду.
2.6. Мінімальний приклад переробленого коду
Щоб ви могли уявити, як всі елементи поєднуються між собою, давайте розглянемо досить мінімальне, але повне визначення перемапованого коду. Ми вибираємо нерозподілений M-код і додаємо до файлу INI наступну опцію:
[RS274NGC] REMAP=M400 modalgroup=10 argspec=Pq ngc=myprocedure
Коротко кажучи, це означає:
-
Код
M400приймає обов’язковий параметрPта необов’язковий параметрQ. Інші слова в поточному блоці ігноруються стосовно кодуM400. Якщо словоPвідсутнє, виконання завершується з помилкою. -
Коли зустрічається код
M400, виконайтеmyprocedure.ngcразом з іншими 10 M-кодами modal group відповідно до order of execution. -
Значення
PтаQдоступні в процедурі як локальні іменовані параметри. На них можна посилатися як#<P>та#<Q>. Процедура може перевірити, чи словоQбуло присутнє за допомогою вбудованої функціїEXISTS.
Очікується, що файл myprocedure.ngc знаходиться в каталозі [DISPLAY]NC_FILES або [RS274NGC]SUBROUTINE_PATH.
Детальний опис параметрів REMAP можна знайти в розділі з посиланнями нижче.
3. Налаштування перепризначення
3.1. Заява REMAP
Щоб перепризначити код, визначте його за допомогою опції REMAP у розділі RS274NG вашого INI-файлу. Використовуйте один рядок REMAP на кожен перепризначений код.
Синтаксис REMAP такий:
Пропускати параметр <code> є помилкою.
Опції оператора REMAP розділені пробілами. Опції є парами ключове слово-значення і наразі мають такий вигляд:
-
modalgroup=<modal group> -
- G-коди
-
Єдина підтримувана наразі модальна група — 1, яка також є значенням за замовчуванням, якщо група не вказана. Група 1 означає «виконувати разом з іншими G-кодами».
- M-коди
-
Наразі підтримуються такі модальні групи: 5, 6, 7, 8, 9, 10. Якщо модальна група не вказана, значення за замовчуванням дорівнює 10 («виконувати після всіх інших слів у блоці»).
- T,S,F
-
для них модальна група фіксована, а будь-який параметр
modalgroup=ігнорується.
-
argspec=<argspec> -
Див. опис опцій параметра argspec. Необов’язково.
-
ngc=<ngc_basename> -
Базова назва файлу підпрограми O-word. Не вказуйте розширення .ngc. Шукається в каталогах, вказаних у каталозі, вказаному в
[DISPLAY]PROGRAM_PREFIX, а потім в[RS274NGC]SUBROUTINE_PATH. Взаємовиключне зpython=. Опущення якngc=, так іpython=є помилкою. -
python=<Назва функції Python> -
Замість виклику процедури ngc O-word, викличте функцію Python. Очікується, що функція буде визначена в модулі
module_basename.oword. Взаємно виключні зngc=. -
prolog=<Назва функції Python> -
Перед виконанням процедури ngc викличте цю функцію Python. Очікується, що функція буде визначена в модулі
module_basename.remap. Необов’язково. -
epilog=<Назва функції Python> -
Після виконання процедури ngc викличте цю функцію Python. Очікується, що функція буде визначена в модулі
module_basename.remap. Необов’язково.
Для опцій python, prolog та epilog необхідний плагін Python Interpreter, який має бути configured, а також відповідні функції Python, які мають бути визначені там, щоб їх можна було використовувати з цими опціями.
Синтаксис для визначення нового коду та перевизначення існуючого коду ідентичний.
3.2. Корисні комбінації опцій REMAP
Зверніть увагу, що хоча можливі багато комбінацій параметрів argspec, не всі вони мають сенс. Наступні комбінації є корисними ідіомами:
-
argspec=<words>ngc=<procname>modalgroup=_<group> -
Рекомендований спосіб виклику процедури NGC із стандартним перетворенням параметра argspec. Використовується, якщо argspec є достатнім. Зверніть увагу, що цього недостатньо для перепризначення кодів зміни інструменту
TxтаM6/M61. -
prolog=<pythonprolog>ngc=<procname>epilog=<pythonepilog>modalgroup=<group> -
Викличте функцію прологу Python, щоб виконати будь-які попередні кроки, а потім викличте процедуру NGC. Після завершення викличте функцію епілогу Python, щоб виконати будь-які роботи з очищення або вилучення результатів, які не можуть бути оброблені в G-коді. Це найгнучкіший спосіб перепризначення коду до процедури NGC, оскільки майже всі внутрішні змінні інтерпретатора та деякі внутрішні функції можуть бути доступні з обробників прологу та епілогу. Крім того, це довша мотузка, на якій ви можете повіситися.
-
python=<pythonfunction>modalgroup=<group> -
Безпосередньо викликайте функцію Python без будь-якого перетворення аргументів. Найпотужніший спосіб перемапування коду і переходу безпосередньо до Python. Використовуйте це, якщо вам не потрібна процедура NGC або NGC просто заважає вам.
-
argspec=<words>python=<pythonfunction>modalgroup=<group> -
Перетворіть слова з argspec та передайте їх функції Python як словник аргументів ключових слів. Використовуйте це, коли вам ліньки самостійно досліджувати слова, передані в блоці.
Зверніть увагу, що якщо все, що ви хочете досягти, це викликати певний код Python з G-коду, існує дещо простіший спосіб виклику функцій Python.
3.3. Параметр argspec
Специфікація аргументу (ключове слово argspec) описує обов’язкові та додаткові слова, які потрібно передати процедурі ngc, а також додаткові передумови для виконання цього коду.
Специфікація аргументів складається з 0 або більше символів класу [@A-KMNP-Za-kmnp-z^>]. Вона може бути порожньою (як argspec=).
Порожній аргумент argspec або його відсутність взагалі означає, що перепризначений код не отримує жодних параметрів з блоку. Він ігноруватиме будь-які додаткові наявні параметри.
Зверніть увагу, що правила RS274NGC все ще застосовуються — наприклад, ви можете використовувати слова осей (наприклад, X, Y, Z) лише в контексті G-коду.
Слова осей також можна використовувати, лише якщо вісь увімкнена. Якщо увімкнено лише XYZ, ABCUVW не буде доступним для використання в argspec.
Слова «F», «S» і «T» (скорочено «FST») матимуть звичайні функції, але будуть доступні як змінні в перепризначеній функції. «F» встановлюватиме швидкість подачі, «S» встановлюватиме оберти шпинделя, «T» запускатиме функцію підготовки інструменту. Слова «FST» не слід використовувати, якщо така поведінка не є бажаною.
Слова DEIJKPQR не мають попередньо визначеної функції та рекомендуються для використання як параметри argspec.
-
ABCDEFHIJKPQRSTUVWXYZ -
Визначає обов’язковий параметр слова: велика літера вказує, що відповідне слово повинно бути присутнім у поточному блоці. Значення слова буде передано як локальний іменований параметр з відповідною назвою. Якщо в argspec присутній символ
@, він буде переданий як позиційний параметр, див. нижче. -
abcdefhijkpqrstuvwxyz -
Визначає необов’язковий параметр слова: мала літера вказує, що відповідне слово може бути присутнім у поточному блоці. Якщо слово присутнє, його значення буде передано як локальний іменований параметр. Якщо в argspec присутній символ
@, він буде переданий як позиційний параметр, див. нижче. -
@ -
Символ
@(знак @) вказує argspec передавати слова як позиційні параметри в порядку, визначеному після опції@. Зверніть увагу, що при використанні передачі позиційних параметрів процедура не може визначити, чи було слово присутнє, чи ні, див. приклад нижче.
|
Tip
|
це допомагає упакувати існуючі процедури NGC як перемаповані коди. Існуючі процедури очікують позиційних параметрів. За допомогою опції @ ви можете уникнути їх перезапису для посилання на локальні іменовані параметри. |
-
^ -
Символ
^(вставка) вказує, що поточна швидкість шпинделя має бути більшою за нуль (шпиндель працює), інакше код завершується невдачею з відповідним повідомленням про помилку. -
> -
The
>(Символ «більше ніж») вказує, що поточна подача має бути більшою за нуль, інакше код завершиться невдало з відповідним повідомленням про помилку. -
n -
Символ
n(більше ніж) вказує на передачу поточного номера рядка в локальному іменованому параметріn.
За замовчуванням параметри передаються як локальні іменовані параметри до процедури NGC. Ці локальні параметри відображаються як «вже встановлені» під час запуску процедури, що відрізняється від існуючої семантики (локальні змінні починають з значення 0,0 і потребують явного присвоєння значення).
Наявність додаткових параметрів слова можна перевірити за допомогою ідіоми EXISTS(#<слово>).
Припустимо, що код визначено як
REMAP=M400 modalgroup=10 argspec=Pq ngc=m400
а m400.ngc виглядає так:
o<m400> sub (P є обов'язковим, оскільки в argspec воно написано великими літерами) (debug, P word=#<P>) (argspec q є необов'язковим, оскільки в argspec воно написано малими літерами. Використовуйте наступним чином:) o100 if [EXISTS[#<q>]] (debug, Q word set: #<q>) o100 endif o<m400> endsub M2
-
Виконання
M400завершиться невдачею з повідомленнямвизначений користувачем M400: відсутній: P. -
Виконання команди
M400 P123відобразитьP word=123.000000. -
Виконання команди
M400 P123 Q456відобразитьP word=123.000000таQ word set: 456.000000.
Припустимо, що код визначено як
REMAP=M410 modalgroup=10 argspec=@PQr ngc=m410
а m410.ngc виглядає наступним чином:
o<m410> sub (debug, [1]=#1 [2]=#2 [3]=#3) o<m410> endsub M2
-
Виконання команди
M410 P10відобразитьm410.ngc: [1]=10.000000 [2]=0.000000. -
Виконання
M410 P10 Q20will displaym410.ngc: [1]=10.000000 [2]=20.000000.
|
Note
|
ви втрачаєте можливість розрізняти більше одного слова додаткового параметра, і не можете визначити, чи був присутній необов’язковий параметр, але мав значення 0, чи взагалі був відсутній. |
Можливо визначити нові коди без будь-якої процедури NGC. Ось перший простий приклад, складніший можна знайти в наступному розділі.
Припустимо, що код визначено як
REMAP=G88.6 modalgroup=1 argspec=XYZp python=g886
Це вказує інтерпретатору виконати функцію Python g886 у модулі module_basename.remap, яка може виглядати так:
з інтерпретатора імпорт INTERP_OK з emccanon імпорт MESSAGE def g886(self, **words): for key in words: MESSAGE("word '%s' = %f" % (key, words[key])) if words.has_key('p'): MESSAGE("the P word was present") MESSAGE("comment on this line: '%s'" % (self.blocks[self.remap_level].comment)) return INTERP_OK
Спробуйте це без використання: g88.6 x1 y2 z3 g88.6 x1 y2 z3 p33 (коментар тут)
Ви помітите поступове впровадження вбудованого середовища Python — детальніше див. here. Зверніть увагу, що з функціями перепризначення Python немає сенсу використовувати функції прологу та епілогу Python, оскільки спочатку виконується функція Python.
Модулі interpreter та emccanon розкривають доступ до більшої частини Інтерпретатора та деяких внутрішніх функцій Canon, тому багато речей, які досі вимагали написання на C/C+\+, тепер можна зробити на Python.
Наступний приклад базується на скрипті nc_files/involute.py, але записаний у вигляді G-коду з деякими витягненнями та перевірками параметрів. Він також демонструє рекурсивне виклик інтерпретатора (див. self.execute()).
Припускаючи таке визначення (Примітка: тут не використовується argspec):
REMAP=G88.1 modalgroup=1 py=involute
Функція involute у файлі python/remap.py, наведена нижче, виконує вилучення всіх слів безпосередньо з поточного блоку. Зверніть увагу, що помилки інтерпретатора можуть бути перетворені на винятки Python. Пам’ятайте, що це «час попереднього читання» — помилки часу виконання не можуть бути перехоплені таким чином.
import sys import traceback з математичного імпорту sin,cos from interpreter import * from emccanon import MESSAGE from util import lineno, call_pydevd # викликає InterpreterException, якщо execute() або read() завершується невдачею throw_exceptions = 1 def involute(self, **words): """ функція перепризначення з необробленим доступом до внутрішніх функцій інтерпретатора """ if self.debugmask & 0x20000000: call_pydevd() # Прапорець налагодження USER2 if equal(self.feed_rate,0.0): return "feedrate > 0 required" if equal(self.speed[0], 0.0): return "spindle speed > 0 required" plunge = 0.1 # якщо було задано слово Z, занурення - зі зменшеною подачею # перевірити контрольний блок на наявність відповідних слів c = self.blocks[self.remap_level] x0 = c.x_number if c.x_flag else 0 y0 = c.y_number if c.y_flag else 0 a = c.p_number if c.p_flag else 10 old_z = self.current_z if self.debugmask & 0x10000000: print("x0=%f y0=%f a=%f old_z=%f" % (x0,y0,a,old_z)) try: #self.execute("G3456") # викличе виняток InterpreterException self.execute("G21",lineno()) self.execute("G64 P0.001",lineno()) self.execute("G0 X%f Y%f" % (x0,y0),lineno()) if c.z_flag: feed = self.feed_rate self.execute("F%f G1 Z%f" % (feed * plunge, c.z_number),lineno()) self.execute("F%f" % (feed),lineno()) for i in range(100): t = i/10. x = x0 + a * (cos(t) + t * sin(t)) y = y0 + a * (sin(t) - t * cos(t)) self.execute("G1 X%f Y%f" % (x,y),lineno()) if c.z_flag: # повернути на початкову висоту self.execute("G0 Z%f" % (old_z),lineno()) except InterpreterException,e: msg = "%d: '%s' - %s" % (e.line_number,e.line_text, e.error_message) return msg return INTERP_OK
Приклади, описані досі, можна знайти у файлі configs/sim/axis/remap/getting-started з повними робочими конфігураціями.
4. Оновлення існуючої конфігурації для перепризначення
Мінімальні передумови для використання операторів REMAP такі:
-
Плагін Python потрібно активувати, вказавши
[PYTHON]TOPLEVEL=<шлях-до-скрипта-топловня>у INI-файлі. -
Скрипт верхнього рівня має імпортувати модуль
remap, який спочатку може бути порожнім, але імпорт має бути виконаний. -
Інтерпретатор Python повинен знайти модуль remap.py вище, тому шлях до каталогу, де знаходяться ваші модулі Python, потрібно додати за допомогою
[PYTHON]PATH_APPEND=<path-to-your-local-Python-directory> -
Рекомендується: імпортувати обробники
stdglueу модульremap. У цьому випадку Python також повинен знайти файлstdglue.py— ми просто копіюємо його з дистрибутива, щоб ви могли внести необхідні локальні зміни. Залежно від вашої інсталяції шлях до файлуstdglue.pyможе відрізнятися.
Припускаючи, що ваша конфігурація знаходиться в /home/user/xxx, а INI-файл — /home/user/xxx/xxx.ini, виконайте наступні команди.
$ cd /home/user/xxx $ mkdir python $ cd python $ cp /usr/share/linuxcnc/ncfiles/remap_lib/python-stdglue/stdglue.py . $ echo 'from stdglue import *' >remap.py $ echo 'import remap' >toplevel.py
Тепер відредагуйте ``/home/user/``xxx``/``xxx``.ini`` та додайте наступне:
[PYTHON] TOPLEVEL=/home/user/xxx/python/toplevel.py PATH_APPEND=/home/user/xxx/python
Тепер перевірте, чи LinuxCNC не видає жодних повідомлень про помилки — у вікні терміналу виконайте:
$ cd /home/user/xxx
$ linuxcnc xxx.ini5. Коди, пов’язані зі зміною інструменту переналаштування: T, M6, M61
5.1. Огляд
Якщо ви не знайомі з внутрішніми механізмами LinuxCNC, спочатку прочитайте розділ Як зараз працює зміна інструменту (важко, але необхідно).
Зверніть увагу, що під час перепризначення існуючого коду ми повністю вимикаємо вбудовану функціональність цього коду інтерпретатора.
Отже, наш перероблений код повинен буде робити дещо більше, ніж просто генерувати команди для переміщення машини так, як нам потрібно — він також повинен буде повторювати ті кроки з цієї послідовності, які необхідні для забезпечення нормальної роботи інтерпретатора та task.
Однак це не впливає на обробку команд, пов’язаних із заміною інструменту, в task та iocontrol. Це означає, що коли ми виконуємо step 6b, це все одно призведе до того, що iocontrol виконає свою дію.
Рішення, рішення:
-
Чи хочемо ми використовувати процедуру на літеру О, чи робити все це кодом на Python?
-
Чи достатньо послідовності HAL «iocontrol» (контакти tool-prepare/tool-prepared та tool-change/tool-changed), чи нам потрібна інша взаємодія HAL для нашого пристрою зміни інструментів (наприклад: більше контактів HAL з іншою послідовністю взаємодії)?
Залежно від відповіді, ми маємо чотири різні сценарії:
-
Під час використання процедури на літеру О-слово нам потрібні функції прологу та епілогу.
-
Якщо використовується лише код Python і жодної процедури на O-слові, достатньо функції Python.
-
Під час використання виводів
iocontrolнаша процедура на O-слові або код Python міститиме здебільшого переміщення. -
Коли нам потрібна більш складна взаємодія, ніж та, що пропонує
iocontrol, ми повинні повністю визначити нашу власну взаємодію, використовуючи контактиmotion.digital*таmotion.analog*, і, по суті, ігнорувати контактиiocontrol, зациклюючи їх.
|
Note
|
Якщо ви не любите процедури O-word і любите Python, ви можете зробити все в Python, і в цьому випадку вам достатньо буде вказати python=<function> spec в операторі REMAP. Але, припускаючи, що більшість людей будуть зацікавлені у використанні процедур O-word, оскільки вони більш звичні для них, ми зробимо це першим прикладом. |
Отже, загальний підхід для нашого першого прикладу буде таким:
-
Ми хотіли б зробити якомога більше за допомогою G-коду в процедурі O-word для більшої гнучкості. Це включає всю взаємодію HAL, яка зазвичай обробляється за допомогою
iocontrol, оскільки ми хотіли б робити розумні речі з переміщеннями, зондами, входами/виходами HAL і так далі. -
Ми спробуємо мінімізувати код Python настільки, наскільки це необхідно, щоб інтерпретатор був задоволений, і змусити
taskвиконувати будь-які дії. Це буде передано функціям Pythonprologтаepilog.
5.2. Розуміння ролі iocontrol з перепризначеними кодами зміни інструменту
iocontrol надає дві послідовності взаємодії HAL, які ми можемо використовувати, а можемо й не використовувати:
-
Коли виконується повідомлення NML, поставлене в чергу командою SELECT_TOOL() canon, це запускає послідовність HAL «підняти tool-prepare і чекати, поки tool-prepared не стане високим» в
iocontrol, крім встановлення контактів XXXX -
Коли виконується повідомлення NML, поставлене в чергу командою CHANGE_TOOL(), це запускає послідовність HAL «підняти зміну інструменту і чекати, поки інструмент не зміниться на високий» в
iocontrol, крім установки контактів XXXX
Вам потрібно вирішити, чи достатньо існуючих послідовностей HAL iocontrol для керування вашим перетворювачем. Можливо, вам потрібна інша послідовність взаємодії — наприклад, більше контактів HAL або, можливо, більш складна взаємодія. Залежно від відповіді, ми можемо продовжувати використовувати існуючі послідовності HAL iocontrol або визначити власні.
Для документації ми вимкнемо ці послідовності iocontrol і створимо власні — результат буде виглядати і відчуватися як існуюча взаємодія, але тепер ми маємо повний контроль над ними, оскільки вони виконуються в нашій власній процедурі O-word.
Отже, ми будемо використовувати деякі контакти motion.digital-* та motion.analog-*, а також відповідні команди M62 .. M68 для взаємодії з HAL у нашій процедурі O-word, і вони ефективно замінять послідовності iocontrol tool-prepare/tool-prepared та tool-change/tool-changed. Отже, ми визначимо наші контакти, які функціонально замінять існуючі контакти iocontrol, і продовжимо, зробивши взаємодію iocontrol циклом. У нашому прикладі ми будемо використовувати таку відповідність:
iocontrol відповідність контактів у прикладах
iocontrol.0 шпилька |
motion шпилька |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Припустимо, ви хочете перевизначити команду M6 та замінити її процедурою з літерою О, але в іншому все «має продовжувати працювати».
Отже, наша процедура O-word замінить кроки описані тут. Переглянувши ці кроки, ви побачите, що код NGC можна використовувати для більшості з них, але не для всіх. Тому те, що NGC не може обробити, буде виконано в пролозі та епілозі Python.
5.3. Визначення заміни M6
Щоб передати ідею, ми просто замінюємо вбудовану семантику M6 нашою власною. Як тільки це спрацює, ви можете продовжувати та розміщувати будь-які дії, які вважаєте за потрібне, у процедурі O-word.
Виконуючи кроки [remap:interpreter-action-on-m6], ми знаходимо:
-
перевірити, чи вже виконано команду T - виконати в пролозі Python
-
перевірити, чи активна компенсація різця - виконати у пролозі Python
-
зупинити шпиндель, якщо потрібно - можна зробити в NGC
-
перо вгору - можна зробити в NGC
-
якщо було встановлено TOOL_CHANGE_AT_G30:
-
перемістити індексатори A, B та C, якщо це можливо - можна зробити в NGC
-
генерувати швидкий рух до позиції G30 - можна виконати в NGC
-
-
надіслати команду CHANGE_TOOL Canon до
task- виконати в епілозі Python -
встановіть пронумеровані параметри 5400-5413 відповідно до нового інструменту - виконайте в епілозі Python
-
сигнал до
taskпро припинення виклику інтерпретатора для попереднього зчитування до завершення зміни інструменту - виконати в епілозі Python
Отже, нам потрібен пролог та епілог. Припустимо, що наш INI-файл з інкантацією перепризначення M6 виглядає так:
REMAP=M6 modalgroup=6 prolog=change_prolog ngc=change epilog=change_epilog
Отже, пролог, що охоплює кроки 1 і 2, виглядатиме так: ми вирішуємо передати кілька змінних до процедури перемапування, де їх можна перевірити та змінити або використати в повідомленні. Це такі змінні: tool_in_spindle, selected_tool (номери інструментів) та відповідні індекси даних інструментів current_pocket і selected_pocket:
|
Note
|
Старі імена selected_pocket та current_pocket насправді посилаються на послідовний індекс tooldata для елементів інструменту, завантажених із таблиці інструментів ([EMCIO]TOOL_TABLE) або через базу даних tooldata ([EMCIO]DB_PROGRAM). |
def change_prolog(self, **words): try: if self.selected_pocket < 0: return "M6: no tool prepared" if self.cutter_comp_side: return "Неможливо змінити інструменти, якщо ввімкнено компенсацію радіуса різця" self.params["tool_in_spindle"] = self.current_tool self.params["selected_tool"] = self.selected_tool self.params["current_pocket"] = self.current_pocket self.params["selected_pocket"] = self.selected_pocket return INTERP_OK except Exception as e: return "M6/change_prolog: {}".format(e)
Ви побачите, що більшість функцій прологу виглядають дуже схожими:
-
Спочатку перевірте, чи виконуються всі передумови для виконання коду, потім
-
підготувати середовище — ввести змінні та/або виконати будь-які підготовчі кроки обробки, які неможливо легко виконати в коді NGC;
-
потім передайте до процедури NGC, повернувши INTERP_OK.
Наша перша ітерація процедури O-word не є цікавою - просто перевірте, чи правильно ми вказали параметри, і сигналізуйте про успіх, повертаючи позитивне значення; кроки 3-5 будуть зрештою висвітлені тут (див. here для змінних, що відносяться до налаштувань файлу INI):
O<change> sub (налагодження, зміна: поточний_інструмент=#<поточний_інструмент>) (налагодження, зміна: вибрана_кишеня=#<вибрана_кишеня>) ; ; вставте сюди будь-який G-код, який вважаєте за потрібне, наприклад: ; G0 #<_ini[setup]tc_x> #<_ini[setup]tc_y> #<_ini[setup]tc_z> ; O<change> endsub [1] m2
Якщо припустити успішне виконання change.ngc, нам потрібно виконати кроки 6-8:
def change_epilog(self, **words): try: if self.return_value > 0.0: # зафіксувати зміни self.selected_pocket = int(self.params["selected_pocket"]) emccanon.CHANGE_TOOL(self.selected_pocket) # викликати синхронізацію() self.tool_change_flag = True self.set_tool_parameters() return INTERP_OK else: return "M6 aborted (return code %.1f)" % (self.return_value) except Exception, e: return "M6/change_epilog: %s" % (e)
Цей замінник M6 сумісний із вбудованим кодом, за винятком того, що кроки 3-5 потрібно заповнити вашим кодом NGC.
Знову ж таки, більшість епілогів мають спільну схему:
-
Спочатку визначте, чи все пройшло правильно під час процедури перепризначення,
-
потім виконайте будь-які дії з фіксації та очищення, які неможливо виконати в коді NGC.
5.4. Налаштування iocontrol з перепризначеним M6
Зверніть увагу, що послідовність операцій змінилася: ми виконуємо все необхідне в процедурі O-word, включаючи будь-яке налаштування/зчитування контактів HAL для запуску змінювача та підтвердження зміни інструменту, ймовірно, за допомогою контактів вводу-виводу motion.digital-* та motion-analog-*. Коли ми нарешті виконуємо команду CHANGE_TOOL(), всі рухи та взаємодії HAL вже завершені.
Зазвичай тільки тепер iocontrol виконує свою роботу, як описано в here. Однак нам більше не потрібно, щоб HAL коливався — все, що залишається зробити iocontrol, це прийняти, що ми закінчили підготовку та зміни.
Це означає, що відповідні виводи iocontrol більше не мають функцій. Тому ми налаштовуємо iocontrol на негайне підтвердження змін, виконавши такі дії:
# сигнали зміни циклу під час перепризначення M6 net tool-change-loop iocontrol.0.tool-change iocontrol.0.tool-changed
Якщо ви з якоїсь причини хочете перепризначити Tx (підготувати), відповідні виводи iocontrol також потрібно зациклити.
5.5. Написання змін та підготовка процедур, що передбачають букву «О»
Стандартні прологи та епілоги, що знаходяться у файлі ncfiles/remap_lib/python-stdglue/stdglue.py, передають кілька «відкритих параметрів» процедурі перепризначення.
«Відкритий параметр» — це іменована локальна змінна, видима в процедурі перемапування, яка відповідає внутрішній змінній інтерпретатора, що має значення для поточного перемапування. Відкриті параметри налаштовуються у відповідному пролозі та перевіряються в епілозі. Їх можна змінювати в процедурі перемапування, і ці зміни будуть відображені в епілозі. Відкриті параметри для вбудованих кодів, що підлягають перемапуванню, такі:
-
T(prepare_prolog):#<tool>,#<pocket> -
M6(change_prolog):#<інструмент_в_шпинделі>,#<вибраний_інструмент>,#<поточна_кишеня>,#<вибрана_кишеня> -
M61(settool_prolog):#<tool>,#<pocket> -
S(setspeed_prolog):#<speed> -
F(setfeed_prolog):#<feed>
Якщо у вас є конкретні потреби в додаткових параметрах, які будуть видимими, їх можна просто додати до прологу — практично всі внутрішні функції інтерпретатора видимі для Python.
5.6. Внесення мінімальних змін до вбудованих кодів, включаючи M6
Пам’ятайте, що зазвичай перепризначення коду повністю вимикає всю внутрішню обробку для цього коду.
Однак у деяких ситуаціях може бути достатньо додати кілька кодів навколо існуючої вбудованої реалізації M6, наприклад, зонд довжини інструменту, але крім цього зберегти поведінку вбудованої функції M6.
Оскільки це може бути типовим сценарієм, вбудована поведінка перепризначених кодів стала доступною в процедурі перепризначення. Інтерпретатор виявляє, що ви посилаєтеся на перепризначений код у процедурі, яка повинна перевизначити його поведінку. У цьому випадку використовується вбудована поведінка — наразі вона ввімкнена для набору: M6, M61,T, S, F. Зверніть увагу, що в іншому випадку посилання на код у власній процедурі перепризначення буде помилкою — рекурсією перепризначення.
Легке повертання вбудованого елемента виглядатиме ось так (у випадку M6):
REMAP=M6 modalgroup=6 ngc=mychange
o<mychange> sub M6 (use built in M6 behavior) (.. перейдіть до перемикача довжини інструмента, виміряйте довжину інструмента та встановіть її..) o<mychange> endsub m2
|
Caution
|
Під час перевизначення вбудованого коду не вказуйте жодних початкових нулів у G- або M-кодах — наприклад, скажімо REMAP=M1 .., а не REMAP=M01 .... |
Дивіться каталог configs/sim/axis/remap/extend-builtins для отримання повної конфігурації, яка є рекомендованою відправною точкою для власної роботи з розширення вбудованого коду.
5.7. Визначення заміни T (підготовка)
Якщо ви впевнені в default implementation, вам не потрібно це робити. Але перепризначення також є способом обійти недоліки поточної реалізації, наприклад, щоб не блокувати доти, доки не буде встановлено контакт «tool-prepared».
Наприклад, що ви могли б зробити:
- У перепризначеному T просто встановіть еквівалент виводу tool-prepare, але не чекайте тут на tool-prepared.
- У відповідному перепризначеному M6 зачекайте на tool-prepared на самому початку процедури O-word.
Знову ж таки, контакти iocontrol tool-prepare/tool-prepared не використовуватимуться та будуть замінені контактами motion.*, тому ці контакти потрібно буде зациклити:
# сигнали підготовки циклу під час перепризначення T net tool-prep-loop iocontrol.0.tool-prepare iocontrol.0.tool-prepared
Отже, ось налаштування для перепризначеного T:
REMAP=T prolog=prepare_prolog epilog=prepare_epilog ngc=prepare
def prepare_prolog(self,**words): try: cblock = self.blocks[self.remap_level] if not cblock.t_flag: return "T requires a tool number" tool = cblock.t_number if tool: (status, pocket) = self.find_tool_pocket(tool) if status != INTERP_OK: return "T%d: pocket not found" % (tool) else: pocket = -1 # this is a T0 - tool unload # ці змінні будуть видимі в підслові ngc O-word # як локальні змінні #<інструмент> та #<кишеня>, і можуть бути # змінено там - епілог отримає змінені дані # цінності self.params["tool"] = tool self.params["pocket"] = pocket return INTERP_OK except Exception, e: return "T%d/prepare_prolog: %s" % (int(words['t']), e)
Мінімальна процедура підготовки ngc знову виглядає так:
o<prepare> sub ; повернення позитивного значення для фіксації: o<prepare> endsub [1] m2
І епілог:
def prepare_epilog(self, **words): try: if self.return_value > 0: self.selected_tool = int(self.params["tool"]) self.selected_pocket = int(self.params["pocket"]) emccanon.SELECT_TOOL(self.selected_tool) return INTERP_OK else: return "T%d: aborted (return code %.1f)" % (int(self.params["tool"]),self.return_value) except Exception, e: return "T%d/prepare_epilog: %s" % (tool,e)
Функції «prepare_prolog» та «prepare_epilog» є частиною стандартного модуля «nc_files/remap_lib/python-stdglue/stdglue.py». Цей модуль призначений для загального вирішення більшості стандартних ситуацій перепризначення.
5.8. Обробка помилок: обробка переривання
Вбудована процедура зміни інструменту має деякі запобіжні заходи на випадок переривання програми, наприклад, натискання клавіші Escape в AXIS під час зміни. Ваша перепризначена функція не має нічого подібного, тому може знадобитися явне очищення, якщо перепризначений код буде перервано. Зокрема, процедура перепризначення може встановити модальні налаштування, які не бажано залишати активними після переривання. Наприклад, якщо ваша процедура перепризначення має коди руху (G0, G1, G38..) і перепризначення переривається, то останній модальний код залишиться активним. Однак, швидше за все, ви захочете, щоб будь-який модальний рух був скасований при перериванні перепризначення.
Для цього використовується функція [RS274NGC]ON_ABORT_COMMAND. Ця опція INI визначає виклик процедури O-word, яка виконується, якщо task з якоїсь причини перериває виконання програми. on_abort отримує один параметр, що вказує причину виклику процедури переривання, який може бути використаний для умовного очищення.
Причини визначено у файлі nml_intf/emc.hh
EMC_ABORT_TASK_EXEC_ERROR = 1, EMC_ABORT_AUX_ESTOP = 2, EMC_ABORT_MOTION_OR_IO_RCS_ERROR = 3, EMC_ABORT_TASK_STATE_OFF = 4, EMC_ABORT_TASK_STATE_ESTOP_RESET = 5, EMC_ABORT_TASK_STATE_ESTOP = 6, EMC_ABORT_TASK_STATE_NOT_ON = 7, EMC_ABORT_TASK_ABORT = 8, EMC_ABORT_INTERPRETER_ERROR = 9, // інтерпретатор не вдався під час попереднього зчитування EMC_ABORT_INTERPRETER_ERROR_MDI = 10, // інтерпретатор не вдалося виконати MDI EMC_ABORT_USER = 100 // коди переривання, визначені користувачем, починаються тут
[RS274NGC] ON_ABORT_COMMAND=O <on_abort> call
Запропонована процедура on_abort виглядатиме так (адаптуйте до своїх потреб):
o<on_abort> sub G54 (зсуви від початку координат встановлені за замовчуванням) G17 (вибір площини XY) G90 (абсолютний) G94 (режим подачі: одиниці/хвилина) M48 (встановлення перевищення подачі та швидкості) G40 (компенсація різака вимкнена) M5 (шпиндель вимкнено) G80 (скасувати модальний рух) M9 (туман і охолоджуюча рідина вимкнені) o100 якщо [#1 дорівнює 5] (машина увімкнена) o100 інакше якщо [#1 дорівнює 6] (машина вимкнена) o100 elseif [#1 eq 7] (estopped) o100 elseif [#1 eq 8] (msg, abort pressed) o100 else (DEBUG, error parameter is [#1]) o100 endif o<on_abort> endsub m2
|
Caution
|
Ніколи не використовуйте M2 у підпрограмі O-word, включаючи цю. Це призведе до важко виявляємих помилок. Наприклад, використання M2 у підпрограмі не призведе до правильного завершення підпрограми і залишить відкритим файл NGC підпрограми, а не вашу основну програму. |
Переконайтеся, що on_abort.ngc знаходиться вздовж шляху пошуку інтерпретатора (рекомендоване розташування: SUBROUTINE_PATH, щоб не захаращувати каталог NC_FILES внутрішніми процедурами).
Оператори в цій процедурі зазвичай гарантують, що будь-який стан після переривання був очищений, наприклад, правильне скидання виводів HAL. Див. приклад. configs/sim/axis/remap/rack-toolchange.
Зверніть увагу, що завершення перепризначеного коду шляхом повернення INTERP_ERROR з епілогу (див. попередній розділ) також призведе до виклику процедури on_abort.
5.9. Обробка помилок: невдача процедури NGC перепризначеного коду
Якщо у вашій процедурі обробника ви визначили, що сталася якась помилка, не використовуйте M2 для завершення обробника - див. вище:
Якщо достатньо відобразити повідомлення про помилку оператора та зупинити поточну програму, використовуйте функцію (abort, `__<message>__), щоб завершити обробник із повідомленням про помилку. Зверніть увагу, що ви можете замінити пронумеровані, іменовані, INI та HAL параметри в тексті, як у цьому прикладі (див. також `tests/interp/abort-hot-comment/test.ngc):
o100 if [..] (певна умова помилки) (abort, Bad Things! p42=#42 q=#<q> INI=#<_ini[a]x> pin=#<_hal[component.pin]) o100 endif
|
Note
|
Розширення змінних INI та HAL є необов’язковим і може бути вимкнено у файлі INI |
Якщо потрібні більш детальні дії з відновлення, використовуйте ідіому, викладену в попередньому прикладі:
-
Визначте функцію епілогу, навіть якщо вона просто сигналізує про помилку,
-
передати від’ємне значення з обробника, щоб сигналізувати про помилку,
-
перевірити значення, що повертається у функції епілогу,
-
вжити будь-яких необхідних заходів щодо відновлення,
-
повернути рядок повідомлення про помилку з обробника, який встановить повідомлення про помилку інтерпретатора та перерве програму (майже як
abort, message=).
Це повідомлення про помилку буде відображено в інтерфейсі користувача, а повернення INTERP_ERROR призведе до обробки цієї помилки як будь-якої іншої помилки під час виконання.
Зверніть увагу, що як (abort, <msg> ), так і повернення INTERP_ERROR з епілогу призведуть до виклику будь-якого обробника ON_ABORT, якщо він визначений (див. попередній розділ).
6. Перепризначення інших існуючих кодів:
6.1. Автоматичний вибір передачі при перепрограмуванні S (встановлення швидкості шпинделя)
Потенційним застосуванням перепрограмованого коду S може бути «автоматичний вибір передачі» залежно від швидкості. У процесі перепрограмування перевіряється, чи можна досягти бажаної швидкості з урахуванням поточного положення передачі, і, якщо ні, то передача змінюється відповідним чином.
6.2. Налаштування поведінки M0, M1
Прикладом використання перепризначення M0/M1 може бути налаштування поведінки існуючого коду. Наприклад, може бути бажано вимкнути шпиндель, туман і заливку під час паузи програми M0 або M1, а потім знову увімкнути ці налаштування після відновлення програми.
Повний приклад саме цього дивіться у configs/sim/axis/remap/extend-builtins/, де M1 адаптується, як зазначено вище.
6.3. Налаштування поведінки M7, M8, M9
Прикладом перепризначення вбудованої поведінки M7/M8/M9 є можливість передачі додаткових аргументів, таких як P-слово, для складнішого керування охолоджуючою рідиною (наприклад, через інструмент проти зовнішнього потоку охолоджуючої рідини).
Див. configs/sim/axis/remap/extend-builtins/ для прикладу такого розширення вбудованої поведінки для M7, M8 та M9.
7. Створення нових циклів G-коду
Цикл G-коду, як він використовується тут, має працювати наступним чином:
-
Під час першого виклику збираються пов’язані слова та виконується цикл G-коду.
-
Якщо наступні рядки просто продовжують слова параметрів, що застосовуються до цього коду, але не додають нового G-коду, попередній G-код виконується повторно з відповідно зміненими параметрами.
Приклад: Припустимо, що у вас є G84.3, визначений як перепризначений цикл G-коду з наступним сегментом INI (див. тут для детального опису cycle_prolog та cycle_epilog):
[RS274NGC] # Цикл з процедурою на букву О: G84.3 <X- Y- Z- Q- P-> REMAP=G84.3 argspec=xyzabcuvwpr prolog=cycle_prolog ngc=g843 epilog=cycle_epilog modalgroup=1
Виконання наступних рядків:
g17 (1) g84.3 x1 y2 z3 r1 (2) x3 y4 p2 (3) x6 y7 z5 (4) G80
спричиняє наступне (зверніть увагу, що R є липким, а Z також липким, оскільки площина є XY):
-
g843.ngcвикликається зі словами x=1, y=2, z=3, r=1 -
g843.ngcвикликається зі словами x=3, y=4, z=3, p=2, r=1 -
g843.ngcвикликається зі словами x=6, y=7, z=3, r=1 -
Цикл
G84.3скасовано.
Окрім створення нових циклів, це забезпечує простий метод перепакування існуючих G-кодів, які не працюють як цикли. Наприклад, код жорсткого нарізування різьби G33.1 не працює як цикл. За допомогою такого обгортника можна легко створити новий код, який використовує G33.1, але працює як цикл.
Дивіться configs/sim/axis/remap/cycle для повного прикладу цієї функції. Вона містить два цикли, один з процедурою NGC, як вище, та приклад циклу, використовуючи лише Python.
8. Налаштування вбудованого Python
Плагін Python обслуговує як інтерпретатор, так і task, якщо так налаштовано, і тому має власний розділ PYTHON у INI-файлі.
8.1. Плагін Python: конфігурація INI-файлу
-
[PYTHON] -
-
TOPLEVEL =<filename> -
Ім’я файлу початкового скрипта Python, який буде виконано під час запуску. Цей скрипт відповідає за налаштування структури назви пакета, див. нижче.
-
PATH_PREPEND =<directory> -
Додайте цей каталог до
PYTHON_PATH. Повторювана група. -
PATH_APPEND =<directory> -
Додати цей каталог до
PYTHON_PATH. Група, що повторюється. -
LOG_LEVEL =<integer> -
Рівень реєстрації дій, пов’язаних із плагінами. Збільште цей рівень, якщо підозрюєте проблеми. Може бути дуже детальним.
-
RELOAD_ON_CHANGE =[0|1] -
Перезавантажте скрипт «TOPLEVEL», якщо файл було змінено. Зручно для налагодження, але наразі створює деякі накладні витрати під час виконання. Вимкніть цю опцію для робочих конфігурацій.
-
8.2. Виконання інструкцій Python з інтерпретатора
Для виконання команд ad-hoc було додано «гарячий коментар» Python. Вихідні дані Python за замовчуванням надходять до stdout, тому для перегляду результатів необхідно запустити LinuxCNC з терміналу. Приклад для вікна MDI:
;py,print(2*3)
Зверніть увагу, що екземпляр інтерпретатора доступний тут як this, тому ви також можете виконати:
;py,print(this.tool_table[0].toolno)
Ось підхід до використання підпрограми O-word для зчитування запису файлу налаштувань та додавання його як параметра G-коду.
(filename myofile.ngc) o<myofile> sub ;py,from interpreter import * ;py,import os ;py,from qtvcp.lib.preferences import Access ; find and print the preference file path ;py,CONFPATH = os.environ.get('CONFIG_DIR', '/dev/null') ; adjust for your preference file name ;py,PREFFILE = os.path.join(CONFPATH,'qtdragon.pref') ;py,print(PREFFILE) ; get an preference instance ;py,Pref = Access(PREFFILE) ; load a preference and print it ;py,this.params['toolToLoad']=Pref.getpref('Tool to load', 0, int,'CUSTOM_FORM_ENTRIES') ;py,print('Tool to load->:',this.params['toolToLoad']) ; return the value o<myofile> endsub [#<toolToLoad>] M2
9. Програмування вбудованого Python в інтерпретаторі RS274NGC
9.1. Простір імен плагінів Python
Очікується, що простір імен буде структуровано наступним чином:
-
oword -
Будь-які виклики в цьому модулі є кандидатами для процедур Python O-word. Зверніть увагу, що модуль Python
owordперевіряється перед тестуванням процедури NGC з тим самим іменем — фактично імена вowordприховують файли NGC з тим самим базовим іменем. -
remap -
Очікується, що тут будуть знаходитися виклики Python, на які посилаються в опціях
prolog,epilogабоpythonспецифікації argspec. -
namedparams -
Функції Python у цьому модулі розширюють або перевизначають простір імен попередньо визначених іменованих параметрів, див. adding predefined parameters.
9.2. Інтерпретатор з точки зору Python
Інтерпретатор є існуючим класом C++ («Interp»), визначеним у «src/emc/rs274ngc». Концептуально всі виклики Python oword.<function> та remap.<function> є методами цього класу Interp, хоча явного визначення цього класу в Python немає (це екземпляр обгортки «Boost.Python»), і тому вони отримують як перший параметр self, який можна використовувати для доступу до внутрішніх компонентів.
9.3. Функції інтерпретатора __init__ та __delete__
Якщо модуль TOPLEVEL визначає функцію __init__, вона буде викликана після повного налаштування інтерпретатора (зчитування INI-файлу та синхронізації стану з моделлю світу).
Якщо модуль TOPLEVEL визначає функцію __delete__, вона буде викликана один раз перед завершенням роботи інтерпретатора та після того, як постійні параметри будуть збережені у PARAMETER_FILE.
Примітка: на даний момент обробник __delete__ не працює для екземплярів інтерпретатора, створених шляхом імпорту модуля gcode. Якщо вам потрібна еквівалентна функціональність (що досить малоймовірно), розгляньте можливість використання модуля Python atexit.
# це буде визначено в модулі TOPLEVEL def __init__(self): # додайте сюди будь-яку одноразову ініціалізацію if self.task: # це екземпляр milltask interp pass else: # це екземпляр інтерпретації, що не є milltask pass def __delete__(self): # додайте сюди будь-які дії з очищення/збереження стану if self.task: # як вище pass else: pass
Ця функція може використовуватися для ініціалізації будь-яких атрибутів на стороні Python, які можуть знадобитися пізніше, наприклад, у функціях remap або O-word, а також для збереження або відновлення стану, що виходить за межі того, що надає PARAMETER_FILE.
Якщо є дії з налаштування або очищення, які повинні відбуватися тільки в екземплярі інтерпретатора milltask (на відміну від екземпляра інтерпретатора, який знаходиться в модулі Python gcode і служить для попереднього перегляду/відображення прогресу, але ні для чого іншого), це можна перевірити за допомогою evaluating self.task.
Приклад використання __init__ та __delete__ можна знайти в configs/sim/axis/remap/cycle/python/toplevel.py, де ініціалізуються атрибути, необхідні для обробки циклів у ncfiles/remap_lib/python-stdglue/stdglue.py (та імпортованих у файл configs/sim/axis/remap/cycle/python/remap.py).
9.4. Умови виклику: NGC до Python
Код Python викликається з NGC у таких ситуаціях:
-
під час звичайного виконання програми:
-
коли виконується виклик O-слова, наприклад
O<proc> call, і ім’яoword.procвизначено та доступне для виклику -
коли виконується коментар типу
;py,<оператор Python>. -
під час виконання перепризначеного коду: будь-які обробники
prolog=,python=таepilog=.
-
Аргументи:
-
self -
Екземпляр інтерпретатора.
-
*args -
Список фактичних позиційних параметрів. Оскільки кількість фактичних параметрів може змінюватися, найкраще використовувати такий стиль оголошення:
# це буде визначено в модулі oword def mysub(self, *args): print("number of parameters passed:", len(args)) for a in args: print(a)
Так само, як процедури NGC можуть повертати значення, так само можуть повертати значення і підпрограми Python, що використовують літеру O-word. Очікується, що вони або повертатимуть значення
-
немає значення (немає оператора
returnабо значенняNone), -
значення типу "float" або "integer",
-
рядок, це означає «це повідомлення про помилку, перервати програму». Працює як
(abort, msg).
Будь-який інший тип повертаного значення викличе виняток Python.
У викликаючому середовищі NGC доступні такі попередньо визначені іменовані параметри:
-
#<value> -
Значення, повернене останньою викликаною процедурою. Ініціалізується як 0.0 під час запуску. Відображається в інтерпретації як
self.return_value(число з плаваючою комою). -
#<value_returned> -
Вказує, що остання викликана процедура виконала
returnабоendsubз явним значенням. 1.0, якщо true. Встановлюється на 0.0 для кожноговиклику. В інтерпретації було виявленоself.value_returned(int).
Див. також приклад tests/interp/value-returned.
Аргументи:
-
self -
Екземпляр інтерпретатора.
-
words -
Словник параметрів ключових слів. Якщо був присутній argspec, слова збираються з поточного блоку відповідно і передаються в словник для зручності (слова також можна було б отримати безпосередньо з блоку виклику, але це вимагає більш глибоких знань про внутрішню структуру інтерпретатора). Якщо argspec не був переданий або були вказані тільки опціональні значення, і жодне з них не було присутнє в блоці виклику, цей словник буде порожнім. Імена слів перетворюються в нижній регістр.
Приклад дзвінка:
def minimal_prolog(self, **words): # у модулі перепризначення print(len(words)," words passed") for w in words: print("%s: %s" % (w, words[w])) if words['p'] < 78: # NB: could raise an exception if p were optional return "failing miserably" return INTERP_OK
Повернуті значення:
-
INTERP_OK -
Повернути це у разі успіху. Вам потрібно імпортувати це з
interpreter. - текст повідомлення
-
Повернення рядка з обробника означає «це повідомлення про помилку, перервіть програму». Працює як
(abort,<msg>).
Аргументи:
-
self -
Екземпляр інтерпретатора.
-
words -
Словник параметрів ключових слів. Той самий словник kwargs, що й для прологів та епілогів (див. вище).
Приклад мінімальної функції `python=":
def useless(self, **words): # у модулі перепризначення return INTERP_OK
Повернуті значення:
-
INTERP_OK -
Повернути це у разі успіху
- текст повідомлення
-
Повернення рядка з обробника означає «це повідомлення про помилку, перервіть програму». Працює як
(abort,<msg>).
Якщо обробнику потрібно виконати «операцію зупинки черги» (зміна інструменту, зондування, зчитування виводу HAL), тоді він повинен призупинити виконання за допомогою наступного оператора:
-
yield INTERP_EXECUTE_FINISH -
Це сигналізує
taskзупинити попереднє читання, виконати всі операції в черзі, виконати операцію «queue-buster», синхронізувати стан інтерпретатора зі станом машини, а потім сигналізувати інтерпретатору продовжувати роботу. На цьому етапі функція відновлюється з оператора, що йде за операторомyield ...
Queue busters переривають процедуру в точці, де викликається така операція, тому процедуру потрібно перезапустити після синхронізації інтерпретатора (synch()). Коли це відбувається, процедура повинна знати, чи вона перезапущена, і де продовжувати. Для перезапуску процедури використовується метод генератора Python.
Це демонструє продовження виклику з єдиною точкою перезапуску:
def read_pin(self,*args): # зачекайте 5 секунд, поки цифровий вхід 00 перейде у високий рівень emccanon.WAIT(0,1,2,5.0) # передати керування після виконання черги-вимкнення: yield INTERP_EXECUTE_FINISH # Виконання post-sync() відновлюється тут: pin_status = emccanon.GET_EXTERNAL_DIGITAL_INPUT(0,0); print("pin status=",pin_status)
|
Warning
|
Функція «yield» є крихкою. На використання «yield INTERP_EXECUTE_FINISH» поширюються такі обмеження: |
-
Код Python, який виконує yield INTERP_EXECUTE_FINISH, має бути частиною процедури перепризначення. Yield не працює в процедурі Python oword.
-
Підпрограма перепризначення Python, що містить оператор yield INTERP_EXECUTE_FINISH, може не повертати значення, як це відбувається зі звичайними операторами yield Python.
-
Код, що слідує за yield, не може рекурсивно викликати інтерпретатор, як у випадку з
self.execute("<mdi command>"). Це архітектурне обмеження інтерпретатора, яке неможливо виправити без серйозного перепроектування.
9.5. Умовні позначення викликів: Python до NGC
Код NGC виконується з Python, коли
-
виконується метод
self.execute(<код NGC>[,<номер рядка>]), або -
Під час виконання перепризначеного коду, якщо визначено функцію
prolog=, процедура NGC, задана вngc=, виконується одразу після цього.
Обробник прологу не викликає обробник, але готує середовище його виклику, наприклад, встановлюючи попередньо визначені локальні параметри.
Концептуально пролог та епілог виконуються на одному рівні виклику, як і процедура O-word, тобто після встановлення виклику підпрограми та до завершення підпрограми endsub або return.
Це означає, що будь-яка локальна змінна, створена в пролозі, буде локальною змінною в процедурі O-word, а будь-які локальні змінні, створені в процедурі O-word, залишаються доступними під час виконання епілогу.
Масив self.params обробляє читання та встановлення пронумерованих і іменованих параметрів. Якщо іменований параметр починається з _ (підкреслення), він вважається глобальним параметром; якщо ні, він є локальним для процедури виклику. Крім того, пронумеровані параметри в діапазоні 1..30 обробляються як локальні змінні; їхні початкові значення відновлюються при поверненні/завершенні процедури O-word.
Ось приклад переробленого коду, що демонструє вставку та вилучення параметрів у/з процедури O-word:
REMAP=m300 prolog=insert_param ngc=testparam epilog=retrieve_param modalgroup=10
def insert_param(self, **words): # у модулі перепризначення print("insert_param call level=",self.call_level) self.params["myname"] = 123 self.params[1] = 345 self.params[2] = 678 return INTERP_OK def retrieve_param(self, **words): print("retrieve_param call level=",self.call_level) print("#1=", self.params[1]) print("#2=", self.params[2]) try: print("result=", self.params["result"]) except Exception,e: return "testparam forgot to assign #<result>" return INTERP_OK
o<testparam> sub (debug, call_level=#<_call_level> myname=#<myname>) ; спробуйте закоментувати наступний рядок і запустіть ще раз #<result> = [#<myname> * 3] #1 = [#1 * 5] #2 = [#2 * 3] o<testparam> endsub m2
self.params() повертає список усіх імен змінних, визначених на даний момент. Оскільки myname є локальною, вона зникає після завершення епілогу.
Ви можете рекурсивно викликати інтерпретатор з коду Python наступним чином:
self.execute(<NGC code>[,<line number>])
Приклади:
self.execute("G1 X%f Y%f" % (x,y)) self.execute("O <myprocedure> call", currentline)
Можливо, вам варто перевірити, чи повертається значення < INTERP_MIN_ERROR. Якщо ви використовуєте багато операторів execute(), ймовірно, легше перехопити InterpreterException, як показано нижче.
|
Caution
|
Метод вставки/отримання параметрів, описаний у попередньому розділі, у цьому випадку не працює. Його достатньо лише для
Функція рекурсивного виклику є крихкою. |
Якщо interpreter.throw_exceptions не дорівнює нулю (за замовчуванням 1), і self.execute() повертає помилку, викликається виняток InterpreterException. InterpreterException має такі атрибути:
-
line_number -
де сталася помилка
-
line_text -
оператор NGC, що спричиняє помилку
-
error_message -
повідомлення про помилку інтерпретатора
Помилки можна перехопити наступним пайтонським способом:
import interpreter interpreter.throw_exceptions = 1 ... try: self.execute("G3456") # підняти виняток InterpreterException except InterpreterException,e: msg = "%d: '%s' - %s" % (e.line_number,e.line_text, e.error_message) return msg # замінити вбудоване повідомлення про помилку
Шар канону практично повністю складається з вільних функцій. Приклад:
import emccanon def example(self,*args): .... emccanon.STRAIGHT_TRAVERSE(line,x0,y0,z0,0,0,0,0,0,0) emccanon.STRAIGHT_FEED(line,x1,y1,z1,0,0,0,0,0,0) ... return INTERP_OK
Фактичні функції канону оголошені в src/emc/nml_intf/canon.hh та реалізовані в src/emc/task/emccanon.cc. Реалізацію функцій Python можна знайти в src/emc/rs274ncg/canonmodule.cc.
9.6. Вбудовані модулі
Вбудовані такі модулі:
-
interpreter -
Відкриває внутрішні механізми класу Interp. Див.
src/emc/rs274ngc/interpmodule.ccта регресійний тестtests/remap/introspect. -
emccanon -
Виявляє більшість дзвінків
src/emc/task/emccanon.cc.
10. Додавання попередньо визначених іменованих параметрів
Інтерпретатор постачається з набором попередньо визначених іменованих параметрів для доступу до внутрішнього стану з рівня мови NGC. Ці параметри доступні лише для читання та є глобальними, тому їм не можна призначити значення.
Додаткові параметри можна додати, визначивши функцію в модулі namedparams. Ім’я функції визначає ім’я нового попередньо визначеного іменованого параметра, на який тепер можна посилатися в довільних виразах.
Щоб додати або перевизначити іменований параметр:
-
Додайте модуль
namedparams, щоб інтерпретатор міг його знайти, -
визначте нові параметри за допомогою функцій (див. нижче). Ці функції отримують
self(екземпляр інтерпретатора) як параметр і тому можуть отримати доступ до довільного стану. Для повернення значення можна використовувати довільні можливості Python. -
Імпортуйте цей модуль зі скрипта
TOPLEVEL.
# namedparams.py # тривіальний приклад def _pi(self): return 3.1415926535
#<circumference> = [2 * #<radius> * #<_pi>]
Очікується, що функції в namedparams.py повертатимуть значення типу float або int. Якщо повертається рядок, це встановлює повідомлення про помилку інтерпретатора та перериває виконання.
Тільки функції з початковим символом підкреслення додаються як параметри, оскільки це конвенція RS274NGC для глобальних змінних.
Можна перевизначити існуючий попередньо визначений параметр, додавши функцію Python з такою ж назвою до модуля namedparams. У цьому випадку під час запуску генерується попередження.
Хоча наведений вище приклад не є надто корисним, зверніть увагу, що практично весь внутрішній стан інтерпретатора доступний з Python, тому довільні предикати можуть бути визначені таким чином. Трохи більш просунутий приклад дивіться в tests/remap/predefined-named-params.
11. Стандартні процедури клею
Оскільки багато завдань перемапування дуже схожі, я почав збирати робочі процедури прологу та епілогу в одному модулі Python. Наразі їх можна знайти в «ncfiles/remap_lib/python-stdglue/stdglue.py», де вони надають такі процедури:
11.1. T: prepare_prolog і prepare_epilog
Вони завершують процедуру NGC для підготовки інструменту Tx.
prepare_prologНаступні параметри стають видимими для процедури NGC:
-
#<tool>- параметр слова на літеруT -
#<pocket>- відповідну кишеню
Якщо запитується інструмент номер нуль (тобто вивантаження інструменту), відповідне гніздо передається як -1.
Це помилка, якщо:
-
Номер інструменту не вказано як параметр T,
-
Інструмент не знайдено в таблиці інструментів.
Зверніть увагу, що якщо ви не встановите параметр [EMCIO] RANDOM_TOOLCHANGER=1, номер інструмента та гнізда будуть ідентичними, а номер гнізда з таблиці інструментів ігнорується. Наразі це обмеження.
prepare_epilog-
Очікується, що процедура NGC поверне додатне значення, інакше видається повідомлення про помилку, що містить повернене значення, і інтерпретатор перериває роботу.
-
У разі, якщо процедура NGC виконала команду T (яка потім посилається на вбудовану поведінку T), ніяких подальших дій не виконується. Це можна використовувати, наприклад, для мінімального коригування вбудованої поведінки, додаючи перед нею або після неї деякі інші оператори.
-
В іншому випадку параметри
#<tool>та#<pocket>витягуються з простору параметрів підпрограми. Це означає, що процедура NGC може змінювати ці значення, і епілог враховує змінені значення. -
Потім виконується команда Canon
SELECT_TOOL(#<інструмент>).
11.2. M6: change_prolog і change_epilog
Це завершує процедуру NGC для зміни інструменту M6.
change_prolog-
Якщо попередньої команди T, яка б спричинила вибір кишені, не було, пролог переривається з повідомленням про помилку.
-
Якщо компенсація радіуса різця увімкнена, пролог переривається з повідомленням про помилку.
Потім, такі параметри експортуються до процедури NGC:
-
#<tool_in_spindle>: номер інструменту, що наразі завантажений -
#<вибраний_інструмент>: номер вибраного інструменту -
#<selected_pocket>: індекс tooldata вибраного інструменту
-
Очікується, що процедура NGC поверне додатне значення, інакше видається повідомлення про помилку, що містить повернене значення, і інтерпретатор перериває роботу.
-
У разі, якщо процедура NGC виконала команду M6 (яка потім посилається на вбудовану поведінку M6), ніяких подальших дій не виконується. Це можна використовувати, наприклад, для мінімального коригування вбудованої поведінки, додаючи перед нею або після неї деякі інші оператори.
-
В іншому випадку параметр
#<selected_pocket>витягується з простору параметрів підпрограми і використовується для встановлення змінної інтерпретатораcurrent_pocket. Знову ж таки, процедура може змінити це значення, і епілог враховує змінене значення. -
Потім виконується команда Canon
CHANGE_TOOL(#<вибрана_кишеня>). -
Нові параметри інструменту (зміщення, діаметр тощо) встановлено.
11.3. Цикли G-коду: cycle_prolog and cycle_epilog
Вони обгортають процедуру NGC, щоб вона могла діяти як цикл, тобто код руху зберігається після завершення виконання. Якщо наступний рядок містить тільки слова-параметри (наприклад, нові значення X, Y), код виконується знову з новими словами-параметрами, об’єднаними в набір параметрів, заданих у першому виклику.
Ці процедури призначені для роботи у поєднанні з параметром argspec=<words>. Хоча це просте у використанні, у реальному сценарії слід уникати argspec і проводити більш ретельне дослідження блоку вручну, щоб отримати кращі повідомлення про помилки.
Запропонована специфікація аргументів виглядає наступним чином:
REMAP=G<somecode> argspec=xyzabcuvwqplr prolog=cycle_prolog ngc=<ngc procedure> epilog=cycle_epilog modalgroup=1
Це дозволить cycle_prolog визначити сумісність будь-яких слів осі, наданих у блоці, див. нижче.
cycle_prolog-
Визначте, чи відповідають слова, передані з поточного блоку, умовам, описаним у Помилки стандартного циклу.
-
Експортувати слова осі як
<x>,#<y>тощо; не вдасться, якщо слова осі з різних груп (XYZ) (UVW) використовуються разом або якщо задано будь-яке з (ABC). -
Експортувати L- як
#<l>; за замовчуванням 1, якщо не вказано. -
Експортувати P- як
#<p>; невдача, якщо p менше 0. -
Експортувати R- як
#<r>; невдача, якщо r не вказано, або менше дорівнює 0, якщо вказано. -
Помилка, якщо швидкість подачі дорівнює нулю, або якщо увімкнено зворотну подачу за часом чи компенсацію різця.
-
-
Визначте, чи це перший виклик G-коду циклу, якщо так:
-
Додайте передані слова (згідно з argspec) до набору фіксованих параметрів, які зберігаються протягом кількох викликів.
-
-
Якщо ні (рядок продовження з новими параметрами), то
-
об’єднати передані слова з існуючим набором закріплених параметрів.
-
-
Експортуйте набір фіксованих параметрів до процедури NGC.
cycle_epilog-
Визначити, чи справді поточний код був циклом, якщо так, то
-
зберегти поточний режим руху, тому рядок продовження без коду руху виконає той самий код руху.
-
11.4. S (Встановити швидкість): setspeed_prolog та setspeed_epilog
TBD
11.5. F (Встановити потік): setfeed_prolog та setfeed_epilog
TBD
11.6. M61 Встановити номер інструменту: settool_prolog та settool_epilog
TBD
12. Перепризначене виконання коду
12.1. Середовище виклику процедур NGC під час перепризначення
Зазвичай процедура O-word викликається з позиційними параметрами. Ця схема є дуже обмеженою, особливо в разі наявності необов’язкових параметрів. Тому угода про виклик була розширена, щоб використовувати щось віддалено схоже на модель ключових аргументів Python.
Див. LINKTO Підпрограми G-коду/основного типу: sub, endsub, return, call.
12.2. Вкладені перепризначені коди
Перепризначені коди можуть бути вкладеними так само, як і виклики процедур, тобто перепризначений код, процедура NGC якого посилається на якийсь інший перепризначений код, виконається належним чином.
Максимальна кількість перепризначень рівня вкладеності наразі становить 10.
12.3. Порядковий номер під час перепризначення
Номери послідовностей поширюються та відновлюються так само, як і у викликах O-word. Дивіться tests/remap/nested-remaps/word для регресійного тесту, який показує відстеження номерів послідовностей під час вкладених перемаплень на трьох рівнях глибини.
12.4. Прапорці налагодження
Наступні прапорці стосуються перепризначення та виконання, пов’язаного з Python:
|
|
відстежує виконання підпрограм типу O-word |
|
|
відстежує виконання коду, пов’язаного з перепризначенням |
|
|
виклики плагіна Python |
|
|
доступ до іменованих параметрів трасування |
|
|
визначений користувачем - не інтерпретується LinuxCNC |
|
|
визначений користувачем - не інтерпретується LinuxCNC |
або ці прапорці у змінну [EMC]DEBUG за потреби. Поточний список прапорців налагодження див. у src/emc/nml_intf/debugflags.h.
12.5. Налагодження вбудованого коду Python
Налагодження вбудованого коду Python складніше, ніж налагодження звичайних скриптів Python, і існує лише обмежена кількість налагоджувачів. Працюючим рішенням на основі відкритого коду є використання Eclipse IDE [https://www.eclipse.org] та плагіна Eclipse https://www.pydev.org [PydDev] і його функції віддаленого налагодження https://pydev.org/manual_adv_remote_debugger.html [remote debugging feature].
Щоб скористатися цим підходом:
-
Встановіть Eclipse через «Центр програмного забезпечення Ubuntu» (виберіть перший варіант).
-
Встановіть плагін PyDev з сайт оновлень Pydev.
-
Налаштуйте дерево вихідного коду LinuxCNC як проект Eclipse.
-
Запустіть сервер налагодження Pydev в Eclipse.
-
Переконайтеся, що вбудований код Python може знайти модуль
pydevd.py, який поставляється разом із цим плагіном — він захований десь глибоко в каталозі інсталяції Eclipse. Встановіть зміннуpydevdу файліutil.py, щоб відобразити розташування цього каталогу. -
Додайте
import pydevdдо вашого модуля Python - див. прикладиutil.pyтаremap.py. -
Викличте
pydevd.settrace()у вашому модулі в певний момент, щоб підключитися до сервера налагодження Eclipse Python — тут ви можете встановлювати точки зупинки у вашому коді, перевіряти змінні, кроки тощо, як завжди.
|
Caution
|
pydevd.settrace() блокуватиме виконання, якщо Eclipse та сервер налагодження Pydev не запущено. |
Щоб охопити останні два кроки: процедура o<pydevd> допомагає перейти в відладчик з режиму MDI. Дивіться також функцію call_pydevd у файлі util.py та її використання у файлі remap.involute для встановлення точки зупинки.
Ось скріншот налагодження процедури involute в Eclipse/PyDev, як показано вище:
Дивіться код Python у configs/sim/axis/remap/getting-started/python для отримання детальної інформації.
13. Попередній перегляд осі та виконання перепризначеного коду
Для повного попереднього перегляду траєкторії інструменту перемальованого коду необхідно вжити деяких запобіжних заходів. Щоб зрозуміти, що відбувається, давайте розглянемо процес попереднього перегляду та виконання (це стосується випадку AXIS, але інші випадки є подібними):
Спочатку зверніть увагу, що є два незалежні екземпляри інтерпретатора:
-
Один приклад у програмі milltask, яка виконує програму після натискання кнопки «Пуск» і фактично змушує машину рухатися.
-
Другий екземпляр в інтерфейсі користувача, основним призначенням якого є створення попереднього перегляду траєкторії інструменту. Він «виконує» програму після її завантаження, але фактично не призводить до рухів верстата.
Тепер припустимо, що ваша процедура перемапування містить операцію зонда G38, наприклад, як частину зміни інструменту з автоматичним відключенням довжини інструменту. Якщо зонд не працює, це буде явною помилкою, тому ви відобразите повідомлення і перервете програму.
А що щодо попереднього перегляду цієї процедури? Під час попереднього перегляду, звичайно, невідомо, чи зонд досягне успіху чи зазнає невдачі, але ви, ймовірно, захочете побачити максимальну глибину зонда і припустити, що він досягне успіху, і продовжити виконання, щоб переглянути подальші рухи. Крім того, немає сенсу відображати повідомлення «зонд зазнав невдачі» і припиняти виконання під час попереднього перегляду.
Щоб вирішити цю проблему, потрібно перевірити, чи виконується ваша процедура в режимі попереднього перегляду чи виконання. Це можна перевірити, протестувавши #<_task> predefined named parameter — під час фактичного виконання значення буде 1, а під час попереднього перегляду — 0. Повний приклад використання див. у файлі configs/sim/axis/remap/manual-toolchange-with-tool-length-switch/nc_subroutines/manual_change.ngc.
У Embedded Python екземпляр task можна перевірити, перевіривши self.task — це буде 1 в екземплярі milltask та 0 в екземплярі(ах) попереднього перегляду.
14. Перепризначені коди
14.1. Існуючі коди, які можна перепризначити
Поточний набір існуючих кодів, відкритих для перевизначення, такий:
-
Tx (Підготуйтеся)
-
M6 (Змінити інструмент)
-
M61 (Встановити номер інструменту)
-
M0 (тимчасово призупинити запущену програму)
-
M1 (тимчасово призупинити запущену програму, якщо увімкнено додатковий вимикач зупинки)
-
M7 (активувати туман охолоджувальної рідини)
-
M8 (активувати залив охолоджувальної рідини)
-
M9 (деактивація туману та затоплення охолоджувальної рідини)
-
M60 (заміна піддонних човників та тимчасова зупинка запущеної програми)
-
M62 .. M65 (керування цифровим виходом)
-
M66 (очікування введення)
-
M67, M68 (керування аналоговим виходом)
-
S (встановлена швидкість шпинделя)
-
F (встановити канал)
14.2. Наразі нерозподілені G-коди:
Наразі нерозподілені G-коди (для перепризначення) необхідно вибирати з порожніх полів наступних таблиць. Усі перелічені G-коди вже визначені в поточній реалізації LinuxCNC і не можуть використовуватися для перепризначення нових G-кодів. (Розробникам, які додають нові G-коди до LinuxCNC, рекомендується також додавати свої нові G-коди до цих таблиць.)
| # | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
|---|---|---|---|---|---|---|---|---|---|---|
00 |
|
|||||||||
01 |
|
|||||||||
02 |
|
|||||||||
03 |
|
|||||||||
04 |
|
|||||||||
05 |
|
|
|
|
||||||
06 |
||||||||||
07 |
|
|||||||||
08 |
|
|||||||||
09 |
| # | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
|---|---|---|---|---|---|---|---|---|---|---|
10 |
|
|||||||||
11 |
||||||||||
12 |
||||||||||
13 |
||||||||||
14 |
||||||||||
15 |
||||||||||
16 |
||||||||||
17 |
|
|
||||||||
18 |
|
|
||||||||
19 |
|
|
| # | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
|---|---|---|---|---|---|---|---|---|---|---|
20 |
|
|||||||||
21 |
|
|||||||||
22 |
||||||||||
23 |
||||||||||
24 |
||||||||||
25 |
||||||||||
26 |
||||||||||
27 |
||||||||||
28 |
|
|
||||||||
29 |
| # | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
|---|---|---|---|---|---|---|---|---|---|---|
30 |
|
|
||||||||
31 |
||||||||||
32 |
||||||||||
33 |
|
|
||||||||
34 |
||||||||||
35 |
||||||||||
36 |
||||||||||
37 |
||||||||||
38 |
||||||||||
39 |
| # | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
|---|---|---|---|---|---|---|---|---|---|---|
40 |
|
|||||||||
41 |
|
|
||||||||
42 |
|
|
||||||||
43 |
|
|
||||||||
44 |
||||||||||
45 |
||||||||||
46 |
||||||||||
47 |
||||||||||
48 |
||||||||||
49 |
|
| # | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
|---|---|---|---|---|---|---|---|---|---|---|
50 |
||||||||||
51 |
||||||||||
52 |
||||||||||
53 |
|
|||||||||
54 |
|
|||||||||
55 |
|
|||||||||
56 |
|
|||||||||
57 |
|
|||||||||
58 |
|
|||||||||
59 |
|
|
|
|
| # | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
|---|---|---|---|---|---|---|---|---|---|---|
60 |
|
|||||||||
61 |
|
|
||||||||
62 |
||||||||||
63 |
||||||||||
64 |
|
|||||||||
65 |
||||||||||
66 |
||||||||||
67 |
||||||||||
68 |
||||||||||
69 |
| # | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
|---|---|---|---|---|---|---|---|---|---|---|
70 |
|
|||||||||
71 |
|
|
|
|||||||
72 |
|
|
|
|||||||
73 |
||||||||||
74 |
||||||||||
75 |
||||||||||
76 |
|
|||||||||
77 |
||||||||||
78 |
||||||||||
79 |
| # | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
|---|---|---|---|---|---|---|---|---|---|---|
80 |
|
|||||||||
81 |
|
|||||||||
82 |
|
|||||||||
83 |
|
|||||||||
84 |
|
|||||||||
85 |
|
|||||||||
86 |
|
|||||||||
87 |
|
|||||||||
88 |
|
|||||||||
89 |
|
| # | Gxx | Gxx.1 | Gxx.2 | Gxx.3 | Gxx.4 | Gxx.5 | Gxx.6 | Gxx.7 | Gxx.8 | Gxx.9 |
|---|---|---|---|---|---|---|---|---|---|---|
90 |
|
|
||||||||
91 |
|
|
||||||||
92 |
|
|
|
|
||||||
93 |
|
|||||||||
94 |
|
|||||||||
95 |
|
|||||||||
96 |
|
|||||||||
97 |
|
|||||||||
98 |
|
|||||||||
99 |
|
14.3. Наразі нерозподілені M-коди:
Ці M-коди наразі не визначені в поточній реалізації LinuxCNC і можуть бути використані для визначення нових M-кодів. (Розробникам, які визначають нові M-коди в LinuxCNC, рекомендується вилучити їх із цієї таблиці.)
| # | Mx0 | Mx1 | Mx2 | Mx3 | Mx4 | Mx5 | Mx6 | Mx7 | Mx8 | Mx9 |
|---|---|---|---|---|---|---|---|---|---|---|
00-09 |
||||||||||
10-19 |
|
|
|
|
|
|
|
|
|
|
20-29 |
|
|
|
|
|
|
|
|
|
|
30-39 |
|
|
|
|
|
|
|
|
|
|
40-49 |
|
|
|
|
|
|
|
|
||
50-59 |
|
|
|
|
|
|
||||
60-69 |
||||||||||
70-79 |
|
|
|
|
|
|
||||
80-89 |
|
|
|
|
|
|
|
|
|
|
90-99 |
|
|
|
|
|
|
|
|
|
|
Усі M-коди від M100 до M199 вже є користувацькими M-кодами, і їх не слід перепризначати.
Усі M-коди від M200 до M999 доступні для перепризначення.
15. Короткий огляд виконання програми LinuxCNC
Щоб зрозуміти перепризначення кодів, може бути корисним розглянути виконання task та інтерпретатора стосовно перепризначення.
15.1. Стан інтерпретатора
Концептуально, стан інтерпретатора складається зі змінних, які поділяються на такі категорії:
-
Інформація про конфігурацію (зазвичай з INI-файлу)
-
«Світова модель» – представлення фактичного стану машини
-
Модальний стан і налаштування - відноситься до стану, який «переноситься» між виконанням окремих кодів NGC - наприклад, після увімкнення шпинделя і встановлення швидкості, він залишається в цьому налаштуванні до вимкнення. Те саме стосується багатьох кодів, таких як подача, одиниці виміру, режими руху (подача або швидкий) і так далі.
-
Стан виконання інтерпретатора - Містить інформацію про блок, що виконується в даний момент, про те, чи перебуваємо ми в підпрограмі, про змінні інтерпретатора тощо. Більша частина цього стану агрегується в - досить несистематичній -
структурі _setup(див. interp_internals.hh).
15.2. Взаємодія завдання та інтерпретатора, черга та попереднє читання
Частина task в LinuxCNC відповідає за координацію фактичних команд машини - рух, взаємодію з HAL тощо. Вона сама по собі не обробляє мову RS274NGC. Для цього task викликає інтерпретатор для аналізу та виконання наступної команди - або з MDI, або з поточного файлу.
Виконання інтерпретатора генерує канонічні операції машини, які фактично переміщують щось. Однак вони не виконуються відразу, а ставляться в чергу. Фактичне виконання цих кодів відбувається в частині task LinuxCNC: канонічні команди витягуються з черги інтерпретатора і виконуються, що призводить до фактичних рухів машини.
Це означає, що зазвичай інтерпретатор значно випереджає фактичне виконання команд — розбір програми може бути завершений ще до того, як почнуться будь-які помітні рухи. Така поведінка називається «попереднім читанням».
15.3. Прогнозування положення машини
Щоб заздалегідь обчислити канонічні машинні операції під час попереднього зчитування, інтерпретатор повинен мати можливість передбачити позицію машини після кожного рядка G-коду, а це не завжди можливо.
Розглянемо простий приклад програми, яка виконує відносні переміщення (G91), і припустимо, що верстат починає роботу з координат x=0, y=0, z=0. Відносні переміщення означають, що результат наступного переміщення залежить від положення попереднього:
N10 G91 N20 G0 X10 Y-5 Z20 N30 G1 Y20 Z-5 N40 G0 Z30 N50 M2
Тут інтерпретатор може чітко передбачити позиції машини для кожного рядка:
Після N20: x=10 y=-5 z=20; після N30: x=10 y=15 z=15; після N40: x=10 y=15 z=45 і таким чином можна розібрати всю програму та згенерувати канонічні операції заздалегідь.
15.4. Засоби запобігання черзі порушують прогнозування позиції
Однак повне попереднє читання можливе лише тоді, коли інтерпретатор може заздалегідь передбачити вплив позиції для кожного рядка в програмі. Розглянемо модифікований приклад:
N10 G91 N20 G0 X10 Y-5 Z20 N30 G38.3 Z-10 N40 O100 if [#5070 EQ 0] N50 G1 Y20 Z-5 N60 O100 else N70 G0 Z30 N80 O100 endif N90 G1 Z10 N95 M2
Щоб заздалегідь обчислити рух в N90, інтерпретатор повинен знати, де знаходиться верстат після рядка N80, а це залежить від того, чи була команда зонда успішною, що невідомо до її фактичного виконання.
Отже, деякі операції несумісні з подальшим попереднім читанням. Вони називаються виключателями черги, і вони:
-
Зчитування значення виводу HAL за допомогою M66: значення виводу HAL непередбачуване.
-
Завантаження нового інструменту за допомогою M6: геометрія інструменту непередбачувана.
-
Виконання зонду з G38.n: кінцеве положення та успіх/невдача непередбачувані.
15.5. Як поводяться з тими, хто не пропускає черги
Щоразу, коли інтерпретатор зустрічає помилку, що обходить чергу, йому потрібно зупинити попереднє читання та чекати, поки не стане доступним відповідний результат. Це працює так:
-
Коли зустрічається такий код, інтерпретатор повертає спеціальний код повернення до
task(INTERP_EXECUTE_FINISH). -
Цей код повернення сигналізує
task, щоб на даний момент припинити попереднє читання, виконати всі накопичені до цього моменту канонічні команди в черзі (включаючи останню, яка є черговою), а потім «синхронізувати стан інтерпретатора з моделлю світу». Технічно це означає оновлення внутрішніх змінних для відображення значень виводів HAL, перезавантаження геометрії інструменту після M6 і передачу результатів зондування. -
Метод інтерпретатора synch() викликається
taskі робить саме це — зчитує всі значення factual моделі світу, які є релевантними для подальшого виконання. -
У цей момент
taskпродовжується та викликає інтерпретатор для подальшого читання — доки програма не завершиться або не буде виявлено інший обхідник черги.
15.6. Порядок слів та порядок виконання
Одне або декілька «слів» можуть бути присутніми в «блоці» NGC, якщо вони сумісні (деякі з них є взаємовиключними і повинні бути в різних рядках). Однак модель виконання передбачає суворе дотримання порядку виконання кодів, незалежно від їхнього розташування в вихідному рядку (G-code Order of Execution).
15.7. Розбір
Після зчитування рядка (в режимі MDI або з поточного файлу NGC) він аналізується, а прапорці та параметри встановлюються в «структурному блоці» (struct _setup, member block1). Ця структура містить всю інформацію про поточний рядок джерела, але незалежно від різного порядку кодів у поточному рядку: якщо кілька кодів сумісні, будь-який порядок джерела призведе до встановлення однакових змінних у структурному блоці. Відразу після розбору всі коди в блоці перевіряються на сумісність.
15.8. Виконання
Після успішного розбору блок виконується за допомогою execute_block(), і тут різні елементи обробляються відповідно до порядку виконання.
Якщо знайдено «черговий руйнівник», у стані інтерпретатора встановлюється відповідний прапорець (toolchange_flag, input_flag, probe_flag), і інтерпретатор повертає значення INTERP_EXECUTE_FINISH, сигналізуючи викликанню («task») про «тимчасове припинення попереднього читання та повторну синхронізацію». Якщо після виконання всіх елементів не виявлено жодного порушника черги, повертається INTERP_OK, що сигналізує про можливість продовження попереднього читання.
Коли читання вперед продовжується після синхронізації, task знову починає виконувати операції інтерпретатора read(). Під час наступної операції читання перевіряються вищезазначені прапорці та встановлюються відповідні змінні (оскільки щойно було виконано synch(), значення тепер є поточними). Це означає, що наступна команда вже виконується в правильно встановленому контексті змінних.
15.9. Виконання процедури
Процедури O-word дещо ускладнюють обробку queue buster. Queue buster може бути знайдений десь у вкладеній процедурі, що призводить до напівзавершеного виклику процедури, коли повертається INTERP_EXECUTE_FINISH. Task забезпечує синхронізацію моделі світу та продовжує аналіз і виконання, доки виконується процедура (call_level > 0).
15.10. Як зараз працює зміна інструменту
Дії, що відбуваються в LinuxCNC, дещо складні, але необхідно отримати загальне уявлення про те, що відбувається на даний момент, перш ніж ви почнете адаптувати ці механізми до власних потреб.
Зверніть увагу, що перепризначення існуючого коду повністю вимикає всю внутрішню обробку для цього коду. Це означає, що крім бажаної поведінки (яка, ймовірно, описана за допомогою NGC O-word або процедури Python), вам потрібно відтворити внутрішні дії інтерпретатора, що в сукупності призведе до повної заміни існуючого коду. Це можна зробити в коді прологу та епілогу.
Кілька процесів «цікавляться» інформацією про інструменти: task та його інтерпретатор, а також інтерфейс користувача. Також процес halui.
Інформація про інструмент зберігається в структурі «emcStatus», яка є спільною для всіх сторін. Одним з її полів є масив «toolTable», який містить опис, завантажений з файлу таблиці інструментів (номер інструменту, діаметр, кут нахилу передньої частини, кут нахилу задньої частини та орієнтація для токарного верстата, інформація про зміщення інструменту).
Авторитетним джерелом і єдиним процесом, який фактично «встановлює» інформацію про інструменти в цій структурі, є процес «iocontrol». Всі інші процеси лише звертаються до цієї структури. Інтерпретатор фактично містить локальну копію таблиці інструментів.
Для цікавих, поточна структура emcStatus доступна за допомогою Python statements. Інтерпретатор сприймає інструмент, завантажений на даний момент, наприклад, доступний за допомогою:
;py,from interpreter import *
;py,print(this.tool_table[0])
Щоб побачити результати, потрібно запустити LinuxCNC з вікна терміналу.
15.11. Як працює Tx (інструмент підготовки)
TxВсе, що робить інтерпретатор, це оцінює параметр toolnumber, шукає відповідний індекс tooldata, запам’ятовує його в змінній selected_pocket для подальшого використання та ставить в чергу команду canon (SELECT_TOOL). Див. Interp::convert_tool_select в src/emc/rs274/interp_execute.cc.
Коли task починає обробку SELECT_TOOL, він надсилає повідомлення EMC_TOOL_PREPARE процесу iocontrol, який обробляє більшість дій, пов’язаних з інструментами в LinuxCNC.
У поточній реалізації task фактично чекає, поки iocontrol завершить операцію позиціонування змінювача, що, на мій погляд, не є необхідним, оскільки це суперечить ідеї, що підготовка змінювача та виконання коду можуть відбуватися паралельно.
Коли iocontrol бачить команду вибору кишені, він виконує відповідне коливання контакту HAL - він встановлює контакт «tool-prep-number», щоб вказати, який інструмент буде наступним, піднімає контакт «tool-prepare» і чекає, поки контакт «tool-prepared» не стане високим.
Коли змінник відповідає повідомленням «інструмент готовий», він вважає етап підготовки завершеним і сигналізує завданню про продовження. Знову ж таки, це «очікування», на мою думку, не є абсолютно необхідним.
TxДивіться функції Python prepare_prolog та prepare_epilog у nc_files/remap_lib/python-stdglue/stdglue.py.
15.12. Як працює M6 (інструмент зміни)
Ви повинні повністю це зрозуміти, перш ніж зможете адаптувати це. Це дуже важливо для написання прологу та епілогу для перепрограмованого M6. Перепрограмування існуючих кодів означає, що ви вимикаєте внутрішні кроки, які виконуються зазвичай, і повторюєте їх настільки, наскільки це необхідно для ваших цілей.
Навіть якщо ви не знайомі з C, я пропоную вам переглянути код Interp::convert_tool_change у src/emc/rs274/interp_convert.cc.
Коли перекладач бачить M6, він:
-
перевіряє, чи вже було виконано команду
T(перевірте, чи settings->selected_pocket має бути >= 0), і, якщо ні, видає повідомлення Need tool prepared -Txx- for toolchange. -
Перевірте, чи активна компенсація на радіус різця, і якщо так, видасть повідомлення про помилку «Неможливо змінити інструменти, якщо ввімкнено компенсацію радіуса різця».
-
зупинити шпиндель, окрім випадків, коли встановлено опцію INI "TOOL_CHANGE_WITH_SPINDLE_ON".
-
генерувати швидкий рух «Z вгору», якщо встановлено опцію INI «TOOL_CHANGE_QUILL_UP».
-
якщо було встановлено TOOL_CHANGE_AT_G30:
-
перемістити індексатори A, B та C, якщо це можливо
-
генерувати швидкий рух до позиції G30
-
-
виконати канонну команду CHANGE_TOOL з вибраною кишенею як параметром. CHANGE_TOOL виконає:
-
генерувати швидкий перехід до TOOL_CHANGE_POSITION, якщо так встановлено в INI
-
поставити в чергу NML-повідомлення EMC_TOOL_LOAD для
task.
-
-
встановити параметри нумератора 5400-5413 відповідно до нового інструменту
-
сигналізувати
taskпро припинення виклику інтерпретатора для попереднього зчитування, повертаючи INTERP_EXECUTE_FINISH, оскільки M6 є обробником черги.
task, коли бачить команду CHANGE_TOOLЗнову ж таки, не набагато більше, ніж перекладання відповідальності на iocontrol шляхом надсилання йому повідомлення EMC_TOOL_LOAD та очікування, поки iocontrol зробить свою справу.
-
він стверджує штифт "зміни інструменту"
-
він очікує, поки штифт "зміна інструменту" стане активним
-
коли це сталося:
-
дессерт "зміна інструменту"
-
встановіть контакти "tool-prep-number" та "tool-prep-pocket" на нуль
-
виконайте функцію load_tool() з кишенею як параметром.
-
Останній крок фактично встановлює записи таблиці інструментів у структурі «emcStatus». Фактичні дії залежать від того, чи була встановлена опція RANDOM_TOOLCHANGER INI, але в кінці процесу «toolTable[0]» відображає інструмент, який наразі знаходиться у шпинделі.
Коли це сталося:
-
iocontrolсигналізуєtaskпро необхідність виконання. -
taskповідомляє інтерпретатору про необхідність виконати операцію synch(), щоб побачити, що змінилося. -
Інтерпретатор synch() отримує всю необхідну інформацію з моделі світу, зокрема й таблицю змінених інструментів.
З цього моменту інтерпретатор має повне уявлення про модель світу та продовжує читати далі.
M6Дивіться функції Python change_prolog та change_epilog у nc_files/remap_lib/python-stdglue/stdglue.py.
15.13. Як працює M61 (Зміна номера інструменту)
M61 потрібен невід’ємний параметр Q (номер інструмента). Якщо дорівнює нулю, це означає «вивантажити інструмент», інакше «встановити поточний номер інструмента на Q».
M61Приклад перевизначення Python для M61 можна знайти у функції set_tool_number у nc_files/remap_lib/python-stdglue/stdglue.py.
16. Статус
-
Функція RELOAD_ON_CHANGE досить погана. Перезапустіть після зміни файлу Python.
17. Зміни
-
Раніше для повернення повідомлень про помилки та завершення роботи з помилкою використовувався метод «self.set_errormsg(text)», за яким слідував «return INTERP_ERROR». Зараз його замінено на просте повернення рядка з обробника Python або підпрограми oword. Це встановлює повідомлення про помилку та припиняє роботу програми. Раніше не було чіткого способу припинення роботи підпрограми Python O-word.
18. Налагодження
У розділі [EMC] INI-файлу параметр DEBUG можна змінити, щоб отримувати різні рівні налагоджувальних повідомлень під час запуску LinuxCNC з терміналу.
Рівень налагодження, 0 означає відсутність повідомлень. Інші значення див. у src/emc/nml_intf/debugflags.h.
DEBUG = 0x00000002 # конфігурація
DEBUG = 0x7FFFDEFF # без інтерпретації, oword
DEBUG = 0x00008000 # тільки py
DEBUG = 0x0000E000 # py + remap + Oword
DEBUG = 0x0000C002 # py + remap + config
DEBUG = 0x0000C100 # py + remap + інтерпретатор
DEBUG = 0x0000C140 # py + remap + інтерпретатор + повідомлення NML
DEBUG = 0x0000C040 # py + remap + NML
DEBUG = 0x0003E100 # py + remap + інтерпретатор + oword + сигнали + namedparams
DEBUG = 0x10000000 # EMC_DEBUG_USER1 - трасування операторів
DEBUG = 0x20000000 # EMC_DEBUG_USER2 - перехоплення в дебагер Python
DEBUG = 0x10008000 # USER1, PYTHON
DEBUG = 0x30008000 # USER1,USER2, PYTHON # USER2 змусить involute спробувати підключитися до pydev
DEBUG = 0x7FFFFFFF # Усі повідомлення про налагодження