Как стать автором
Обновить
2617.23
Timeweb Cloud
То самое облако

DMX голова: трепанация черепа и замена мозга (превращение в 3D платформу)

Уровень сложностиСредний
Время на прочтение14 мин
Количество просмотров4.7K


Некоторое время назад мне попалась на глаза китайская DMX голова для сценического света, которая произвела на меня неизгладимое впечатление — «да это же готовая платформа для 3D позиционирования!» — воскликнул я и немедленно заказал её. У меня мгновенно возник план: выкинуть стоковую плату управления, поставить свои драйверы для моторов, прикрутить что-нибудь вроде ES32/ESP8266, написать прошивку и дополнить всё это дело собственным API для интеграции мою IoT экосистему.

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

Итак, поехали…

Сама голова


Для тех, кто не очень в теме, поясню: речь идёт о т. н. «голове», то есть устройстве для создания динамических цветовых сцен на различных мероприятиях — концертах, презентациях, выступлениях и т. п. Голова имеет несколько мощных RGB(W) светодиодов и систему управления положением в пространстве и может в динамическом режиме направлять свет в нужную режиссёру сторону.

А управление головой осуществляется по DMX интерфейсу, который является стандартом для подобного рода аппаратуры. То есть любой техник сцены может без проблем подключить такую голову к своему пульту управления.

Надо сказать, что сама голова сделана отлично — всё работает как и заявлено и свои функции она выполняет на 100%, по крайней мере у меня не возникло ни одного замечания, пока голова ещё была жива в заводском состоянии.



В моём случае проблема заключается в том, что функционал головы жёстко ограничен (разумеется, закрытой) прошивкой и интерфейсом DMX. Понятное дело, что для режиссёров сцены это нормально и им больше ничего не нужно, но меня это категорически не устраивало — мне, как минимум, нужна возможность самому определять алгоритмы работы головы и, как максимум, нужны беспроводные интерфейсы управления и возможность аппаратно дополнять само устройство — то есть возможность устанавливать на платформу камеры, дисплеи, датчики, микроконтроллеры и прочие компоненты.

Поэтому вопрос «вскрывать или не вскрывать» для меня не стоял и в заводском состоянии голова продержалась недолго (смайл), всего несколько часов, а дальше началась уже совсем другая история.

Для чего это нужно


Для того, чтобы было более понятно о чём идёт речь и чем меня, собственно, заинтересовала эта тема, приведу несколько примеров возможного использования «освобождённой» головы.

Управление светом. Как минимум, если ничего не трогать и заменить только микроконтроллер, драйверы и прошивку, то можно самостоятельно определять алгоритмы работы головы. Можно также добавить Wi-Fi или Ethernet интерфейсы и API для интеграции с IoT системами.

Сканирование окружающего пространства. Существует множество задач, когда требуется сканирование окружающего пространства. Например, ультразвуковой датчик имеет ограниченный угол обзора, — установив его на такую платформу, можно расширить объём обнаружения почти до полной сферы. Разумеется, установить можно не только ультразвуковой, но и любой другой датчик.

Развёртка для точечных датчиков. Существует ещё один класс задач, когда при помощи точечного датчика необходимо создать «фотографию» окружающего пространства. При помощи такой платформы эта труднорешаемая задача превращается в тривиальную — устанавливаем датчик и запускаем сканирование по любому нужному алгоритму.

Позиционирование фото и видео оборудования. При помощи такой платформы можно как угодно позиционировать фото и видео оборудование — от панорамной съёмки до построения системы съёмки несколькими автоматическими камерами с разных ракурсов. Сюда же можно добавить эксперименты по астрофотографии.

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



Приложения искусственного интеллекта. Это просто просится на реализацию: цепляем видеокамеру, микрофоны и дисплей, прикручиваем AI и получаем робота, которого можно программировать и совершенствовать до бесконечности.

