Русский
Русский
English
Статистика
Реклама

Робототехника своими руками

Сделать робота на raspberry pi, обновленный pi-tank. Часть 1. Железо

27.03.2021 10:18:41 | Автор: admin
Предлагается сделать домашнего робота, отличительными чертами которого будут:
относительная простота создания (как по времени, так и трудозатратам),
недорогие комплектующие,
доступный софт,
возможность удаленного управления, в том числе через интернет,
возможность бесшумно передвигаться,
наличие веб-камеры, которая (которой):
> вещает в сеть
> можно удаленно управлять(поворотная камера по осям x и y, pan-tilt)
> имеет возможность фото-, видео- съемки с сохранением на диск и скачивания данных медиа
> можно управлять настройками (экспозиция, баланс и т.п.)
> поддерживает день|ночь
> может сохранять снимки при наличии движения (motion detection).
возможность управлять режимом работы для экономии батареи, в том числе пробуждаться и засыпать, контролировать заряд батареи.




Небольшая вводная

.

Данный проект был создан более 3 лет назад и в течение этих 3-ти лет с ним многое происходило. Рождались и умирали ардуины, добавлялся и также отходил к праотцам речевой интерфейс, менялись драйверы двигателей, блоки питания, части советского железного конструктора, камеры для raspberry pi.
Не хватало только способа сэкономить энергию, так как работы батареи (powerbankа) робота хватало на 8-10 часов без слишком активной езды, но с постоянно работающей камерой и двигателями в режиме ready-to-go.
И вот, относительно недавно появилось решение для поставленной задачи. Данное решение потребовало в очередной раз перепахать весь проект, чтобы вспомнить что и как там реализовано.
Поэтому, пойдем по свежим следам.
Некоторые решения могут показаться странными, но к ним привела практика, поэтому будут соответствующие пояснения.

Перечень комплектующих

.

траки (chassis) как вариант ссылка
Лучше брать именно траки, так как колеса, а также омни-колеса в домашних условиях плохо себя проявили, проскальзывая либо застревая. Кроме того, чем шире и выше база танка, тем лучше проходимость через пороги. Плюс возможность поместить батарею под базу, сделав танк еще более устойчивым.
Траки можно брать голые без всяких там ардуин, пультов и т.п.


raspberry pi 3b+
Основной одноплатник, на котором будет все работать. Желательно взять для него корпус с возможностью доступа к gpio. Без корпуса все будет значительно быстрее пылиться и ржаветь.
Сразу ответим на попутные вопросы:
Почему не raspberry pi 4? более энергозатратная, нужен кулер, нестандартный powerbank и т.д. Почему не pi zero видео немного подтормаживает, но, в принципе, на ней тоже должно все завестись.
Почему не другие одноплатники (бананы, оранжи, одроиды и т.п.) так исторически сложилось.



-гребенки для gpio raspberry pi (8PCS,2X20(40 Pin) Extra Tall Female 0.1 Inch Pitch Stacking Header for Raspberry Pi A+/B+/Pi 2/Pi 3 Extra Tall Header) как вариант ссылка


-Witty Pi 3 Mini как вариант ссылка
Это единственная шапка для raspberry pi. Она как раз и будет отвечать за питание, а также режим работы робота.
*для шапки можно также взять LM29150 и впаять на плату. Это позволить питать raspberry не только от 5V, но и выше (до 8V). Об этом есть в инструкции в шапке.


csi-камера для raspberry pi. Работает быстрее, чем usb камера, занимает меньше места. Лучше брать рыбий глаз с автоматическим переключением день/ночь (характерный проводок от камеры на фото) как вариант ссылка.


sg-90 сервы 2 шт. Хлипкие, но ими можно напрямую управлять с gpio raspberry pi без страха спалить пины.


пластиковый подвес для серв (Servo bracket PT Pan/Tilt Camera Platform Anti-Vibration Camera Mount for Aircraft FPV dedicated nylon PTZ for 9G SG90) как вариант ссылка.
Для raspberry pi есть особые pan-tilt шапки, но они на порядок дороже.


l298n 1 шт. драйвер двигателей.


