Одна из задач, встречающаяся при разработке новых изделий – это задача компоновки их упаковки.

image

В качестве иллюстрации этого утверждения приведем пример, в котором с такой задачей столкнулись даже IT-специалисты. Как раз на момент написания этой статьи программисты одного из подразделений ООО «Специальный технологический центр» занимались подбором комплектующих для комплекса радиоэлектронной аппаратуры, в состав которого входили серверы и автоматизированные рабочие места. Мне как конструктору в этот момент пришлось принять участие в выборе тары для укладки ЗИП (первое изображение под катом). Как могут решаться подобного рода задачи – см. далее.



Чтобы выбрать ящик, необходимо узнать габариты упаковываемых изделий, а затем скомпоновать их.

К настоящему времени задачи упаковки уже решались в ряде исследований. В терминологии теории алгоритмов эти задачи относятся к классу NP-полных задач, не имеющих точных алгоритмов ее решения за полиноминальное время [1]. С примером решения данной задачи с помощью эвристического алгоритма можно также ознакомиться в работе [2], а применение частного случая эвристического алгоритма – генетического алгоритма – увидеть в работе [3]. Многие из этих решений включают в себя разработку приложений, визуализирующих результаты работы алгоритмов. Однако в перечисленных источниках не упоминается о передаче результатов работы таких программ в CAD-систему SolidWorks (или другую систему с аналогичной функциональностью) для дальнейшего оформления конструкторской документации. Фрагмент чертежа упаковки, оформленного в программе Компас, показан ниже на рисунке.



Другой причиной, побудившей автора написать данную статью являются затраты времени, с которыми сталкивается разработчик при поиске методов решения типовых задач программирования с использованием API SolidWorks. Документация на API указанной программы на английском языке, а примеры решения таких задач часто встречаются на англоязычных форумах.

Таким образом, основными задачами, решаемыми в данной статье являются:

  1. Показать принципиальную возможность моделирования упаковки с использованием API SolidWork.
  2. Продемонстрировать некоторые практические примеры решения типовых задач программирования.

Отдельные примеры, относящиеся ко второй задаче, были рассмотрены в статье [4].

Формализуем описание исходных данных для моделирования.

Имеется множество n размещаемых объектов (изделий), i=1, 2,…, n. Каждый i-й блок характеризуют три параметра – размеры по осям $ L_x $, $ L_y $ и $ L_z $. Все изделия смещены относительно начала координат 3D-модели сборки на неотрицательные величины:

по оси X: $ [0, D_{xi}]; $

по оси Y: $[0, D_{yi}]; $

по оси Z: $[0, D_{zi}]$

Добавим также в описание задачи одно условие, которое следует учитывать при моделировании. В некоторых из упаковок встречается задача консервации изделия с использованием силикагеля. Силикагель в мешочках закладывается в полиэтиленовые чехлы, которые затем завариваются. Эти мешочки имеют определенный объем. Для равномерной укладки предлагается использовать прокладки из пенопласта с вырезами, которые накладываются на места укладки силикагеля и фиксируются стрейч-пленкой.

Таким образом, имеется множество m размещаемых прокладок, j=1, 2,…, m.

Каждая j-я прокладка аналогичным образом характеризуется размерами по осям $ L_x $, $ L_y $ и $ L_z $, неотрицательным смещением вдоль каждой из осей, а также вырезом вдоль одной из осей. Размеры выреза заданы так, как показано трех рисунках. Применение прокладок необязательно.







Также вдоль стенок ящика, в который упаковываются изделия, могут устанавливаться прокладки из пенопласта.

Эти прокладки моделируются одной деталью, которая также задается тремя размерами $ L_x $, $ L_y $ и $ L_z $ по осям, толщиной стенок S и смещением в отрицательном направлении относительно осей:

по оси X: $[D_x, 0);$

по оси Y: $[D_y, 0);$

по оси Z: $[D_z, 0).$

Помимо этого в сборке может размещаться модель ящика, задаваемая отрицательными смещениями по осям, по аналогии с предыдущей прокладкой. Ящик спроектирован в программе, рассмотренной в статье [4].

Данное формализованное описание сохраняется в виде списка в текстовом файле с кодировкой ANSI. Такая кодировка нужна для корректного отображения результатов чтения с помощью C++\CLI.