Отработка алгоритмов. На этой платформе можно отрабатывать алгоритмы управления для «взрослых» систем. Например, мощности головы не хватит для управления тяжёлыми солнечными панелями, но на ней можно с удобством отрабатывать алгоритмику их работы.

Платформа для обучения и экспериментов. Это просто великолепная платформа для экспериментов и обучения IT, программированию, электронике, робототехнике и т. д.

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

Ну и, кроме всего прочего, это просто красиво (смайл).

Приступаем начинать


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

Степени свободы вращения

Голова имеет 7 мощных светодиодов, установленных на подвижной «голове», которая может вращаться на 540 градусов по горизонтали и 180 градусов по вертикали. 540 градусов по горизонтали — это полтора полных оборота. Голова не может вращаться постоянно в одну сторону — диапазон её перемещений жёстко ограничен стопорами. 180 градусов по вертикали это, соответственно, половина полного оборота.



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

А почему, собственно, голова не может вращаться постоянно в одну сторону? Ответ очевиден — на вращающейся площадке установлены компоненты (светодиоды, датчик Холла, вентилятор и пр.), которые соединены с основанием проводами и, если голова будет непрерывно вращаться в одну сторону, то просто «перекрутит» эти провода и остановится.

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



Итого, при угле расхождения в ноль градусов охват окружающего пространства головой составляет ровно полусферу. Если датчик или излучатель имеет больший угол расхождения, то, соответственно, увеличивается и степень охвата окружающего пространства. Можно сказать, что подобные ТТХ подходят для большинства практических применений. Если этого диапазона недостаточно, то можно немного доработать механику головы и расширить диапазон вращения по вертикали. Тогда охват приблизится к полной сфере.

Плата светодиодов

Существуют разные модификации подобных DMX голов с различными типами установленных светодиодов. Есть простые RGB варианты и более продвинутые полноцветные, позволяющие задать любой цвет свечения и любой алгоритм изменения цветов. В моём случае голова была с полноцветными светодиодами.



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



Изначально плату светодиодов соединял с основной платформой жгут из 8 проводов, которые сейчас отпаяны и оставлены в качестве «шины» для передачи питания и транспортировки сигналов с подвижной части головы на её основу (для оборудования, которое в будущем будет устанавливаться на неё).



Блок питания

Блок питания головы имеет две линии 12 и 24 В постоянного тока. 24-вольтовая линия используется для запитки светодиодов, а 12-вольтовая для питания всего остального — платы контроллера и шаговых моторов.

Блок питания — это как раз тот элемент головы, который нет необходимости заменять или модернизировать — там достаточно и мощности и набора выдаваемых напряжений.

Шаговые моторы



Голова управляется двумя одинаковыми 12-вольтовыми шаговыми моторами 42H-12-16 RYX4/12L, один из которых вращает её по горизонтали, а другой — по вертикали. Вертикальный вращает голову напрямую, а горизонтальный через ременную передачу 1:4. В результате мы имеем вертикальное разрешение 200 шагов на оборот (шаг 1,8°), а горизонтальное — 800 шагов на оборот (шаг 0,45°).



Подключение моторов 4-проводное (две обмотки).

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

Вентиляторы

Шаговики при своей работе греются. А также плата (мощных) светодиодов тоже греется и всё это требует охлаждения, поэтому в основании и в подвижной части установлены два вентилятора на 12 В.

Работают они, если слушать в концертном зале, довольно тихо, но при установке в жилом помещении шум становится заметен. Ниже будет описано решение этой проблемы.

Концевики

Тут китайские инженеры решили проявить креативность и на горизонтальной оси установили механический концевик, а на вертикальной — датчик Холла (44E). Для нас это не имеет принципиального значения: с программной точки они работают аналогичным образом (0/1). Только датчик Холла требует для своего подключения три провода, а механический концевик — два.



Управляющая плата

Управляющая плата содержит микроконтроллер в 20-контактном корпусе (со стёртой маркировкой), ключи управления светодиодами, микросхемы драйверов управления шаговыми моторами (AT8833), разъёмы для подключения концевиков, микрофон (для реагирования на внешние звуки) и прочую логику.