usb повышающий преобразователь с 5V до 12V 1шт. (DC-DC 5V to 12V 5W USB Step Up Power Supply Module Boost Converter Voltage Board 4.2V-5.2V) как вариант ссылка

powerbank c 2-мя выходами usb (для питания двигателей и raspberry pi).


провода, делали советского конструктора как средства крепежа, стойки.

Все. Нет никаких аккумуляторов 18650 и ардуин.
Бюджет: до 15т.р., самое дорогое траки.

Как все собрать.


Останавливаться на том как собрать траки (chassis) мы не будем, так как, в зависимости от выбранного варианта, сборка может отличаться. Кроме того, как правило, продавец траков дает инструкцию или ссылку на нее. Например такую посмотреть.
Единственная ремарка: от двигателей идут сразу несколько проводов. Нам понадобятся только пары красный-черный, питание и земля.
Как собирать подвес вместе с sg-90, мы также не будем останавливаться. Необходимо только иметь в виду, что перед закреплением в подвес сервы должны находиться в среднем положении (угол 90 градусов). Это нужно для того, чтобы подвес имел ход движения во все стороны, а не имел перекос в одну из них. Так что лучше сначала выставить сервы, а потом их закреплять.
Также по поводу серв. В проекте есть возможность управлять сразу двумя сервами (влево-вправо, вверх-вниз).
Но практика показала, что лучше влево-вправо не использовать по двум причинам:
можно потерять направление робота,
крепежные элементы sg-90 хлипкие и быстро изнашиваются.

Взглянем на схему подключения:


В принципе, ничего сложного нет. На драйвере двигателей l298n выводы ENA и ENB не задействованы и на них должны стоять перемычки.
Шим сигнал не используется и робот не сможет плавно разгоняться и тормозить. Это сделано намеренно, так как при плохом wi-fi или иных задержках робот по разному реагировал на управляющие сигналы. Вместо этого используются паузы в скриптах. Как это реализовано будет показано позднее.
Вместо блока батарей подразумевается powerbank. Здесь же пригодится usb повышающий преобразователь с 5V до 12V.
Питание на raspberry pi подается через wittypi 3 mini. Дополнительно питать одноплатник и сервы не нужно.

В завершение немного
фото
:









Продолжение следует.
Подробнее..

Сделать робота на raspberry pi, обновленный pi-tank. Часть 2. Софт

03.04.2021 18:14:06 | Автор: admin

Вторая часть полностью посвящена описанию программного обеспечения, используемого на роботе.
Так как разработанный робот (pi-tank) по большому счету рассчитан на начинающих роботостроителей, то все будет максимально упрощено, а в конце статьи будет приложен образ (image) для raspberry pi для самостоятельного дальнейшего изучения.


Небольшая оговорка. На предлагаемом образе для raspberry pi, рассчитанном на sd карту размером 8 Гб все настроено и установлено. Никаких дополнительных шагов предпринимать не требуется. Это сделано с целью упростить и облегчить часть, связанную с софтом, так как, исходя из практики, не всякий робототехник дотягивает до финиша, когда реализуется многокомпонентный проект.
Поэтому статья посвящена скорее настройке софта под себя, однако она позволит также пролить свет на то, как все собрать и настроить с нуля.

Основа.


В качестве отправной точки при разработке был взят RPi-Cam-Web-Interface. Достаточно древний, но тем не менее, не потерявший своей актуальности фреймворк.
Как его установить подробно описано на странице проекта и сложностей вызвать :
не должно
git clone https://github.com/silvanmelchior/RPi_Cam_Web_Interface.gitcd RPi_Cam_Web_Interface./install.sh


Есть нюансы для дистрибутива buster (о них написано на сайте проекта), но для Raspbian Stretch, который используется на роботе, все штатно.
После установки доступен web-сервер, который выводит по адресу raspberry-ip:8080/html/ картинку по умолчанию:


Данная картинка отличается от того, что можно наблюдать на роботе:

Как не трудно заметить, страница робота располагает стрелками для управления подвесом камеры (pan-tilt), собранном на базе серв sg-90, а также пользовательскими кнопками для управления роботом (фары, фары выкл и т.п.)
Назначение кнопок интерфейса интуитивно понятно.