Синтаксис записи в текстовом файле приведен ниже.

#Путь к результатам
Путь к папке для сохранения результатов работы
Наименование файла компоновки (без расширения)
#Конец
#Упаковываемые изделия
Наименование упаковываемого изделия (без расширения)
0 – без группы, больше нуля – номер группы упаковываемых одинаковых изделий
Lx
Ly
Lz
Dx
Dy
Dz
#Конец
#Пенопласт
Наименование прокладки (без расширения)
Lx
Ly
Lz
X, Y или Z – ось, вдоль которой выполнен вырез
d1
d2
L1
L2
Dx
Dy
Dz
#Конец
#Пенопласт у стенок
Lx
Ly
Lz
S
Dx
Dy
Dz
#Конец
#Ящик
Путь к файлу 3D-модели сборки ящика
Dx
Dy
Dz
#Конец

Для реализации моделирования данной упаковки было разработано приложение на языке C++\CLI. Приложение читает вышеупомянутый текстовый файл, путь к которому передается программе через аргумент командной строки. Приложение разработано в IDE Microsoft Visual Studio 2022 (64-разрядная версия). Программа запускалась на компьютере с операционной системой Windows 10. Компьютер имел следующие характеристики: процессор Intel® Core(TM) i5-7600 CPU 3.50 ГГц, оперативная память 16 Гб. CAD-система – SolidWorks 2019 (64-разрядная). Время моделирования одной компоновки, состоящей из семи упаковываемых изделий, одной прокладки, одной прокладки у стенок ящика и самого ящика составило 1 мин 34 с.

Если рассматривать задачу укрупненно, то последовательность моделирования следующая:

  1. Чтение файла с данными.
  2. Копирование необходимых файлов шаблонов деталей в папку с результатом моделирования.
  3. Вставка моделей в компоновку.

В свою очередь, вставка моделей в компоновку реализована в следующей последовательности (на примере моделей упаковываемых изделий), представленной ниже. В скобках указаны задачи, решение которых рассматривалось в статье [4].

  1. Получение доступа к объекту типа SldWorks^ (см. статью).
  2. Отключение видимости приложения (см. задачи ускорения работы макроса в статье)
  3. Открытие файла 3D-модели компоновки.
  4. Вставка в цикле 3D-моделей упаковываемых изделий.
  5. Указание сопряжений для вставленной модели.

Вставка 3D-моделей упаковываемых изделий иллюстрируется фрагментом программного кода соответствующей функции.

//Значения переменных
// swApp - объект SldWorks^, переданный по ссылке в функцию
IModelDoc2^ swModel;
int ok; //Результат изменения свойств. Функция SetActiveConfigProperty рассмотрена в статье [4].
ModelView^ modView;
DesignTable^ DesTbl; //Таблица параметров
bool bool_D; //Результаты обращения к таблице параметров
AssemblyDoc^ assemb;
ModelDocExtension^ swModelDocExt;

//Откроем файл модели груза
swApp->OpenDoc6(gcnew System::String(str_Cargo_output_full_path.c_str()), 1, 0, "", swErrors, swWarnings);
                
//Проведем процедуры инициализации переменных для работы со свойствами
swApp->ActivateDoc2(gcnew System::String(sPackaged_cargo[i].str_Name.c_str()) +".SLDPRT", false, longstatus);
swModel = (IModelDoc2^)swApp->ActiveDoc;
                
//Пропишем в документ необходимые свойства
//Х – размер по оси Х
s_property = "X";
ok = Packing_wizard::SetActiveConfigProperty(swModel, s_property, mylib::to_string(sPackaged_cargo[i].dbl_Lx), 1);
//Y – размер по оси Y
s_property = "Y";
ok = Packing_wizard::SetActiveConfigProperty(swModel, s_property, mylib::to_string(sPackaged_cargo[i].dbl_Ly), 1);
//Z – размер по оси Z
s_property = "Z";
ok = Packing_wizard::SetActiveConfigProperty(swModel, s_property, mylib::to_string(sPackaged_cargo[i].dbl_Lz), 1);
                                                
 //Отключаем регенерацию графического окна
modView = (ModelView^)swModel->ActiveView;
modView->EnableGraphicsUpdate = false; //Отключаем регенерацию

//Получаем доступ к таблице параметров
DesTbl = (DesignTable^)swModel->GetDesignTable();
bool_D = DesTbl->Attach();

