WEB - CONSTRUCTOR OF SCALABLE ROBOTIC SYSTEMS FOR SIMULATION OF COMPLEX SURFACES FOR DYNAMIC TESTING
- Authors: Grafkin A.V., Mylnikov E.N., Ponamarenko D.I.
- Issue: No 2(21) (2022)
- Pages: 78-86
- Section: Informatics
- Published: 09.08.2023
- URL: https://vmuis.ru/smus/article/view/10602
- ID: 10602
Cite item
Full Text
Abstract
This article describes the process of designing a distributed SaaS system that implements the functions of a WEB constructor using the Django framework in the Python programming language. PostgreSQL is used as a database management system (DBMS). The main functions of interaction with the database are analyzed: creation (create), reading (read), editing (update), deletion (delete) - CRUD. The REST API is used to interact with the system services. The user interface is implemented as a client using html templates using bootstrapcdn styles. To simplify debugging, logging methods are used. Coordination of the work of developers is provided using the Git version control system and the GitHub version control server.
Keywords
Full Text
Введение. В настоящее время все чаще используются WEB-приложения, так как в отличии от стандартных приложений, данные программы способны полноценно работать без установки на компьютер. WEB - конструктор проектируется с учетом возможности построения динамической системы, позволяющей моделировать сложные поверхности, которые формируются с помощью множества Stewart – платформ (рис. 1). Параметр каждой платформы (базового модуля системы) можно задать через конфигуратор соответствующего устройства. Количество устройств может меняться динамически, конфигурация динамической системы задается в конструкторе.
Рис. 1. Stewart-платформа
Проектируемая роевая система роботов состоит из Stewart – платформ и может использоваться как испытательный стенд. WEB-конструктор с распределенной системой SааS позволяет в режиме онлайн изменять систему (менять количество, расположение и характеристики), для моделирования сложных поверхностей под конкретную задачу с помощью конфигуратора.
SaaS (software as a service - программное обеспечение как услуга) - одна из форм облачных вычислений, модель обслуживания, при которой подписчикам предоставляется готовое прикладное программное обеспечение, полностью обслуживаемое провайдером. Поставщик в этой модели самостоятельно управляет приложением, предоставляя заказчикам доступ к функциям с клиентских устройств через веб-браузер [1].
Конструктор отвечает за хранение, загрузку и выгрузку законов движения – закон, по которому будет изменяться положение в пространстве базового модуля. Каждый базовый модуль изменяет свое положение согласно заданного закона движения. В совокупности базовые модули Stewart – платформ образуют систему Stewart – платформ, а законы движения каждого отдельного модуля вместе – закон движения системы.
Проектирование базы данных проекта. Анализируя предметную область, можно выделить следующие сущности – «Система Stewart платформ», «Stewart платформа» (базовый модуль), «Закон движения платформы». Система и базовый модуль имеют связь «один ко многим», так как в одной системе может быть много базовых модулей, но конкретный базовый модуль может быть только в одной системе. Базовый модуль и закон движения платформы имеют связь один ко многим, так как у закона может быть много базовых модулей, но базовый модуль может работать только по одному закону движения. Разработаем ER – модель базы данных (рис.2).
Рис. 2. ER - модель базы данных
Параметры закона движения хранятся в базе данных в виде JSON поля:
{"time start": 0, "step": 1, "repeat": 5, "coordinates": {"x": {"0": 0, "1": 0, "2": 0, "3": 0, "4": 0, "5": 0}, "y": {"0": 0, "1": 0, "2": 0, "3": 0, "4": 0, "5": 0}, "z": {"0": 0, "1": 0, "2": 0, "3": 0, "4": 0, "5": 0}, "a": {"0": 0, "1": 0, "2": 0, "3": 0, "4": 0, "5": 0}, "b": {"0": 0, "1": 0, "2": 0, "3": 0, "4": 0, "5": 0}, "g": {"0": 0, "1": 0, "2": 0, "3": 0, "4": 0, "5": 0}}}, где
"time start": время начала движения базового модуля,
"step": шаг, частота дискретизации от времени начала движения,
"repeat": количество повторений шага,
"coordinates": {“x”, “y”, “z”, “a”, “b”, “g”,}: координаты относительно осей в пространстве, где каждому моменту времени соответствует координата.
Программная реализация базы данных проекта. На первом этапе необходимо установить PostgreSQL локально на компьютер. Затем создать базу данных в PostgreSQL и учетную запись Admin [2].
Чтобы подключить созданную базу данных к Django необходимо установить модуль psycopg2. В файле settings.py/DATABASE необходимо прописать следующие настройки:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'BD_system_stewart_platform',
'USER': 'Admin',
'PASSWORD': 'adminadmin',
'HOST': 'localhost',
'PORT': '',}}
Чтобы создать таблицы в базе данных необходимо прописать следующий код в файле models.py:
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import User
class system_stewart_platform(models.Model):
title_system = models.CharField('Наименование системы', max_length=50)
discription_system = models.CharField('Описание системы', max_length=500)
LAW_TYPE=(
('Волна', 'Волна'),
('Колебания', 'Колебания'),)
law_type_system = models.CharField(verbose_name='Закон движения системы', max_length=50, choices=LAW_TYPE, null=False, blank=True, default='Волна', help_text='Выбрать из списка')
x_max_matrix = models.IntegerField('Размер матрицы по оси x')
y_max_matrix = models.IntegerField('Размер матрицы по оси y')
author = models.ForeignKey(User,related_name='system_stewart_platform_user_created', verbose_name='Пользователь', on_delete=models.CASCADE, null=True,blank=True, default=None)
time_create = models.DateTimeField(auto_now_add=True, verbose_name="Добавлено")
time_update = models.DateTimeField(auto_now=True, verbose_name="Изменено")
def _str_(self):
return self.title_system
def get_absolute_url(self):
return reverse('systemDetailView', args=[str(self.id)])
class Meta:
verbose_name = 'Система Stewart Platform'
verbose_name_plural = 'Системы Stewart Platform'
class law_for_platform(models.Model):
law_type_plat = models.CharField('Наименование типа закона', max_length=50)
amplitude = models.IntegerField('Амплитуда закона от 0 до 100')
coordinates_t = models.JSONField('Координаты и параметры для платформы')
author = models.ForeignKey(User, related_name='law_for_platform_wave_user_created',
verbose_name='Пользователь', on_delete=models.CASCADE, null=True,
blank=True, default=None)
time_create = models.DateTimeField(auto_now_add=True, verbose_name="Добавлено")
time_update = models.DateTimeField(auto_now=True, verbose_name="Изменено")
def _str_(self):
return self.law_type_plat
def get_absolute_url(self):
return reverse('LawDetailView', args=[str(self.id)])
class Meta:
verbose_name = 'Закон движения для базового модуля'
verbose_name_plural = 'Законы движения для базового модуля'
class stewart_platform(models.Model):
system_stewart_platform = models.ForeignKey(system_stewart_platform, verbose_name='Система', on_delete=models.CASCADE)
law_type = models.ForeignKey(law_for_platform, verbose_name='Закон движения платформы', on_delete=models.CASCADE)
title_platform = models.CharField('Наименование базового модуля', max_length=50)
discription_platform = models.CharField('Описание базового модуля', max_length=500)
ip_adress = models.GenericIPAddressField('IP адрес', protocol='both', unpack_ipv4=False)
port_platform = models.PositiveSmallIntegerField('Порт подключения', default=0)
position_x_in_matrix = models.IntegerField('Позиция базового модуля по оси х')
position_y_in_matrix = models.IntegerField('Позиция базового модуля по оси у')
author = models.ForeignKey(User, related_name='stewart_platform_user_created',
verbose_name=u'Пользователь', on_delete=models.CASCADE, null=True,blank=True, default=None)
time_create = models.DateTimeField(auto_now_add=True, verbose_name="Добавлено")
time_update = models.DateTimeField(auto_now=True, verbose_name="Изменено")
def _str_(self):
return self.title_platform
def get_absolute_url(self):
return reverse('platformDetailView', args=[str(self.id)])
class Meta:
verbose_name = 'Базовый модуль'
verbose_name_plural = 'Базовые модули'
С помощью команды в терминале «python manage.py createsuperuser» создаем учетную запись администратора, назначаем логин и пароль. Проводим миграции с помощью команд в терминале: «python manage.py makemigrations» и «python manage.py migrate» и регистрируем ее в панели администратора в файле admin.py:
from django.contrib import admin
from .models import system_stewart_platform, stewart_platform, law_for_platform
admin.site.register(system_stewart_platform)
admin.site.register(stewart_platform)
admin.site.register(law_for_platform)
Наполним базу данных информацией, заполнив таблицы система Stewart platform, базовый модуль Stewart platform и закон движения, например, через панель администратора или используя команды в терминале. Проверим корректность наполнения базы данных в PostgreSQL, сделав SELECT запрос (рис.3) [3].
Рис. 3. Проверка базы данных в PostgreSQL
Реализация CRUD в проекте. CRUD — акроним, обозначающий четыре базовые функции, используемые при работе с базами данных: создание (create), чтение (read), модификация (update), удаление (delete). В данном проекте реализована возможность добавления, редактирования, удаления и просмотра систем Stewart platform, базового модуля Stewart platform и закона движения Stewart platform. Реализованы формы для добавления и редактирования, а также возможности удаления экземпляров. Пользователь видит на сайте все объекты, а также отдельные страницы каждого экземпляра. Для реализации CRUD в проекте принято решение воспользоваться встроенными в Django модулями ListView, DetailView, CreateView, UpdateView, DeleteView. На первом этапе необходимо импортировать модули в файл views.py. Используем классовый подход создания views, а не функционально – ориентированный. Модуль reverse_lazy нужен для переадресации на нужную нам страницу после добавления экземпляра в базу данных.
Для того, чтобы просматривать, добавлять, изменять и удалять данные из базы данных могли только авторизованные пользователи создадим класс LoginRequiredMixin и воспользуемся методом декоратором @method_decorator(login_required). Таким образом код во view.py будет выглядеть следующим образом:
from .models import *
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
class LoginRequiredMixin(object):
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(*args, **kwargs)
class systemListView(LoginRequiredMixin, ListView):
model = system_stewart_platform
template_name = "systemStewartPlatform/system/systemListView.html"
class systemDetailView(LoginRequiredMixin, DetailView):
model = system_stewart_platform
template_name = "systemStewartPlatform/system/systemDetailView.html"
class systemCreateView(LoginRequiredMixin, CreateView):
model = system_stewart_platform
template_name = 'systemStewartPlatform/system/systemCreateView.html'
fields = ['title_system', 'discription_system', 'law_type_system', 'x_max_matrix', 'y_max_matrix', 'author']
class systemEditView(LoginRequiredMixin, UpdateView):
model = system_stewart_platform
template_name = 'systemStewartPlatform/system/systemEditView.html'
fields = ['title_system', 'discription_system', 'law_type_system', 'x_max_matrix', 'y_max_matrix', 'author']
class systemDeleteView(LoginRequiredMixin, DeleteView):
model = system_stewart_platform
template_name = 'systemStewartPlatform/system/systemDeleteView.html'
success_url = reverse_lazy('home')
class platformListView(LoginRequiredMixin, ListView):
model = stewart_platform
template_name = "systemStewartPlatform/platform/platformListView.html"
class platformDetailView(LoginRequiredMixin, DetailView):
model = stewart_platform
template_name = "systemStewartPlatform/platform/platformDetailView.html"
class platformCreateView(LoginRequiredMixin, CreateView):
model = stewart_platform
template_name = 'systemStewartPlatform/platform/platformCreateView.html'
fields = ['system_stewart_platform', 'law_type', 'title_platform', 'discription_platform', 'ip_adress', 'port_platform', 'position_x_in_matrix',
'position_y_in_matrix', 'author']
class platformEditView(LoginRequiredMixin, UpdateView):
model = stewart_platform
template_name = 'systemStewartPlatform/platform/platformEditView.html'
fields = ['system_stewart_platform', 'law_type', 'title_platform', 'discription_platform', 'ip_adress', 'port_platform', 'position_x_in_matrix',
'position_y_in_matrix', 'author']
class platformDeleteView(LoginRequiredMixin, DeleteView):
model = stewart_platform
template_name = 'systemStewartPlatform/platform/platformDeleteView.html'
success_url = reverse_lazy('home')
class LawListView(LoginRequiredMixin, ListView):
model = law_for_platform
template_name = "systemStewartPlatform/law/LawListView.html"
class LawDetailView(LoginRequiredMixin, DetailView):
model = law_for_platform
template_name = "systemStewartPlatform/law/LawDetailView.html"
class LawCreateView(LoginRequiredMixin, CreateView):
model = law_for_platform
template_name = 'systemStewartPlatform/law/LawCreateView.html'
fields = ['law_type_plat', 'amplitude', 'coordinates_t', 'author']
class LawEditView(LoginRequiredMixin, UpdateView):
model = law_for_platform
template_name = 'systemStewartPlatform/law/LawEditView.html'
fields = ['law_type_plat', 'amplitude', 'coordinates_t', 'author']
class LawDeleteView(LoginRequiredMixin, DeleteView):
model = law_for_platform
template_name = 'systemStewartPlatform/law/LawDeleteView.html'
success_url = reverse_lazy('home')
Затем для каждого созданного нами нового представления необходимо прописать маршруты в urls.py:
from django.urls import path
from .views import *
urlpatterns = [
path('systemListView', systemListView.as_view(), name='systemListView'),
path('systemDetailView/<int:pk>/', systemDetailView.as_view(), name='systemDetailView'),
path('systemNewView', systemCreateView.as_view(), name='systemCreateView'),
path('systemDetailView/<int:pk>/edit/', systemEditView.as_view(), name='systemEditView'),
path('systemDeleteView/<int:pk>/delete/', systemDeleteView.as_view(), name='systemDeleteView'),
path('platformListView', platformListView.as_view(), name='platformListView'),
path('platformDetailView/<int:pk>/', platformDetailView.as_view(), name='platformDetailView'),
path('platformNewView', platformCreateView.as_view(), name='platformCreateView'),
path('platformDetailView/<int:pk>/edit/', platformEditView.as_view(), name='platformEditView'),
path('platformDeleteView/<int:pk>/delete/', platformDeleteView.as_view(), name='platformDeleteView'),
path('LawListView', LawListView.as_view(), name='LawListView'),
path('LawDetailView/<int:pk>/', LawDetailView.as_view(), name='LawDetailView'),
path('LawNewView', LawCreateView.as_view(), name='LawCreateView'),
path('LawDetailView/<int:pk>/edit/', LawEditView.as_view(), name='LawEditView'),
path('LawDeleteView/<int:pk>/delete/', LawDeleteView.as_view(), name='LawDeleteView'),]
Также для каждого созданного маршрута и представления необходимо создать шаблон html, который будет отображаться на сайте при переходе по адресу страницы.
Для проверки работы CRUD запустим тестовый сервер (рис.4).
Рис. 4. Интерфейс WEB-конструктора с реализованными функциями CRUD
Реализация REST API в проекте. В системах, реализующих доступ к базе данных через API в стиле REST, функции CRUD реализуются зачастую через HTTP-методы PUT, POST, GET, PATCH, DELETE.
API (Application Programming Interface) – это программный интерфейс. Он обеспечивает взаимодействие двух программ между собой и позволяет встраивать контент с любого сайта. Основной задачей API является создание связи между двумя приложениями. API позволяет отправлять запросы на передачу или получение информации. Взаимодействие осуществляется через JSON, а данные получаем в приложениях с помощью API - запросов. API - запрос включает в себя 4 компонента: endpoint (точка приема запроса), header (заголовок), method (метод) и data (данные). После вызова всех компонентов мы можем построить API - запрос [4].
Для реализации REST API в проекте необходимо установить модуль djangorestframework. Затем создать новое отдельное приложение в нашем проекте используя команду «python manage.py startapp LawAPI».
В файл setting.py в INSTALLED_APPS необходимо добавить созданное нами новое приложение, а также «rest_framework». Создадим новый словарь в файле настроек для задания необходимых нам параметров djangorestframework:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 2,
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated']}
Создадим файл serialazers.py, в котором создадим сериалайзер для наших моделей:
from rest_framework import serializers
from systemStewartPlatform.models import *
class systemSerializer(serializers.ModelSerializer):
author = serializers.HiddenField(default = serializers.CurrentUserDefault())
class Meta:
model = system_stewart_platform
fields = '__all__'
class platformSerializer(serializers.ModelSerializer):
author = serializers.HiddenField(default = serializers.CurrentUserDefault())
class Meta:
model = stewart_platform
fields = '__all__'
class lawSerializer(serializers.ModelSerializer):
author = serializers.HiddenField(default = serializers.CurrentUserDefault())
class Meta:
model = law_for_platform
fields = '__all__'
Затем создадим представления в файле views.py, где укажем queryset и serializer_class:
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ModelViewSet
from lawAPI.serializers import *
from systemStewartPlatform.models import *
class systemViewSet(ModelViewSet):
queryset = system_stewart_platform.objects.all()
serializer_class = systemSerializer
class platformViewSet(ModelViewSet):
queryset = stewart_platform.objects.all()
serializer_class = platformSerializer
class lawViewSet(ModelViewSet):
queryset = law_for_platform.objects.all()
serializer_class = lawSerializer
В файле urls.py пропишем маршруты используя модуль djangorestframework routers:
from rest_framework import routers
from lawAPI.views import *
router = routers.SimpleRouter()
router.register(r'system', systemViewSet)
router.register(r'platform', platformViewSet)
router.register(r'law', lawViewSet)
Реализованный функционал REST API продемонстрирован на рисунке 5.
Рис. 5. REST API
Заключение. В работе разработан проект WEB-конструктора для построения динамической системы, позволяющей моделировать сложные поверхности, которые формируются с помощью множества Stewart – платформ. Настроен Фреймворк Django, спроектирована база данных. Для реализации возможности добавления, редактирования, удаления и просмотра базы данных с сайта реализован CRUD с использованием форм и REST API. Экспериментальная проверка, запущенного локально сервера сайта в отладочном режиме демонстрирует правильную работу разработанного функционала.
About the authors
Aleksey Viktorovich Grafkin
Email: lvg_alex@mail.ru
Associate professor, department of information systems security
Russian FederationEvgeniy Nikolaevich Mylnikov
Author for correspondence.
Email: mylnikov.yevgeniy@gmail.com
Russian Federation
Denis Ivanovich Ponamarenko
Email: maestrodark@icloud.com
Russian Federation
References
- SaaS. URL: https://ru.wikipedia.org/wiki/Программное_обеспечение_как_услуга (дата обращения: 10.08.2022).
- What is PostgreSQL. URL: http://www.sai.msu.su/~megera/postgres/talks/what_is_postgresql.html (дата обращения: 10.08.2022).
- Васильев, А. Ю. Работа с PostgreSQL настройка и масштабирование: учебное пособие/ А. Ю. Васильев. – California: Creative Commons, 2017. — 203 с.
- Django Rest Framework URL: https://www.django-rest-framework.org/ (дата обращения: 11.08.2022).