Также на web-странице имеются вкладки для более детальной настройки параметров камеры, а также работы с системой:


Как попасть на raspberry.


При загрузке raspberry становится доступна через VNC c учетными данными логин pi, пароль raspberry.
wi-fi сеть, к которой по умолчанию подключается логин boss, пароль 1234554321.
Также можно попасть по ssh, пара логин-пароль те же.

Как все работает и где поменять под себя.


Вся начинка расположена в директории /var/www/html/, а сам RPi-Cam-Web-Interface стартует из /home/pi/RPi-Cam_Web_Interface.
Управление подвесом камеры осуществляется синими стрелками на web-странице. Сам фреймворк не умеет из коробки управлять сервами. Поэтому используется дополнительный пакет
И здесь есть небольшой нюанс. По умолчанию servoblaster использует gpio4 и gpio17 пины raspberry для управления подвесами (сигнальные провода серв). По счастливому стечению обстоятельств те же самые пины использует шапка raspberry pi witty pi 3 mini, отвечающая за питание, графики включения и т.п. Поэтому, чтобы железо не мешало друг другу пины для серв были перенесены для целей servoblasterа.
Делается это в /etc/rc.local командой:
sudo /home/pi/PiBits/ServoBlaster/user/servod --p1pins=13,15,0,0,0,0,0,0 & 

При этом 13,15 это физические пины, а не gpio! Остальные нули это возможность подключить еще сервы и управлять ими. То есть еще 6 серв можно подключить, обозначив пины вместо нулей.
*Какие пины задействованы servoblasterом в текущий момент можно заглянув в файл /dev/servoblaster-cfg
Также в /etc/rc.local задаются пины raspberry для управления двигателями:
код
gpio -g mode 5 out
gpio -g mode 6 out
gpio -g mode 9 out
gpio -g mode 10 out
gpio -g mode 11 out
gpio -g mode 22 out
gpio -g mode 27 out


*В данном случае gpio22 и gpio27 это и есть те пины 13,15, которые использует servoblaster.

Как с нуля настраивается pan-tilt описано на странице проекта здесь.

Как добавляются кнопки также описано на сайте в разделе User buttons. Чтобы добавить или изменить кнопки (фары и т.п.) необходимо обратиться к файлу /var/www/html/
userbuttons
фары,light.sh
фары-выкл,lightoff.sh
вперед,forward.sh
назад,reverse.sh
налево,left.sh
направо,right.sh
стоп,stop.sh
м налево,left-m.sh
м направо,right-m.sh
м вперед,forward-m.sh
м назад,reverse-m.sh

Здесь строки означают наименование кнопок, а также соответствующий им скрипт управления.
Сами скрипты управления находятся в /var/www/html/macros. И, вполне возможно, данные скрипты придется править, т.к. при подключении проводов к драйверу двигателей l298n полярность может быть иной и робот поедет не в ту сторону, согласно нажатой кнопке.
Чтобы это исправить, необходимо открыть скрипт, например /var/www/html/macros/left.sh
#!/bin/bash
gpio -g write 9 0
gpio -g write 11 1
gpio -g write 6 0
gpio -g write 5 1

И попробовать комбинации замены 1 и 0 на gpio. Но как правило, можно просто поменять left.sh на forward.sh или на right.sh и т.п. в зависимости от ситуации.

Кнопки интерфейса с приставкой м, отвечают за так называемый малый ход:

Это реализовано в скриптах left-m.sh и т.п. Ранее использовался pwm для управления. Однако стало понятно, что при задержках wi-fi и иных обстоятельствах расстояние, которое реализуется при нажатии на кнопку с pwm различается. Робот то уезжает слишком далеко до момента, когда нажата стоп, то практически не реагирует, особенно, при разряжающихся батареях.
Поэтому был реализован простой подход в скрипте подача сигнала и дальнейшее, через паузу, его гашение:
left-m.sh
#!/bin/bash
gpio -g write 9 0
gpio -g write 11 1
gpio -g write 6 0
gpio -g write 5 1
sleep 0.3
gpio -g write 9 0
gpio -g write 11 0
gpio -g write 6 0
gpio -g write 5 0