Для нас эта плата не имеет никакой ценности, поскольку её функционал жёстко задан разработчиком, а наша задача как раз и состоит в том, чтобы «освободить» голову и кардинально расширить её возможности.

Устройство также содержит 4-символьный цифровой индикатор и четыре кнопки для управления и настройки головы. Всё это тоже нам не нужно — если понадобится, то вместо цифрового индикатора можно установить какой-нибудь дисплей, причём как на стационарную часть платформы, так и на подвижную.

В целом, диспозиция ясна. Теперь переходим непосредственно к работам по переделке головы.

Шаг 1. Чтобы получить шедевр, нужно отсечь всё лишнее


Первым шагом на пути переделки и модернизации головы является её разборка и удаление «лишних» частей. По большому счёту нас интересует только механическая часть головы (плюс металлическое основание с блоком питания) и шаговые моторы с концевиками — всё остальное нужно (аккуратно) демонтировать.

Снимаем пластиковый внешний корпус, удаляем разъёмы DMX интерфейса (зачем нам DMX интерфейс?), отключаем все провода от управляющей платы и демонтируем её, отрезаем провода от платы светодиодов.



В результате получаем:
  1. Металлическое основание с блоком питания (3 провода GND, 12V, 24V), шаговиком горизонтальной оси (4 провода), механическим концевиком горизонтальной оси (2 провода) и вентилятором.
  2. Подвижную часть с шаговым мотором (4 провода), датчиком Холла (3 провода GND, 5V, DATA) и вентилятором охлаждения (2 провода). Плюс жгут из 8 проводов для передачи питания и данных между статичным основанием и подвижной частью.

Это всё. В результате мы получаем эдакий набор «сделай сам», где самая «муторная» механическая часть уже сделана трудолюбивыми китайцами, а нам остаётся только получать удовольствие (а чем вы думаете мы тут занимаемся?) от программирования и создания проектов на этой платформе.

Шаг 2. Выбираем MCU и архитектуру


Как по мне, для управления платформой можно выбрать любой микроконтроллер, начиная от ATmega328 и заканчивая ESP32 — всё определяется вашими потребностями и нужным набором функций. Поскольку сейчас речь идёт о создании базового варианта платформы «proof of concept», то разумным вариантом мне показалось использование ESP8266 в виде популярного модуля WeMos D1 mini (коих в моём хозяйстве накопилось целая коробка).

В WeMos D1 mini есть всё необходимое: быстрый MCU, поддержка Wi-Fi, встроенный переходник USB-UART и т. д. и для запуска платформы и экспериментов с ней ESP8266 будет более чем достаточно. Можно даже прикрутить веб-интерфейс и сделать работу с платформой совсем комфортной.

В практическом плане, использовать «голый» модуль WeMos D1 mini не очень удобно, поэтому для него была сделана плата, которая включает в себя:
  • сам модуль WeMos D1 mini;
  • колодку для подключения входного напряжения 12 В от блока питания;
  • модуль понижающего DC/DC преобразователя на 5 В (HW-613) для питания драйверов шаговиков, датчика Холла и прочих компонентов;
  • ряды пинов (GND, 5V, 3V3) для подключения различных компонентов платформы.



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

А в дальнейшем, в зависимости от конкретного проекта, управляющую плату можно просто заменить на любую другую с любым нужным MCU и любым нужным функционалом (вот она — сила DIY!).

Шаг 3. Шаговики и их драйверы


Поскольку управляющую плату вместе с драйверами шаговиков мы удалили, то теперь нам нужно «изобрести» какое-нибудь своё решение по управлению головой. Оптимальным я посчитал вариант платы для установки стандартных модулей драйверов.



