Vismach — це набір функцій Python, які можна використовувати для створення та анімації моделей машин*.
Цей розділ присвячений вбудованій версії Qt Vismach, див. також: https://sa-cnc.com/linuxcnc-vismach/ .
1. Вступ
Vismach відображає модель у 3D-вікні перегляду, а деталі моделі анімуються, коли значення пов’язаних з ними контактів HAL змінюються.
Виглядом 3D-вікна Vismach можна маніпулювати наступним чином:
-
масштаб за допомогою колеса прокручування
-
панорамування перетягуванням середньою кнопкою миші
-
повернути перетягуванням правою кнопкою миші
-
нахил шляхом перетягування лівою кнопкою миші
Модель Vismach має форму скрипта Python та може використовувати стандартний синтаксис Python.
Це означає, що існує більше одного способу розміщення скрипта, але в наведених у цьому документі прикладах буде використано найпростіший та найбазовіший з них.
Основна послідовність створення моделі Vismach така:
-
Створіть деталі
-
Визначте, як вони рухаються
-
Об’єднайтеся в рухові групи
2. Ієрархія проектування машин
Модель дотримується логічного деревоподібного дизайну.
Уявіть собі дерево з корінням/стовбуром, гілками та меншими відгалуженнями. Якщо ви рухаєте більшу гілку, менші гілки рухатимуться разом з нею, але якщо ви рухаєте меншу гілку, більша не рухатиметься.
Проектування машин відповідає цьому концептуальному проєкту.
Візьмемо, наприклад, млин, показаний на зображенні 3D-огляду вище:
-
Якщо перемістити X, він може рухатися самостійно,
-
але якщо ви перемістите Y, це також перемістить збірку X, оскільки вона приєднана до збірки Y.
Отже, для цієї машини дерево виглядає так:
model
|
|---frame
| |
| |---base
| |
| |---column
| |
| |---top
|
|---yassembly
| |
| |---xassembly
| | |
| | |---xbase
| | |
| | |---work
| |
| |---ybase
|
|---zassembly
|
|---zframe
| |
| |---zbody
| |
| |---spindle
|
|---toolassembly
|
|---cat30
|
|---tool
|
|---tooltip
|
|---(tool cylinder function)
Як бачите, найнижчі частини повинні існувати першими, перед тим, як їх можна буде згрупувати з іншими в збірку. Отже, ви будуєте вгору від найнижчої точки дерева та збираєте їх разом.
Те саме стосується будь-якої конструкції машини: подивіться на приклад маніпулятора машини, і ви побачите, що він починається з кінчика, додається до більшої частини маніпулятора, а потім зрештою групується з основою.
3. Запустіть скрипт
Для тестування корисно включити рядок #!/usr/bin/env python3, щоб _дозволити виконання файлу безпосередньо з командного рядка.
Перше, що потрібно зробити, це імпортувати необхідні бібліотеки.
#!/usr/bin/env python3 import hal import math import sys from qtvcp.lib.qt_vismach.qt_vismach import *
4. Штифти HAL.
Спочатку бібліотека vismach вимагала створення компонента та підключення виводів HAL для керування симуляцією.
qt_vismach можна зчитувати системні піни HAL безпосередньо або, якщо бажаєте, використовувати окремі піни HAL, які необхідно визначити в компоненті HAL:
c = hal.component("samplegui") c.newpin("joint0", hal.HAL_FLOAT, hal.HAL_IN) c.newpin("joint1", hal.HAL_FLOAT, hal.HAL_IN) c.ready()
Ви можете вибрати один із двох варіантів у функціях, які приймають ці записи:
-
hal_comp -
Об’єкт компонента HAL або None.
У QtVCP, якщо ви безпосередньо зчитуєте системні виводи, тоді аргумент компонента встановлюється наNone.
-
hal_pin -
Назва виводу BIT HAL IN, який змінюватиме колір.
Якщо hal_comp має значення «None», то це має бути повна назва системного виводу, інакше це назва виводу без назви компонента.
5. Створення деталей
5.1. Імпорт файлів STL або OBJ
Найпростіше, мабуть, зробити так:
-
створення геометрії в пакеті CAD
-
імпортувати в скрипт моделі за допомогою функцій
AsciiSTL()абоAsciiOBJ().
Обидві функції можуть приймати один із двох іменованих аргументів: filename або data:
part = AsciiSTL(filename="path/to/file.stl") part = AsciiSTL(data="solid part1 facet normal ...") part = AsciiOBJ(filename="path/to/file.obj") part = AsciiOBJ(data="v 0.123 0.234 0.345 1.0 ...")
-
Деталі моделі STL додаються до простору Vismach в тих самих місцях, де вони були створені в просторі STL або OBJ, тобто в ідеалі з точкою обертання в їх початку координат.
|
Note
|
Набагато легше переміщувати модель під час побудови, якщо початок координат знаходиться в точці обертання. |
5.2. Побудувати з геометричних примітивів
Або ж деталі можна створити всередині скрипта моделі з діапазону примітивів форми.
-
assembly = collction([part1,part2,part3]) -
Колекція — це загальний контейнер пов’язаних частин
Багато фігур створюються у початку координат і після створення їх потрібно перемістити в потрібне місце.
-
cylinder = CylinderX(x1, r1, x2, r2) -
cylinder = CylinderY(y1, r1, y2, r2) -
cylinder = CylinderZ(z1, r1, z2, r2) -
Створює (необов’язково конічний) циліндр на заданій осі із заданими радіусами у заданих точках на осі.
-
sphere = Sphere(x, y, z, r) -
Створює сферу радіуса r у точці (x,y,z).
-
triangle = TriangleXY(x1, y1, x2, y2, x3, y3, z1, z2) -
triangle = TriangleXZ(x1, z1, x2, z2, x3, z3, y1, y2) -
triangle = TriangleYZ(y1, z1, y2, z2, y3, z3, x1, x2) -
Створює трикутну пластину між площинами, визначеними двома останніми значеннями, паралельними заданій площині, з вершинами, заданими трьома парами координат.
-
arc = ArcX(x1, x2, r1, r2, a1, a2) -
Створіть дугоподібну фігуру.
-
box = Box(x1, y1, z1, x2, y2, z2) -
Створює прямокутну призму з протилежними кутами у вказаних положеннях та ребрами, паралельними осям XYZ.
-
box = BoxCentered(xw, yw, zw) -
Створює бокс xw на yw на zw з центром у початку координат.
-
box = BoxCenteredXY(xw, yw, z) -
Створює блок-основу на площині WY шириною xw / yw та висотою z.
Складені деталі можуть бути створені шляхом складання цих примітивів або під час створення, або згодом:
part1 = Collection([Sphere(100,100,100,50), CylinderX(100,40,150,30)]) part2 = Box(50,40,75,100,75,100) part3 = Collection([part2, TriangleXY(10,10,20,10,15,20,100,101)]) part4 = Collection([part1, part2])
6. Переміщення частин моделі
Для складання моделі деталі може знадобитися перемістити в просторі Vismach. Початок координат не рухається — функції Translate() та Rotate() переміщують колекцію під час додавання деталей відносно стаціонарного початку координат.
6.1. Переклад деталей моделі
-
part1 = Translate([part1], x, y, z) -
Перемістіть деталь1 на задані відстані по осях x, y та z.
6.2. Обертові деталі моделі
-
part1 = Rotate([part1], theta, x, y, z) -
Повернути деталь на кут тета [градуси] навколо осі між початком координат та координатами x, y, z.
7. Анімація деталей
Для анімації моделі, що контролюється значеннями виводів HAL, є чотири функції: HalTranslate, HalRotate, HalToolCylinder та HalToolTriangle.
_Щоб деталі рухалися всередині збірки, їм потрібно визначити рухи HAL перед складанням за допомогою команди "Колекція".
Вісь обертання та вектор переміщення рухаються разом з деталлю:
-
оскільки його переміщує скрипт Vismach під час складання моделі, або
-
оскільки він рухається у відповідь на контакти HAL під час анімації моделі.
7.1. HalTranslate
-
part = HalTranslate([part], hal_comp, hal_pin, xs, ys, zs) -
-
part -
Колекція або частина.
Її можна створити заздалегідь у скрипті або, за бажанням, на цьому етапі, наприклад,
`part1 = HalTranslate([Box(....)], ...)`. +
-
hal_comp -
Наступним аргументом є HAL-компонент.
У QtVCP, якщо ви безпосередньо зчитуєте системні виводи, то аргумент component встановлюється наNone.
-
hal_pin -
Назва HAL-піна, який анімуватиме рух.
Це має відповідати існуючому HAL-піну, який описує положення суглоба, наприклад:"joint.2.pos-fb"В іншому випадку буде вказано екземпляр компонента та назву виводу цього компонента.
xs, ys, zs;; Шкали X, Y, Z.
Для декартової машини, створеної в масштабі 1:1, це зазвичай буде «1,0,0» для руху в позитивному напрямку X.
Однак, якщо файл STL був у см, а машина — в дюймах, це можна виправити, використовуючи 0,3937 ( = 1 см/1 дюйм = 1 см /2,54 см ) як масштаб.
-
7.2. HalRotate
-
part = HalRotate([part], hal_comp, hal_pin, angle_scale, x, y, z) -
Ця команда схожа за своєю роботою на
HalTranslate, за винятком того, що зазвичай спочатку необхідно перемістити деталь до початку координат, щоб визначити вісь.
-
x, y, z -
Визначає вісь обертання від початку координат точки (x, y, z).
Коли деталь переміщується назад від початку координат до свого правильного розташування, вісь обертання можна вважати «вбудованою» в деталь. -
angle_scale -
Кути повороту вказані в градусах, тому для поворотного з’єднання з масштабуванням 0-1 вам потрібно буде використовувати шкалу кутів 360.
-
7.3. HalToolCylinder
-
tool = HalToolCylinder() -
Створіть циліндр для представлення циліндричного фрезерного інструменту на основі таблиці інструментів та поточного завантаженого інструменту.
tool = HalToolCylinder() toolshape = Color([1, .5, .5, .5],[tool]) # або більш компактно: toolshape = Color([1, .5, .5, .5], [HalToolCylinder()])
7.4. HalToolTriangle
-
tool = HalToolTriangle() -
Створіть трикутник для позначення трикутного токарного інструменту, виходячи з таблиці інструментів та поточного завантаженого інструменту.
tool = HalToolTriangle() toolshape = Color([1, 1, 0, 1],[tool]) # або більш компактно: toolshape = Color([1, 1, 0, 1],[HalToolTriangle()])
7.5. Налаштовувані примітиви HAL
Усі примітивні фігури можуть мати імена виводів HAL, що замінюють координати.
Це можна зробити, додавши об’єкт компонента як першу змінну і замінивши рядок імені виводу на координату, або
замінивши повний рядок імені компонента/виводу на координату.
У цьому прикладі створюється прямокутна призма з протилежними кутами у вказаних положеннях та ребрами, паралельними осям XYZ.
Початкова координата Z буде контролюватися виводом HAL «Zstart».
box = Box(component, x1, y1, 'Zstart', x2, y2, z2) box = Box(x1, y1, 'componentName.Zstart', x2, y2, z2)
8. Збірка моделі
Щоб деталі рухалися разом, їх потрібно зібрати за допомогою команди Collection().
Важливо зібрати деталі та визначити їхні рухи у правильній послідовності.
Наприклад, щоб створити фрезерний верстат з рухомою головкою, обертовим шпинделем та анімованою тягою, вам потрібно:
-
Створіть основну частину голови.
-
Створіть шпиндель у початку координат.
-
Дайте визначення обертання.
-
Перемістіть головку до шпинделя або шпиндель до головки.
-
Створіть планку для витягування.
-
Визначте рух тяги.
-
Зберіть три частини в головний вузол.
-
Визначте рух головки.
У цьому прикладі обертання шпинделя позначається обертанням набору приводних собачок:
#Собаки для перегонів dogs = Box(-6,-3,94,6,3,100) dogs = Color([1,1,1,1],[dogs]) dogs = HalRotate([dogs],c,"spindle",360,0,0,1) dogs = Translate([dogs],-1,49,0) #Дишло draw = CylinderZ(120,3,125,3) draw = Color([1,0,.5,1],[draw]) draw = Translate([draw],-1,49,0) draw = HalTranslate([draw],c,"drawbar",0,0,1) # головка/шпиндель head = AsciiSTL(filename="./head.stl") head = Color([0.3,0.3,0.3,1],[head]) head = Translate([head],0,0,4) head = Collection([head, tool, dogs, draw]) head = HalTranslate([head],c,"Z",0,0,0.1) # база base = AsciiSTL(filename="./base.stl") base = Color([0.5,0.5,0.5,1],[base]) # покласти на нього голову base = Collection([head, base])
Нарешті, потрібно створити єдину колекцію всіх деталей машини, підлоги та роботи (якщо такі є).
Для серійної машини кожна нова частина буде додана до колекції попередньої частини.
Для паралельної машини може бути кілька "базових" частин.
Таким чином, наприклад, у scaragui.py link3 додається до link2, link2 до link1 та link1 до link0, тож остаточна модель створюється за допомогою:
model = Collection([link0, floor, table])
Тоді як модель VMC з окремими частинами, що рухаються на основі, може мати
model = Collection([base, saddle, head, carousel])
9. Інші функції
9.1. Колір
Встановлює колір відображення деталі.
-
part = Color([_colorspec_], [_part_]) -
Зверніть увагу, що на відміну від інших функцій, визначення деталі в цьому випадку йде другим.
-
_colorspec_ -
Три значення RGB (0-1.0) та непрозорість. [R, G, B, A]
Наприклад, [1.0,0,0,0.5] для червоного кольору з непрозорістю 50%.
-
9.2. HALColorFlip
Встановлює колір відображення деталі на основі призначеного стану виводу біта HAL.
-
part = HALColorFlip([_colorspec_], [_colorspec_], [_part_], hal_comp, hal_pin) -
Зверніть увагу, що на відміну від інших функцій, визначення деталі в цьому випадку йде другим.
-
_colorspec_ -
Три значення RGB (0-1.0) та непрозорість.
Наприклад, [1.0,0,0,0.5] для червоного кольору з непрозорістю 50%. -
hal_comp -
Об’єкт компонента HAL або None.
У QtVCP, якщо ви безпосередньо зчитуєте системні виводи, тоді аргумент компонента встановлюється наNone.
-
hal_pin -
Назва виводу BIT HAL IN, який змінюватиме колір.
Якщо hal_comp має значення «None», то це має бути повна назва системного виводу, інакше це назва виводу без урахування назви компонента.
-
9.3. HALColorRGB
Встановлює колір відображення деталі на основі визначеного значення виводу HAL U32.
Колір декодується з значення U32. Кожен колір є десятковим значенням від 0 до 255 (тут показано в шістнадцятковому форматі)
червоний = 0xXXXXXXRR
зелений = 0xXXXXGGXX
синій = 0xXXBBXXXX
у поєднанні як 0xXXBBGGRR
-
part = HALColorRGB([_part_], hal_comp, hal_pin, alpha=1.0) -
-
hal_comp -
Об’єкт компонента HAL або None.
У QtVCP, якщо ви безпосередньо зчитуєте системні виводи, тоді аргумент компонента встановлюється наNone.
-
hal_pin -
Назва виводу U32 HAL IN, який змінюватиме колір.
Якщо hal_comp має значення «None», то це має бути повна назва системного виводу, інакше це назва виводу без урахування назви компонента.
-
alpha= -
Встановлює непрозорість. (0-1.0)
-
9.4. Проекційний дисплей
Створює підказку у графічному інтерфейсі Vismach для відображення таких елементів, як положення осей, заголовки або повідомлення.
-
myhud = Hud()
myhud = Hud() myhud.show("Mill_XYZ")`
9.5. Проекційний дисплей HAL
Більш просунута версія Hud, яка дозволяє відображати піни HAL:
-
myhud = HalHud()
myhud = HalHud() myhud.display_on_right() myhud.set_background_color(0,.1,.2,0) myHud.set_text_color(1,1,1) myhud.show_top("Mill_XYZ") myhud.show_top("------------") myhud.add_pin('axis-x: ',"{:10.4f}","axis.x.pos-cmd") myhud.add_pin('axis-y: ',"{:10.4f}","axis.y.pos-cmd") myhud.add_pin('axis-z: ',"{:10.4f}","axis.z.pos-cmd") myhud.show("-------------")
Деякі з доступних функцій HalHUD:
-
set_background_color(red, green, blue, alpha)
-
add_pin(text, format, pinname)
-
set_text_color(red, green, blue)
9.6. ПриховатиКолекцію
HideCollection – це контейнер, який використовує вивід HAL для керування відображенням частин, що містяться в ньому. +
Логіка високого рівня на виводі HAL приховуватиме частини, що містяться в ньому.
comp.newpin("hide-chuck", hal.HAL_BIT, hal.HAL_IN) # <виготовити верстат з патроном осі А chuckassembly = HideCollection([chuckassembly],comp,'hide-chuck') # також можна використовувати ось так chuckassembly = HideCollection([chuckassembly],None,'myvismach.hide-chuck')
9.7. Колір графіка залежно від типу руху
Якщо ви хочете відображати різні кольори для різних рухів, вам потрібно додати ще трохи коду на Python.
Додайте це на початку файлу:
з імпорту qtvcp.core Стан STATUS = Status()
і це для класу Window:
STATUS.connect('motion-type-changed', lambda w, data: v.choosePlotColor(data)) # Розкоментуйте, щоб змінити колір подачі та побачити всі кольори, що друкуються на термінал #v.setColorsAttribute('FEED',(0,1,0)) #print(v.colors)
Ви можете встановити кольори DEFAULT, FEED, TRAVERSE, ARC, PROBE, ROTARYINDEX, TOOLCHANGE за допомогою setColorsAttribute().
9.8. Захоплення
-
tooltip = Capture()
Уявіть це як невидиму частину, яку потрібно прикріпити до підказки, щоб відстежувати положення та орієнтацію системи координат інструменту. Насправді це матриця перетворення, яка постійно оновлюється під час руху моделі. -
work = Capture()
Те саме, що й вище, але прикріплено до робочого столу для відстеження системи координат заготовки.
9.9. головний
Це команда, яка все це реалізує, створює відображення тощо, якщо її викликати безпосередньо з Python.
Зазвичай цей файл імпортується QtVCP, а об’єкт window() інстанціюється та вбудовується в інший екран.
-
main(model, tooltip, work, size=10, hud=myhud, rotation_vectors=None, lat=0, lon=0) -
-
_model_ -
Має бути колекція, яка містить усі деталі машини.
-
_tooltip_і_work_ -
Потрібно створити за допомогою
Capture(), щоб намалювати задній план, який в основному є позицією підказки, намальованою в робочій системі координат. Дивітьсяmill_xyz.pyдля прикладу того, як підключити підказку до інструменту, а інструмент до моделі. -
_size_ -
Встановлює ступінь візуалізації об’єму в початковому вигляді.
-
_hud_ -
стосується проекційного дисплея.
-
_rotation_vectors_або_lat, lon_ -
Можна використовувати для встановлення початкової точки огляду. Рекомендується це зробити, оскільки початкова точка огляду за замовчуванням досить некорисна безпосередньо згори.
-
10. Поради
Створіть маркер початку координат осей, щоб мати змогу бачити деталі відносно нього для цілей побудови. Ви можете видалити його після завершення.
# побудувати маркери початку осі X = CylinderX(-500,1,500,1) X = Color([1, 0, 0, 1], [X]) Y = CylinderY(-500,1,500,1) Y = Color([0, 1, 0, 1], [Y]) Z = CylinderZ(-500,1,500,1) Z = Color([0, 0, 1, 1], [Z]) origin = Collection([X,Y,Z])
Додайте його до колекції класу Window, щоб він ніколи не переміщувався з початку.
v.model = Collection([origin, model, world])
Почніть з кінчика різання та рухайтеся назад. Додайте кожну колекцію до моделі в початку координат та запустіть скрипт для підтвердження розташування, потім поверніть/змістіть та запустіть скрипт для повторного підтвердження.
11. Базова структура скрипта QtVismach
# імпорт import hal from qtvcp.lib.qt_vismach.qt_vismach import * # імпортувати статус для повідомлень про тип руху from qtvcp.core import Status STATUS = Status() # створіть тут HAL-піни, якщо потрібно #c = hal.component("samplegui") #c.newpin("joint0", hal.HAL_FLOAT, hal.HAL_IN) # створити підлогу, інструменти та працювати floor = Box(-50, -50, -3, 50, 50, 0) work = Capture() tooltip = Capture() # Зберіть та зберіть модель part1 = Collection([Box(-6,-3,94,6,3,100)]) part1 = Color([1,1,1,1],[part1]) part1 = HalRotate([part1],None,"joint.0.pos-fb",360,0,0,1) part1 = Translate([dogs],-1,49,0) # створити модель верхнього рівня model = Collection([base, saddle, head, carousel]) # ми хочемо або вбудувати в qtvcp, або відобразити безпосередньо за допомогою PyQt5 # тому створимо вікно для відображення моделі class Window(QWidget): def __init__(self): super(Window, self).__init__() self.glWidget = GLWidget() v = self.glWidget v.set_latitudelimits(-180, 180) world = Capture() # розкоментуйте, якщо є HUD # HUD має знати, де креслити #v.hud = myhud #v.hud.app = v # оновити колір графіка залежно від типу руху STATUS.connect('motion-type-changed', lambda w, data: v.choosePlotColor(data)) # розкоментуйте, щоб змінити колір стрічки #v.setColorsAttribute('FEED',(0,1,0)) # і побачити всі кольори, надруковані на терміналі #print(v.colors) v.model = Collection([model, world]) size = 600 v.distance = size * 3 v.near = size * 0.01 v.far = size * 10.0 v.tool2view = tooltip v.world2view = world v.work2view = work mainLayout = QHBoxLayout() mainLayout.addWidget(self.glWidget) self.setLayout(mainLayout) # якщо викликати цей файл безпосередньо з python3, він відобразить вікно PyQt5 # добре підходить для підтвердження частин збірки. if __name__ == '__main__': main(model, tooltip, work, size=600, hud=None, lat=-75, lon=215)