Witty pi 3 mini и управление питанием.


Продукт Witty pi 3 mini был приобретен, чтобы минимизировать потери питания при работе от powerbank и увеличить общее время функционирования робота.
Ранее при выключении робота, которое реализовано на web-странице

включить робота заново без посторонней помощи было невозможно. Были варианты с помощью внешней arduino, но все это было непросто и не эстетично.

Witty pi 3 mini не единственное решение в своем роде, и даже не первое в своей линейке. Но оно более-менее доступное и работающее из коробки.
Софт устанавливается предельно
просто

После установки может потребоваться уточняющая настройка в /home/pi/uwi/uwi.conf
текущие настройки
host='192.168.1.105';
port=8000;
web_socket_url='ws://'+host+':'+port+'/';
response_timeout=5000;
reconnect_timeout=1000;
debug=0;

wittypi3='/home/pi/wittypi';
zero2go='/home/pi/zero2go';



Далее при каждой загрузке на web странице raspberry:8000 (127.0.0.1:8000) будет доступен
web-интерфейс с настройками:


Первая вкладка это просто еще один способ управлять gpio raspberry pi

вторая вкладка это непосредственно настройки witty pi
На температурный датчик можно не обращать внимание, т.к. его точность сомнительна.

Можно настраивать прямо с web-страницы, но так же можно и с помощью скрипта:
/home/pi/wittypi/wittyPi.sh. При запуске скрипта, он выводит то же самое, что доступно на web-странице:
>>> Current temperature: 28.75C / 83.75F
>>> Your system time is: Sat 03 Apr 2021 16:20:47 MSK
>>> Your RTC time is: Sat 03 Apr 2021 16:20:48 MSK
>>> Vin=4.73V, Vout=4.68V, Iout=1.13A
Now you can:
1. Write system time to RTC
2. Write RTC time to system
3. Synchronize time
4. Schedule next shutdown
5. Schedule next startup
6. Choose schedule script
7. Set low voltage threshold
8. Set recovery voltage threshold
9. View/change other settings...
10. Reset data...
11. Exit

Здесь необходимо:
синхронизировать время на witty pi c системными часами raspberry (3. Synchronize time)
записать это время в rtc (1. Write system time to RTC)
далее поработать с пробуждением либо засыпанием, но проще сразу выбрать какой-нибудь
скрипт
6. Choose schedule script
[1] 7:00_on_7:30_off_21:00_on_21:30_off.wpi
[2] on_10m_every_2h.wpi
[3] on_1h_every_2d.wpi
[4] on_30m_everyday_but_weekend.wpi
[5] on_5m_every_20m.wpi
[6] turn_on_every_hour.wpi

Например [5], просыпаться на 5 минут каждые 20 минут.

После выбора скрипта соответствующие интервалы сна будут сразу обозначены:


обязательно заглянуть в другие настройки (9. View/change other settings...)
Здесь необходимо настроить [5] Dummy load duration [0] это паразитные импульсы для powerbankа, не дающие ему уснуть. Так как большинство powerbankов снимают питание при минимизированной нагрузке. Диапазон значений 0-255.
Все остальные настройки можно не трогать.

Witty pi предполагает также возможность контроля напряжения питания и корректное отключение при падении, а также включение при изменившихся условиях.
Доступна также более гибкая регулировка в части создания своих собственных графиков включения и выключения скриптогенератор:

Об этом подробно написано в инструкции.
Сон pi-tanka

Пока все. Если что-то забыто или непонятно пишите.

Образ для raspberry pi скачать.
Подробнее..

Из песочницы Дешевый и полнофункциональный робот-манипулятор своими руками

31.07.2020 12:10:12 | Автор: admin
Сразу оговоримся, что совсем дешево делать не будем, т.к. не хочется убивать нервные клетки, делая доморощенные энкодеры для моторчиков + хочется упростить создание 3D модели, которая нужна для управления через ROS (ссылка на готовую модель ниже в статье).