Этот вариант хорош тем, что можно безболезненно менять драйверы при их подборе или поломке. Кроме того, плата содержит все элементы обвязки и нам не нужно об этом заботиться. Разумеется, в законченном устройстве лучше сделать собственную плату управления платформой, включающую микроконтроллер, драйверы и всё остальное, что требуется по проекту.



Из модулей драйверов у меня были типовые A4988 и DRV8825, я попробовал и те и другие и в конечном варианте остановился на DRV8825 — они работают несколько тише, но всё равно достаточно шумно. В данный момент я заказал модули TMC2208 и TMC2209, они должны работать ещё тише, чем DRV8825.



Подключение шаговых моторов к драйверам стандартное, к нашем случае это четыре провода от двух обмоток, а управление микроконтроллером производится по схеме STEP/DIR (шаг/направление). На плату драйвера подаётся напряжение 12 В для питания мотора, напряжение 5 В для питания самого драйвера и два провода от управляющих GPIO контроллера (STEP/DIR). Земля контроллера соединяется с землёй плат драйверов (у нас две платы драйверов — для горизонтальной и вертикальной осей) и минусовым проводом блока питания.

Шаг 4. Сборка


Теперь нам нужно просто собрать вместе управляющую плату с ESP8266 и две платы драйверов и установить их на место стоковой платы управления. Это простая операция, нужно только быть внимательным и не перепутать провода при монтаже.



Поскольку основание платформы (место установки плат) металлическое, то платы нужно установить на диэлектрическое основание, чтобы нигде ничего не замкнуло.

На этом этапе нужно также подключить концевики, поскольку это важная часть системы и без них ничего работать не будет. Механический концевик подключается двумя проводами (GND, GPIO2), а датчик Холла — тремя (GND, 5V, GPIO13)



На этом этап модернизации аппаратной части платформы можно считать законченным и можно переходить к настройке работы нашего девайса.

Шаг 5. Включение и настройка


Если всё сделано правильно и нигде ничего не перепутано, то можно включать платформу. Поскольку в данный момент управляющая прошивка не загружена, то визуально ничего происходить не должно — голова не должна двигаться.

Далее нужно настроить величину тока шаговых моторов. Для этого на модулях драйверов имеются подстроечные резисторы. Опытным путём я установил, что для нашего случая оптимальное напряжение на подстроечных резисторах модулей DRV8825 составляет 0,3 В, что соответствует, согласно формуле, 0,6 А.



При этой настройке моторы нормально работают и справляются с перемещением и удержанием головы и при этом минимально греются. Максимальный зафиксированный нагрев составляет 55 градусов Цельсия, что позволяет вообще отказаться от вентиляторов и просто отключить их.

(Или можно снизить скорость их вращения и уровень шума, добавив в цепь питания резистор в несколько десятков Ом и мощностью 1-2 Вт. Нужно только следить, чтобы снижение тока через вентиляторы не было чрезмерным и не мешало им стартовать при включении платформы.)



Тестовая прошивка


Ну и чтобы убедиться, что мы всё сделали правильно и можем по своему желанию управлять платформой, напишем тестовый скетч, который будет определять положение головы, парковать её в нулевую точку и совершать тестовые перемещения (установку вертикального угла и сканирующее перемещение по горизонтали).

Тестовый алгоритм работы следующий:
  1. Установка «нулевого» положения по горизонтали. В общем случае изначальное положение головы может быть любым, поэтому сначала нужно установить голову в «нулевое» положение. Для горизонтальной оси за нулевую точку примем положение 270° от концевика, то есть ровно посередине всего диапазона возможных перемещений по горизонтали.
  2. Установка «нулевого» положения по вертикали. Для вертикальной оси за нулевую точку примем положение 90° от горизонта, или 78,8° от срабатывания датчика Холла (так уж китайцы его установили). Другими словами, в нулевой точке по вертикали голова смотрит ровно в зенит и может перемещаться на 90° в обе стороны (какая прелесть).
  3. Завершение инициализации и пауза 2 секунды.
  4. Установка по вертикали в рабочее положение. С этого шага начинается имитация «рабочего процесса» и голова по вертикали устанавливается в положение 90° от нулевой точки и «смотрит» ровно по горизонту, без отклонения вверх и вниз (вниз, кстати, она и не сможет — в этом положении она упирается в ступор).
  5. Сканирующие движения по горизонтали. Имитируем «радар», вращая голову влево (на 180°) и вправо (на 180°) на полные 360° от нулевой точки (270°). Кстати, имеем ещё запас по 90° в обе стороны (но это «радару» и не нужно — его задача охватить 360°).
  6. Завершение теста и установка в нулевую точку. Завершаем тестовый процесс и «паркуем» голову в нулевую точку по горизонтали.