//Обновляем таблицу параметров и отключаемся от нее
bool_D = DesTbl->UpdateTable(2, true);
DesTbl->Detach();

//Сохраняем документ
swModel->Save();
 
//Активируем модель компоновки
swApp->ActivateDoc2(gcnew System::String(sOutput_data.str_Name.c_str()) + ".SLDASM", false, longstatus);

//Готовим интерфейс для вставки модели
assemb = (AssemblyDoc^)swApp->ActiveDoc;

//Вставляем модель за пределами максимальных габаритов ящика 2850х1500х2000 мм
assemb->AddComponent(gcnew System::String(str_Cargo_output_full_path.c_str()), 1.5, 2.85, 2.0);
                
//Закрываем модель груза
swApp->CloseDoc(gcnew System::String((sPackaged_cargo[i].str_Name + ".SLDPRT").c_str()));

//Активируем модель компоновки
swApp->ActivateDoc2(gcnew System::String(sOutput_data.str_Name.c_str()) + ".SLDASM", false, longstatus);
swModel = swApp->IActiveDoc2;

//Перестраиваем модель компоновки
swModel->EditRebuild3();

//Если компонент, вставленный в сборку, первый, отключаем его фиксацию
if (i == 0)
{
  swModel = (ModelDoc2^)swApp->ActiveDoc;
  swModelDocExt = swModel->Extension;
  swModelDocExt->SelectByID2(gcnew System::String((sPackaged_cargo[i].str_Name + "-1@" + sOutput_data.str_Name).c_str()),"COMPONENT", 0, 0, 0, false, 0, nullptr, 0);
  assemb->UnfixComponent();
  swModel->ClearSelection2(true);
}

Здесь следует отметить несколько моментов. Один из них – чтобы можно было задать сопряжения с неотрицательными величинами между плоскостями системы координат 3D-модели сборки и гранями вставляемых изделий, изделия вставляются с координатами, лежащими на границе внутренних габаритов ящика. Другой момент – для вставки компонента в сборку с помощью метода AddComponent он должен быть предварительно открыт методом OpenDoc6. Некоторые из показанных в коде методов уже были приведены в статье [4].

Рассмотрим теперь принятые подходы к автоматическому указанию сопряжений в модели сборки.

Для их реализации в 3D-моделях вставляемых в сборку изделий была предварительно выполнена специальная разметка с использованием справочной геометрии.

Рассмотрим первый способ автоматического указания сопряжений и первый способ разметки, показанной на рисунке ниже.



Точкой O обозначено начало координат. Точка 1 лежит на оси X, точка 2 на оси Y, точка 3 – на оси Z.

Точки 13 в системе координат сборки будут иметь координаты с индексами 13 соответственно.

Для автоматизированного задания сопряжений между плоскостями системы координат сборки и поверхностями упаковываемых изделий необходимо выделить методами API. Для выделения поверхностей достаточно указать координаты любой точки, расположенной на поверхности и не лежащей на ребрах 3D-модели.

Один из вариантов – это указать точки, лежащие в центре трех отрезков, соединяющих точки 13.

При задании сопряжений 3D-модель упаковываемого изделия будет перемещаться гранями параллельно плоскостям системы координат сборки. Поэтому точки на середине отрезков будут иметь следующие координаты.

Точка, служащая для указания сопряжений вдоль оси X:

$x_x = x_3; \\ y_x = 0,5\cdot(y_2 + y_3); \\ z_x = 0,5\cdot(z_2 + z_3).$

Точка, служащая для указания сопряжений вдоль оси Y:

$x_y = 0,5\cdot(x_1 + x_3);\\ y_y = y_1;\\ z_y = 0,5\cdot(x_1 + x_2). $

Точка, служащая для указания сопряжений вдоль оси Z:

$x_z = 0,5\cdot(x_1 + x_2);\\ y_z = 0,5\cdot(y_1 + y_2);\\ z_z = z_1. $

Приведем программный код, иллюстрирующий измерение координат точек 13 и указания сопряжений вдоль оси Х. Этот код является продолжением кода, приведенного выше.

        //Координаты точек
        Coordinates sC_point_1; //Точка 1 компонента
        Coordinates sC_point_2; //Точка 2 компонента
        Coordinates sC_point_3; //Точка 3 компонента
        Coordinates sC_X; //Характерная точка для задания сопряжения по оси X
        Coordinates sC_Y; //Характерная точка для задания сопряжения по оси Y
        Coordinates sC_Z; //Характерная точка для задания сопряжения по оси Z
  AssemblyDoc^ swAssemblyDoc;