На момент написания статьи ориентировочная конечная стоимость изделия составляет ~70 000 руб. Если у вас есть 3D принтер, то можно смело вычесть из нее 20 000 руб. Если принтера нет, то его появление станет приятным бонусом. Все расходы я буду описывать исходя из того, что у нас нет ничего, кроме денег.

Как выглядит результат:



Также нужно отметить, что для программирования руки нам понадобится компьютер с установленными ОС Linux (я использую Ubuntu 18.04) и фреймворком ROS (я использую Melodic).

Может возникнуть вопрос почему 70К рублей это дешево?

Отвечаю. Изначально я не хотел заморачиваться с созданием роборуки и думал просто купить что-нибудь простенькое, но достаточно функциональное в сборе.

Что являлось для меня критериями функциональности и минимальной допустимой простотой (т.е. почему НЕ подойдут манипуляторы с алиэкспресса) можно обсудить в комментариях, чтобы не грузить тех, кому это очевидно и/или не интересно.

Конкурентные решения на рынке


Опишу, однако, кратко примеры того, что я рассматривал на рынке:

1) top3dshop.ru/robots/manipulators/dobot-magician-basic.html
176 000 руб. DOBOT можно купить не только в этом магазине, но обычно он стоит еще больше. Наверняка есть шанс найти его где-нибудь дешевле, но все равно это будет сильно дороже, чем 70 000 руб.

2) robotbaza.ru/product/robot-manipulyator-widowx-robotic-arm-mark-ii
280 000 руб. Еще дороже. Вообще, манипуляторы от TossenRobotics прямо у производителя стоят супервменяемых денег. Вот только доставку в Россию (а я-то именно тут) из их магазина не заказать.

Забегая немного вперед скажу, что делать мы будем копию робо-руки PhantomX Pincher Robot Arm Kit Mark II, которая производится именно компанией TossenRobotics.

Итого, видим, что 70 000 руб это совсем не так дорого.

Что же нам нужно купить?


Все цены привожу на момент написания статьи (июль 2020 года):

1) 6 моторчиков DYNAMIXEL AX-12A



Я покупал по цене 7200 руб за 1 штуку, но, кажется, можно найти и за 6000 при большом желании. Будем считать, что вам не повезет и вы тоже купите за 7200.
Суммарная стоимость: 43 200 руб

2) 3D принтер

Подойдет любой простенький, можно уложиться в 20 000 руб.

3) Arduino Uno + Power Shield





Стоимость: ~4 000 руб

4) Опционально (но я очень рекомендую): Лабораторный источник питания



Стоимость: ~3 500 руб

Сборка


Отлично! Мы закупили все, что нам нужно (вероятно, дольше всего ждали доставки моторчиков, мне их везли больше месяца).

Что дальше?

1) Напечатаем детали для манипулятора на 3D принтере.

Качаем STL файлы отсюда

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

Делаем 3D модель


Класс! Рука у нас есть, но ведь ей же нужно как-то управлять. Хочется максимально использовать достижения человечества, поэтому установим себе ROS.

Для того, чтобы полноценно работать с манипулятором в ROS нужно сделать его URDF модель. Она будет нам необходима для того, чтобы управлять робо-рукой с помощью пакета MoveIT!
На момент написания статьи последняя стабильная сборка доступна для Melodic/Ubuntu 18.04, чем и объясняется мой выбор версии системы и фреймворка в начале статьи.

Построение URDF модели довольно трудоемкая (и, на мой взгляд, самая скучная) часть данного проекта. Нужно немного допилить напильником stl модели компонентов и соединить их воедино в XML-образном файле, вручную подбирая правильные коэффициенты смещения деталей друг относительно друга.

Кто хочет может проделать работу самостоятельно, всем остальным поберегу нервы и просто дам ссылку на свой готовый файл:

github.com/vladmiron85/armbot/blob/master/catkin_ws/src/armbot_description/urdf/base.urdf

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

Выглядит модель вот так:


Из полученного URDF файла мы сделаем конфиг MoveIT!, который позволит нам моделировать движения манипулятора и отправлять управляющие команды на реальную робо-руку.