Для реализации задуманного используем библиотеку AccelStepper. В ней содержится множество специализированных функций для реализации (сколь угодно изощрённого) управления шаговыми моторами.

/*
  Head test
  WeMos D1 mini (ESP8266)
*/

#include <AccelStepper.h>

#define DIR_PIN_H 4
#define STEP_PIN_H 5

#define DIR_PIN_V 14
#define STEP_PIN_V 12

#define ENDER_H 2
#define ENDER_V 13

#define INTERFACE_TYPE 1

AccelStepper stepperH(INTERFACE_TYPE, STEP_PIN_H, DIR_PIN_H);
AccelStepper stepperV(INTERFACE_TYPE, STEP_PIN_V, DIR_PIN_V);

void setup() {
  Serial.begin(115200);
  Serial.println(F("Start Head..."));
  
  pinMode(ENDER_H, INPUT_PULLUP);
  pinMode(ENDER_V, INPUT_PULLUP);
 
  setStartPosH();
  setStartPosV();
  
  Serial.println(F("Init done"));
  delay(2000);
}

void loop() {
  checkTargetH();
  stepperH.run();
  stepperV.run();
}

Здесь: определяем номера GPIO подключения драйверов и концевиков, делаем внутреннюю подтяжку линий концевиков к напряжению 3,3 В, устанавливаем нулевые точки положения головы по горизонтали и вертикали, ждём 2 секунды и далее имитируем «рабочий процесс» сканирования.

Ось H

Функции инициализации и рабочего процесса для горизонтальной оси:

/*
  Module Axis H
  800 steps / 0,45°
*/

#define MICRO_H 16 // 1, 2, 4, 8, 16

#define MAX_SPEED_H (250*MICRO_H)
#define ACCELERATION_H 4000
#define SPEED_H 100

#define MIDDLE_H (600*MICRO_H)
#define TO_MIDDLE_H (MIDDLE_H+1000)

#define DOUBLE_H (1200*MICRO_H)
#define TO_ENDER_H (DOUBLE_H+1000)

#define WORK_H (400*MICRO_H)

#define CYCLOS_H 3

int targetPosH = 0;
int cyclosH = 0;

bool endPosH() {
  return !digitalRead(ENDER_H);
}

void initH() {
  stepperH.setMaxSpeed(MAX_SPEED_H);
  stepperH.setAcceleration(ACCELERATION_H);
  stepperH.setSpeed(SPEED_H);
}

void setStartPosH() {
  initH();
  stepperH.moveTo(TO_ENDER_H);
  while(!endPosH()) {
    stepperH.run();
    yield();
  }
  stepperH.setCurrentPosition(0);
  stepperH.moveTo(-TO_MIDDLE_H);

  while(stepperH.currentPosition() > -MIDDLE_H) {
    stepperH.run();
    yield();
  }
  stepperH.setCurrentPosition(0);
  setTargetH();
}

void setTargetH() {
  targetPosH = WORK_H;
  stepperH.moveTo(targetPosH);
}

void checkTargetH() {
  if (stepperH.currentPosition() == targetPosH && cyclosH < CYCLOS_H) {
    
    targetPosH = -targetPosH;
    stepperH.moveTo(targetPosH);
    cyclosH++;
  }

  if (cyclosH == CYCLOS_H) {
    stepperH.moveTo(0);
  }
}

Здесь:

Устанавливается нужный режим количества микрошагов для мотора горизонтальной оси. В данном случае — 16.

#define MICRO_H 16 // 1, 2, 4, 8, 16

Примечание. Выбор режима микрошагов — дело субъективное. Мне показался оптимальным вариант 16 для обеих осей при котором соблюдается баланс между плавностью и уровнем шума и загрузкой MCU.

В зависимости от установленного режима пересчитываются все управляющие константы, как по количеству шагов (перемещений), так и по скорости.

#define MAX_SPEED_H (250*MICRO_H)
#define ACCELERATION_H 4000
#define SPEED_H 100

#define MIDDLE_H (600*MICRO_H)
#define TO_MIDDLE_H (MIDDLE_H+1000)

#define DOUBLE_H (1200*MICRO_H)
#define TO_ENDER_H (DOUBLE_H+1000)

#define WORK_H (400*MICRO_H)

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



Далее идёт функция установки нулевого положения головы по горизонтальной оси.

void setStartPosH() {

Алгоритм парковки следующий: поскольку мы не знаем начальное положение головы, то нам нужно «привязаться» к какой-то точке, координаты которой нам известны. Соответственно, перемещаем голову в сторону концевика, пока не упрёмся в него. Далее перемещаем голову в нулевое положение (270° или 600*MICRO_H).

Далее задаём тестовое количество сканирующих перемещений «радара».

#define CYCLOS_H 3

И диапазон перемещений головы по горизонтали (±180°)

#define WORK_H (400*MICRO_H)

А в функции

void checkTargetH() {

отрабатываем логику движения головы по горизонтали и в конце опять паркуем её в нулевое положение.

Ось V

Вертикальная ось настраивается и работает аналогичным образом.

/*
  Module Axis V
  200 steps / 1,8°
*/

#define MICRO_V 16 // 1, 2, 4, 8, 16

#define MAX_SPEED_V (70*MICRO_V)
#define ACCELERATION_V 4000
#define SPEED_V 100

#define MIDDLE_V (44*MICRO_V)
#define TO_MIDDLE_V (MIDDLE_V+1000)

#define DOUBLE_V (88*MICRO_V)
#define TO_ENDER_V (DOUBLE_V+1000)

#define WORK_V (51*MICRO_V)

bool endPosV() {
  return !digitalRead(ENDER_V);
}

void initV() {
  stepperV.setMaxSpeed(MAX_SPEED_V);
  stepperV.setAcceleration(ACCELERATION_V);
  stepperV.setSpeed(SPEED_V);
}

void setStartPosV() {
  initV();
  stepperV.moveTo(-TO_ENDER_V);
  while(!endPosV()) {
    stepperV.run();
    yield();
  }
  stepperV.setCurrentPosition(0);
  stepperV.moveTo(TO_MIDDLE_V);

  while(stepperV.currentPosition() < MIDDLE_V) {
    stepperV.run();
    yield();
  }
  stepperV.setCurrentPosition(0);
  stepperV.moveTo(WORK_V);
}

Этот код немного проще, поскольку по нашему сценарию мы просто устанавливаем голову по вертикали в нужное положение и никак не перемещаем её. Далее аналогичная таблица количества микрошагов для вертикальной оси.



Результат


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


Для одной статьи этого материала более, чем достаточно — о дальнейшей модернизации платформы и проектах на её основе я постараюсь рассказать в последующих статьях. А вы уже сейчас можете самостоятельно экспериментировать, основываясь на информации, изложенной в этой статье.



Возможно, захочется почитать и это:


Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале

Теги:
Хабы:
Всего голосов 20: ↑19 и ↓1+29
Комментарии15

Публикации

Информация

Сайт
timeweb.cloud
Дата регистрации
Дата основания
Численность
201–500 человек
Местоположение
Россия
Представитель
Timeweb Cloud

Истории