//Измерение координат точек
                //Получение координат точки 1 во вставляемой детали
                swModelDocExt->SelectByID2(gcnew System::String(("Точка1@"+ sPackaged_cargo[i].str_Name + "-1@" + sOutput_data.str_Name).c_str()), "DATUMPOINT", 0, 0, 0, false, 0, nullptr, 0);
                Measure = swModelDocExt->CreateMeasure();
                Measure->ArcOption = 0;
                Measure->Calculate(nullptr);
                sC_point_1.dbl_X = Measure->X;
                sC_point_1.dbl_Y = Measure->Y;
                sC_point_1.dbl_Z = Measure->Z;
                swModel->ClearSelection2(true);
                //Получение координат точки 2
                swModelDocExt->SelectByID2(gcnew System::String(("Точка2@" + sPackaged_cargo[i].str_Name + "-1@" + sOutput_data.str_Name).c_str()), "DATUMPOINT", 0, 0, 0, false, 0, nullptr, 0);
                Measure = swModelDocExt->CreateMeasure();
                Measure->ArcOption = 0;
                Measure->Calculate(nullptr);
                sC_point_2.dbl_X = Measure->X;
                sC_point_2.dbl_Y = Measure->Y;
                sC_point_2.dbl_Z = Measure->Z;
                swModel->ClearSelection2(true);
                //Получение координат точки 3
                swModelDocExt->SelectByID2(gcnew System::String(("Точка3@" + sPackaged_cargo[i].str_Name + "-1@" + sOutput_data.str_Name).c_str()), "DATUMPOINT", 0, 0, 0, false, 0, nullptr, 0);
                Measure = swModelDocExt->CreateMeasure();
                Measure->ArcOption = 0;
                Measure->Calculate(nullptr);
                sC_point_3.dbl_X = Measure->X;
                sC_point_3.dbl_Y = Measure->Y;
                sC_point_3.dbl_Z = Measure->Z;
                swModel->ClearSelection2(true);

                //Переходим к расчету координат характерных точек
                //Точка для задания смещений вдоль оси Х
                sC_X.dbl_X = sC_point_3.dbl_X;
                sC_X.dbl_Y = 0.5 * (sC_point_2.dbl_Y + sC_point_3.dbl_Y);
                sC_X.dbl_Z = 0.5 * (sC_point_2.dbl_Z+ sC_point_3.dbl_Z);

                //Переходим к указанию сопряжений
                //Подготовка интерфейса
                swModel = (IModelDoc2^)swApp->ActiveDoc;
                swAssemblyDoc = (AssemblyDoc^)swModel;
                
                //Сопряжения со смещениями вдоль оси Х
                if (sPackaged_cargo[i].dbl_Dx == 0) //Сопряжение совпадения
                {
                    swModelDocExt->SelectByID2("Справа", "PLANE", 0, 0, 0, false, 0, nullptr, 0);
                    swModelDocExt->SelectByID2("", "FACE", sC_X.dbl_X, sC_X.dbl_Y, sC_X.dbl_Z, true, 0, nullptr, 0);
                    
                    swAssemblyDoc->AddMate3(0, 1, false, 0, 0, 0, 0, 0, 0, 0, 0, false, longstatus);
                    
                    swModel->ClearSelection2(true);
                    //Перестраиваем модель компоновки
                    swModel->EditRebuild3();
                }
                else //Сопряжение на расстоянии
                {
                    swModelDocExt->SelectByID2("Справа", "PLANE", 0, 0, 0, false, 0, nullptr, 0);
                    swModelDocExt->SelectByID2("", "FACE", sC_X.dbl_X, sC_X.dbl_Y, sC_X.dbl_Z, true, 0, nullptr, 0);

                    swAssemblyDoc->AddMate3(5, 1, false, sPackaged_cargo[i].dbl_Dx * 0.001, sPackaged_cargo[i].dbl_Dx * 0.001, sPackaged_cargo[i].dbl_Dx * 0.001, 0, 0, 0, 0, 0, false, longstatus);

                    swModel->ClearSelection2(true);
                    //Перестраиваем модель компоновки
                    swModel->EditRebuild3();
                }


Второй способ автоматического указания сопряжений был применен для позиционирования в сборке 3D-модели ящика. В модели ящика был построен трехмерный эскиз и на трех гранях были размещены с помощью справочной геометрии три точки. Таким образом, для указания сопряжений необходимо было выделить плоскости системы координат и вышеуказанные точки, лежащие на гранях.

В заключение отметим, что в результате проделанной работы показана принципиальная возможность моделирования упаковки с использованием API SolidWorks. Разработанное приложение может быть использовано с существующими приложениями, решающими задачи трехмерной упаковки (при условии их доработки), а также с вновь разработанным приложением, которое могло бы, например, учитывать при расчетах использование силикагеля для консервации. Предложен вариант описания информации для обмена данными между разработанным приложением и приложениями, решающими задачи трехмерного моделирования упаковки. Представлены варианты решения некоторых типовых задач взаимодействия с API SolidWorks.

Библиографический список


  1. А. А. Гиля-Зетинов, К. К. Панкратов, А. В. Хельвас Разработка алгоритма укладки паллет на полностью автоматизированном складе // Труды МФТИ .– 2019 .– т. 11 .– №1(41) .– С. 20-30.
  2. Нужнов Е.В., Барлит А.В. Трехмерная упаковка на основе эвристических процедур // Перспективные информационные технологии и интеллектуальные системы. – 2002. – № 3.– С. 95-101.
  3. Луцан М.В., Нужнов Е.В. Решение задачи трехмерной упаковки с палетированием контейнеров // Известия ЮФУ. Технические науки .– 2014 .– № 7 (156) .– С. 196-204.
  4. Опыт применения API SolidWorks для автоматизированного проектирования тары [Электронный ресурс] .– URL: habr.com/ru/company/stc_spb/blog/645115 .– (дата обращения 18.03.2022).

Комментарии (2)


  1. Stratum
    19.03.2022 10:28
    +1

    Похоже, что автор ни разу не занимался упаковкой реального оборудования. Не учтены ни масса оборудования, ни центры тяжести, ни прочность вложенной упаковки, ни вентиляция, ни герметичность, ни опасность груза, ни требования вертикального и горизонтального расположения объектов. Кроме того логистически габариты упаковки надо увязывать к стандатным европаллетам, чтобы нормально грузить и перегружать. При этом крайне желательно использовать одинаковые ящики с возможностью штабелирования, пусть и не со 100% заполнением. И это только минимум. У серьезных заказчиков требования к упаковке станиц на 300.


    1. constructor_e Автор
      19.03.2022 11:58
      +1

      Благодарю за ценные замечания! Исходя из них, объясню предпосылки написания своей статьи.

      1. Изначально я опирался на свой опыт. В двух организациях я сталкивался с такими задачами: имеется комплект разнородной аппаратуры в коробках, которые надо упаковать в деревянные ящики нестандартных типоразмеров. Ящики либо выбираются из уже спроектированных, либо проектируются под нужные размеры. Таких ящиков на комплекс немного - скажем, штук 5. В остальные ящики укладываются разнородные по размерам грузы не в коробках - антенны, металлоконструкции и др. Спутниковые антенны большой массы и габаритов - это отдельная тема, ими я не занимался. Конечно, есть ГОСТы и ОСТы на ряды типоразмеров ящиков, но я предполагаю, что в данной ситуации они не дадут особого преимущества. Комплексы, как правило, единичные или мелкосерийные, что также накладывает требования на глубину оптимизации задачи.

      2. В статье я ставил задачу описать движок для компоновки. Предполагается, что логика компоновки, требования к которой Вы перечислили, решается в другой программе.

      3. В публикациях, которые я изучал по данному вопросу, не указан полный объем логики компоновки, о котором Вы писали. Упоминались, разве что, отдельные вопросы. Например, допустимая ориентация упаковываемых изделий.

      4. Есть программа для решения задачи компоновки, не сочтите за рекламу (http://www.packer3d.ru/program/functional). Там грузы в коробках упаковываются сразу в вагоны, фуры и т.п. Она имеет далеко не всю функциональность, что Вы перечислили, если судить по данным, представленным на ее сайте.