Для создания конфига есть отличный туториал (ссылка)

Тут я могу опять сэкономить время и предоставить свой конфиг. Лежит он вот тут:

github.com/vladmiron85/armbot/tree/master/catkin_ws/src/armbot_moveit_config

Можно скачать конфиг с гитхаба и запустить следующей командой:

roslaunch armbot_moveit_config demo.launch

Примерно так можно будет управлять нашей реальной робо-рукой через rviz, когда мы подключим ее к ROS:


А что с реальной рукой?


Переместимся из мира 3D моделей в суровую реальность. У нас есть собранный ранее манипулятор. Хотелось бы его как-то подвигать. Сделаем это с помощью Arduino UNO и Power Shield.

Подключим первый моторчик манипулятора (который снизу) к Power Shield'у и блоку питания следующим образом:



Да, data pin моторчика мы соединим сразу с 3 и 4 выводом Arduino. Пытливый читатель мануала Dynamixel (вот он) сразу заметит, что связь с внешним миром у моторчика организована по Half Duplex Asynchronous Serial Communication, а это означает, что data pin используется сразу и для получения команд и для ответа.

По умолчанию, на аппаратном уровне Arduino умеет работать только с Full Duplex UART. Эту проблему можно обойти, используя Soft Serial библиотеку, что мы и сделаем. Именно использование Half Duplex режима объясняет подключение data pin мотора к 3 и 4 выводам шилда одновременно.

Помимо полудуплексного обмена работа с Dynamixel через Arduino имеет еще пару занимательных моментов, которые могут быть не совсем очевидны с самого начала. Сведем их все воедино.

Как подвигать наш манипулятор?


1) Сначала скачаем нужную библиотеку. Она называется ardyno и ее можно получить через Arduino Library Manager, либо тут (ссылка)

2) По умолчанию Dynamixel AX-12A хотят работать с baud rate = 1000000. Однако Software Serial Interface не потянет такую скорость, поэтому baud rate стоит снизить до 57600. Таким образом, начало файла с вашей программой будет выглядеть примерно вот так:

#include "DynamixelMotor.h"// communication baudrateconst long unsigned int baudrate = 57600;SoftwareDynamixelInterface interface(3, 4);

3) Все наши моторчики соединены друг с другом последовательно. Значит, чтобы обращаться к каждому из них нужно знать его ID? Это действительно так, объект DynamixelMotor при инициализации получает два параметра: interface (одинаков для всех, его мы задали в предыдущем пункте) и id (должен быть у всех разный, иначе поведение будет у манипулятора весьма странное)

DynamixelMotor motor(interface, id);

Id каждому моторчику придется задать вручную. Кажется, что будучи соединенными последовательно, они могли бы и сами рассчитаться по номерам от 1 до 6, но этого не предусмотрено. Поэтому нужно каждый моторчик отдельно подключить к Arduino (отключив от остальных) и выполнить следующую программу:

#include "DynamixelMotor.h"// communication baudrateconst long unsigned int baudrate = 57600;// id of the motorconst uint8_t id=1;SoftwareDynamixelInterface interface(3, 4);DynamixelMotor motor(interface, id);void setup(){  interface.begin(baudrate);  delay(100);   // check if we can communicate with the motor  // if not, we turn the led on and stop here  uint8_t status=motor.init();  if(status!=DYN_STATUS_OK)  {    pinMode(LED_BUILTIN, OUTPUT);    digitalWrite(LED_BUILTIN, HIGH);    while(1);  }  motor.changeId(NEW_ID);}void loop(){}

Изначально все моторчики имеют id=1, именно поэтому мы и указываем вверху

const uint8_t id=1;

NEW_ID для каждого моторчика нужно заменить на число от 1 до 6 (да, ок, первый моторчик можно не трогать). Нумеруем их в порядке от нижнего к верхнему.

Ура! у нас есть полноценный манипулятор, который мы можем двигать, а также имеется 3D модель к нему. Можно брать ROS и программировать любые крутые штуки. Но это уже рассказ для отдельной статьи (и не одной). Данное же повествование подошло к концу, спасибо за внимание!
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru