Insikt
- Senior Developer
- Insikt Intelligence
- Jan 2019 – Feb 2020 1 yr 2 mos
- Barcelona Area, Spain
-
Docker,WMware,k8sAWSZookeeperKafkaStormKotlinTweeter apiPythonAngularPostgreSQLSonarQubeJenkinsHadoop
Это устройство размещается непосредственно в рабочей зоне на складе запасных частей. Чем больше диапазон дистанций для размещения этого устройства, тем лучше. Оптимальное соотношение цена-качество-дистанция у такого кронштейна NB North Bayou Gaming Monitor Stand NB45-B.
После публикации статьи Использование OpenCPN для автоматизации производства / Хабр (habr.com) в личной почте были вопросы по настройке программного обеспечения на собранном устройстве.
В той статье были даны ключевые ссылки на рабочий в плане TS, LCD и emmc (тачпанели, экрана и встроенной памяти) имидж Debian Linux. И ссылки на строчки открытого кода, которые достаточны для опытного специалиста с избытком времени на изучение чужого кода.
Там же подробно было показан один из возможных способов механической сборки компонентов OLIMEX LTD – OLinuXino Arduino Maple Pinguino ARM Open Source Hardware Development Boards. Все компоненты этой компании идут с подробным открытым описанием как необходимого программного обеспечения, так и с полной открытой публикацией всего дизайна железа. То есть любой желающий может разработать, изготовить и заказать на любом заводе свою собственную интегрированную плату взяв за основу разведенные платы Olimex.
В этой статье будут более детально и последовательно приведены все необходимые конфигурации как самого имиджа Linux, так и необходимых библиотек для OpenCPN и для новых плагинов, о которых я рассказывал в предыдущей статье.
Мы используем Olimexino-MICRO A20. На нашей плате есть память emmc и у нас уже подключён экран LCD через кабель IDC40. На сайте производителя есть кабели длинной 6 см, 10 см и 15 см. Они стоят не дорого и можно купить сразу 3 кабеля и по месту подобрать тот который вам подходит. Либо попробовать использовать кабель от старых настольных PC, которым подключались жесткие диски до эпохи SATA.
Для активизации LCD мы идем с правами root в каталог /root. Пароли по умолчанию в имидже Olimex Debian Linux – olimex. Изначально настроены два пользователя – root и olimex. Оба с одинаковым паролем – olimex. В каталоге мы запускаем скрипт настройки LCD, который открывает меню, где и можно выбрать тип вашего LCD.
./change_display.sh
Я предпочёл вначале сделать все предварительные настройки на SD карте, с целью сохранения загрузочного имиджа на всякий случай. Но вы можете на этом этапе перейти на работу со встроенной emmc памяти.
./emmc.sh
Расширять полученную рабочую партицию мне не пришлось, скрипт все делает автоматически. Дождавшись завершения работы скрипта, можно выключить питание устройства.
poweroff
Вытащить SD карту и путем нажатия кнопки ресет либо путём включения и выключения штекера питания включить устройство. Примерно через 30 секунд загрузка должна завершится и вы увидите X десктоп на своей LCD панели. Если вам необходимы манипуляции с загрузчиком и вы хотите видеть процесс загрузки ядра, подключите до включения устройства дополнительный HDMI монитор.
Для надежности и для компиляции собственных модулей лучше всего клонировать репозиторий OpenCPN.
git clone https://github.com/OpenCPN/OpenCPN
Для нашей версии ядра крайняя версия OpenCPN, которая собирается без проблем это 4.1, но мы будем использовать версию 4.0.
cd OpenCPN
git checkout v4.0.0
Для компиляции OpenCPN нам нужны следующие библиотеки и пакеты
По сути в списке достаточно оставить только одноименные пакеты с суффиксом -dev, так как сами библиотеки поставятся автоматически, но я привет те команды, которые я использовал.
sudo apt-get install cmake build-essential libwxbase3.0-0 libwxbase3.0-dev sudo apt-get install libwxgtk3.0-dev libwxgtk3.0 sudo apt-get install libcairo2-dev libcairo2 sudo apt-get install portaudio19-dev sudo apt-get install curl-dev curl libcurl libcurl4-openssl-dev sudo apt-get install libpangocairo-1.0-0 libpango libpango1.0-dev sudo apt-get install libsdl-pango-dev pkg-config sudo apt-get install libpangomm-1.4-dev libpangox-1.0-dev sudo apt-get install libgtk-pixbuf2.0-0 libgtk-pixbuf libgtkpixbuf sudo apt-get install libgtkextra-dev libgtk-3.0 libgtk3.0-cil-dev sudo apt-get install liblzma-dev libarchive-dev libzip2 lbzip2 libbz2-dev sudo apt-get install libexif-dev libexif-gtk-dev libelf-dev sudo apt-get install gettext libtinyxml2-dev
Не все эти библиотеки нужны, кой-где возможны ошибки в написании. Но с помощью следующей команды можно найти правильное название.
sudo apt-cache search libtinyx
Дополнительные библиотеки
Пару библиотек для этого проекта я собрал самостоятельно. Стоковая версия OpenCPN не подключается к базе данных MySQL, поэтому потребовались эти доработки. Склонировал automake-1.9 и mysqlcppapi-2.0.0. При сборке последней пришлось поправить пару строчек в 1-ом или 2-ух файлах исходного кода, так как мы по умолчанию используем старый компилятор.
При желании можно собрать и свою версию libwxgtk3.0. Я это сделал, чтоб убедится что все зависимости установлены.
В старой версии OpenCPN работа с прогнозами погоды была не такая продвинутая как в zygrib_7. Поэтому можно собрать и использовать дополнительную программу, а можно доработать встроенный плагин OpenCPN для разбора файлов прогноза. В итоге у вас из исходников должно получиться 2 deb пакета:
zygrib-maps_7.0.0-1_all.deb
zygrib_7.0.0-1_armhf.deb
Библиотеки необходимые для подключения принтера этикеток Zebra GK420d
После установки следующих библиотек и настройки cups Zebra GK420d cтал печатать без доработки исходного кода. При не правильной настройке драйвера или размера этикетки принтер сообщает об ошибке превышения отступов.
sudo apt-get install cups foomatic-db-compressed-ppds cups-pdf smbclient xpp
sudo apt-get install ghostscript-x printer-driver-gutenprint
sudo apt-get install cups-browsed font-droid libpaper-utils
В wxWidget в библиотеке печати прошито намертво приложение evince с характерными для него ключами. Эта команда хранит свои параметры в бинарном формате в каталоге:
/home/olimex/.local/share/gvfs-metadata
Это стандартное хранилище для gnome, но не для нашего облегчённого оконного менеджера – lxde.
Автостарт в lxde
Кстати, если вам нужно настроить автостарт для этой среды, нужно редактировать этот файл:
/home/olimex/.config/lxsession/LXDE/autostart
Либо скопировать desktop файл из каталога /usr/share/application/ в каталог, как в примере ниже:
/home/olimex/.config/autostart/LXinput-setup.desktop
Настройка lp
Я использовал для распечатки команду lp, которую можно настроить на заданный тип принтера из командной строки. Более подробную информацию смотрите на вашем локальном web CUPS сервере через Mozilla Firefox: http://localhost:631/help/options.html
Там же через web интерфейс можно выбрать доступный принтер, настроить драйвера для притера (ppd файлы), поменять права доступа к нему. Так же можно посмотреть очередь печати и возможные ошибки возвращаемые принтером.
lpstat -p -d
lpoptions -d Zebra_Technologies_ZTC_GK420d
lp testprint.pdf
lp test.txt
lp test.jpg
Для запуска нужного приложения по нажатию кнопки “Print preview” в wxWidget нужно обновить альтернативные программы. По умолчанию для показа перед печатью используется браузер, но только если не установлен gv или xpdf, а так же evince.
После того как вы установите необходимый просмотрщик файлов можно попробовать использовать команды:
xdg-mime default lp.desktop application/pdf
update-alternatives --config x-www-browser
И изменить содержание файла /home/olimex/.config/mimeapps.list
application/pdf=pdf.desktop
на
application/pdf=lp.desktop
Файл /usr/share/application/lp.desktop получается копированием файла xpdf.desktop путём замены строчки на Exec=lp. Параметр имя в этом файле тоже надо поменять: Name=lp
Изменить файл /etc/papersize следующим содержанием:
w288h432
Лучше всего подходит модуль R5370-ANT. Он имеет антенну и поддерживает все необходимые протоколы и самое главное поддерживается этим имиджем Olimex из коробки. Имеется аналог, но без антенны R5370.
sudo apt-get install wpasupplicant
rfkill list
rfkill unblock wifi
iwconfig
sudo ifconfig wlan0 up
sudo iwlist wlan0 scan | grep ESSID
В файл /etc/network/interfaces добавить:
auto wlan0
iface wlan0 inet dhcp
wpa-ssid your_wifi_ssid
wpa-psk your_wifi_pass
ssid и psk значения в этих файлах и командах надо заменить на принятые в вашей сети. Для генерации файла /etc/network/wpa_supplicant.conf
cd /etc/network
wpa_passphrase your_wifi_ssid your_wifi_pass | sudo tee wpa_supplicant.conf
Файл получиться примерно такой
network={
ssid=your_wifi_ssid
scan_ssid=1
psk=your_wifi_pass
key_mgmt=WPA_PSK
}
Следующая команда выполнит подключение устройство к местной wifi сети:
cp wpa_supplicant.conf /etc/wpa_supplicant.conf
killall wpa_supplicant
sudo wpa_supplicant -c /etc/wpa_supplicant.conf -i wlan0
iwconfig
dhclient wlan0
ifconfig
После рестарта устройства WiFi подхватится автоматически.
apt-get install ntp
timedatectl status
timedatectl list-timezones
timedatectl set-timezone Europe/Madrid
Новые принтеры Zebra GK420d отличаются процедурой инициализации для USB от выпущеных ранее 2007 года. Возможно придется внести изменения в настройки CUPS (ELP II) или в ppd файли или в исходный код.
Настройки могут быть связаны с отступами, шириной распечатываемой области (Print Width – на фото ниже помечен овалом справа). Zebra использует старый язык управления принтерами подобный ELP и при переходе к новым стандартам растровой печати с поворотом страницы требуется компенсатция левого отступа.
Вот примерно в этом месте можно вставить изменения прямо в исходники CUPS. Но лучше исправить ppd файл и подгрузить параметры стандартным образом.
Для распечатки конфигурации принтера нажмите кнопку на панели принтера и не отпускайте до момента пока светодиод мигнёт один раз, затем отпустите кнопку.
Серия из одного и двух миганий (пока вы держите кнопку нажатой и отпускаете после двойного мигания) обеспечит автоматическую калибровку носителей (параметры на фото помечены прямоугольником слева). Будут выплюнуты от одно до четырёх наклеек, которые можно будет руками венуть назад.
Если удерживать кнопку до последовательной серии в пять миганий (одно, два, три, четыре, пять), то будет начата распечатка прямоугольников с шагом в 4 мм. Повторное нажатие кнопки подтвердит выбранную вами ширину.
Процедура инициализации новых принтеров выпущенных в 2021 году или позже:
~SD15
~TA000
~JSN
^XA
^ST09,15,2021,11,06,15,M
^XZ
^XA
^SZ2
^PW812
^LL1218
^PON
^PR5,5
^PMN
^MNY
^LS0
^MTD
^MMT,N
^MPE
^XZ
^XA^JUS^XZ
~SD10 – яркость
~TA000 – без отрывания этикетки (для этого надо подключить резак)
~JSN – обратная подача по умолчанию (нет)
^SZ2 – режим EPL II
^PW609 – ширина принтера
^LL1246 – длинна этикетки
^PR5,5 – скорость вывода на печать
^MNY – отслеживание подложки между этикетками, ^MNA – автоматическая калибровка, ^MNM – отлеживание чёрных полосок, ^MNN – рулон без перерывов
^LS0 – левое положение (отступ)
^XA – запуск команды форматирования
^JUS – команда сохранения конфигурации
^XZ – завершение команды форматирования
Для отключения сенсора новой этикетки, если вы просто хотите распечатывать чеки, используют следующую команду:
^XA^MNN^JUS^XZ
Пошлите эту команду в принтер или вставте ^MNN - рулон без перерывов
в поток данных, который посылаете.
Пример распечатки документа в wxWidget. Пример настройки причуды для принтера в файле /usr/share/cups/usb.
Wouldn’t it be needed to add this quirck to org.cups.usb-quirks ?
# Zebra GD420 (https://github.com/apple/cups/issues/5395)
0x0a5f 0x0080 unidir no-reattach
Как упоминалось ранее было использовано следующее ультрaзвуковое устройство LCD-TS15.6. Лучшая инструкция по конфигурации и калибровке тут. Но 7 шаг из этой инструкции делать не обязательно, и скорее это приведет к постоянной перегрузке устройства.
Есть лог настройки, который реально помогает понять что нужно сделать.
После установки тачпанели в устройство нам надо повторить выполнение двух команд.
ts_calibrate
После запуска этой команды нужно будет последовательно нажать на 5 крестиков на экране. 4 по краям и один в центре. Затем скопировать записанные данные в надлежащее место.
cp /etc/pointercal /usr/etc/pointercal
Необходимо перегрузить систему. Затем убедится что USB интерфейс тачпанели имеет адрес, который прописан в /usr/share/X11/xorg.conf.d/20-ts.conf и в /etc/environment. Для уверенности я просто отключаю на USB хабе все остальные устройства и включаю их после загрузки системы.
Перед началом компиляции убедитесь что системные часы установлены на текущую дату и время. Без этого шага из-за неправильной автоматической настройки даты модификации файлов, утилита make будет каждый раз перекомпилировать все файлы и сообщать об возможной ошибке. Это очень затратно по времени. Полная компиляция OpenCPN на данном железе A20 может длиться дольше 40 минут.
date -s "16 AUG 2021 14:57"
cd OpenCPN
mkdir build
cd build
cmake ../
make
su
make install
opencpn -no_opengl
OpenGL это конечно боль этого старого имиджа Debian для SoC A20. Полагаю что в имиджах для новых продуктах Olimex решат проблему и по умолчанию настроят драйвера и поставят необходимые библиотеки для аппаратного ускорения графики.
Так как у нас на производстве используется планарный (не 3D) дизайн, то пока такой задачи как построение объемных 3D моделей не стоит, как и наложение слоёв в чертежах на данном рабочем месте. Возможно в будущем это будет актуально для других рабочих мест.
В прошлой статье не хватило места рассказать про подключение данных весов к USB разъёму. На выходе этих весов обычный COM DB-9, каких уже нет на современных компьютерах.
Для быстрого превращения COM в USB без паяльника я использовал MOD-RS232 и USB-SERIAL-F. С этими кабелями я много работал прошивая ESP8266 поэтому был совершенно уверен, что они совместимы с любой версией Linux без компиляции дополнительных модулей.
Я открутил разъем от корпуса, подключил модули внутри корпуса, выпустив USB конец кабеля наружу. И предварительно закрепив узел кабеля внутри весов.
Включил режим непрерывной передачи параметров и стал регулярно через MiniCOM принимать данные в текстовом виде от весов в момент изменения веса. Данные состояли из 3 параметров, которые дублировали содержимое 3 экранов на лицевой панели весов (Weight, Unit Weight, Total Count).
Причем меня интересует только Weight, потому что Unit Weight удобнее брать из Базы данных ERP. А Total Count вычислять самостоятельно и сравнивать с необходимым по заказу. И соответственно выводить Диалог с Progress Bar. Тогда работнику не нужно будет следить за числами, достаточно просто смотреть на индикатор.
Так как наши весы заняты на производстве, то первым делом я добавил в подходяшее место в OpenCPN симуляцию посылки весами данных. Это можно считать своеобразным тестом будущего парсера протокола весов.
void PlugInManager::SendNMEASentenceToAllPlugIns(const wxString &sentence)
{
wxString sentence1 = "G.W. :+ 10.1155kg\n";
// wxString sentence1 = "U.W. :+ 0.08155 g/pcs\n";
// wxString sentence1 = "Total:+ 144 pcs\n";
wxString decouple_sentence(sentence1); // decouples 'const wxString &' and 'wxString &' to keep bin compat for plugins
for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
{
PlugInContainer *pic = plugin_array.Item(i);
pic->m_pplugin->SetSentence(decouple_sentence);
if(pic->m_bEnabled && pic->m_bInitState)
{
if(pic->m_cap_flag & WANTS_NMEA_SENTENCES)
pic->m_pplugin->SetNMEASentence(decouple_sentence);
}
}
}
Как видно в коде выше OpenCPN формирует строку для передачи в плагин NMEA. По началу я создал отдельную библиотеку для протокола весов. Но в силу нехватки времени переключился на реализацию протокола весов прямо внутри библиотеки разбора NMEA. При этом я планирую вынести весь этот код в отдельную библиотеку дашборда в будущем во время рефакторинга.
Для того чтоб срабатывало прерывание и вызывалась эта функция, я подключал мой USB GPS приёмник. Благодаря этой дополнительной строчке я получал данные характерные для весов.
Для получения реальных данных с весов надо подключить весы, сменить в графических настройках OpenCPN источник данных с GPS на MyWeigh, закомментировать эту тестовую строчку и перекомпилировать этот файл с последующей линковкой и установкой исполняемых библиотек и самой программы opencpn.
Функция SetSentence добалвлена в плагин dashboard_pi по аналогии с SetNMEASentence. Причем все протоколы вынесены в отдельные подкаталоги этого плагина и оформлены в виде классов. Я поступил точно так же и завел подкаталог myweigh, в котором находятся все необходимые файлы для парсинга протокола весов.
При компиляции и линковке возникли ошибки. Как я сейчас понимаю, скорее всего из-за не прописанного myweigh.h или myweigh.hpp. Все эти исправления я оставил на рефакторинг, а сами файлы перенес в основную часть плагина dashboard_pi. То есть на один уровень выше, не выделяя в подкаталог.
Посмотрим на функцию АPI плагина, которую я добавил.
void dashboard_pi::SetSentence( wxString &sentence )
{
// m_MyWeigh << sentence;
m_NMEA0183 << sentence;
// wxCharBuffer buf = sentence.ToUTF8();
// wxString mnemonic = buf+1;
// mnemonic = mnemonic+2;
bool bGoodData = false;
if( m_NMEA0183.PreParse1() )
{
if( m_NMEA0183.LastSentenceIDReceived == _T("G.W."))
{
if( m_NMEA0183.Parse1() )
{
bascula_weigh = 0.0;
if(m_NMEA0183.Gw.IsDataValid == NTrue)
{
bascula_weigh = m_NMEA0183.Gw.UnitWeighKg;
bGoodData = true;
SendSentenceToAllInstruments( OCPN_DBP_WEIGH, bascula_weigh, "kg" );
// wxString msg1;
// msg1 += _T("\n\n");
progress_dialog = instrument_progress_dialog->GetPprog(bascula_weigh, db_weigh, db_quantity);
// progress_dialog->Hide();
// instrument_progress_dialog->ppprog->Update(20);
// instrument_progress_dialog->ppprog->Show();
// instrument_progress_dialog->ppprog->Raise();
}
}
}
if( m_NMEA0183.LastSentenceIDReceived == _T("U.W."))
{
if( m_NMEA0183.Parse1() )
{
double unit_weigh = 0.0;
if(m_NMEA0183.Uw.IsDataValid == NTrue)
{
unit_weigh = m_NMEA0183.Uw.UnitWeighKg;
SendSentenceToAllInstruments( OCPN_DBP_UNIT_WEIGH, unit_weigh, "kg/pcs" );
}
}
}
if( m_NMEA0183.LastSentenceIDReceived == _T("Tota"))
{
if( m_NMEA0183.Parse1() )
{
double total_unit = 0;
if(m_NMEA0183.Tot.IsDataValid == NTrue)
{
total_unit = m_NMEA0183.Tot.TotalUnit;
// getUsrDistanceUnit_Plugin( g_iDashDepthUnit );
SendSentenceToAllInstruments( OCPN_DBP_TOTAL_QUANTITY, total_unit, "pcs" );
// SendSentenceToAllInstruments( OCPN_DBP_TOTAL_QUANTITY, total_unit, m_NMEA0183.LastSentenceIDReceived );
}
}
}
}
// if(bGoodData)
// {
// Refresh(false);
// }
}
В 13, 35, 48 строчке видно что парсинг происходит по первым 4 символам принимаемым от весов. В отличие от NMEA протокола нет пропуска первого служебного символа. Так как протокол весов не содержит такового.
После 2 дополнительных проверок m_NMEA0183.Parse1() и m_NMEA0183.Gw.IsDataValid происходит присваивание значения через вызов метода соответствующего класса (Weight, Unit Weight, Total Count).
В строчках 20, 42 и 55 происходит вызов 3 различных классов, которые написаны для разбора 3 различных сообщений весов. Эти классы мы посмотрим позже (Смотрите параграф ниже – “Класс Gw”).
А пока обратим внимание на вызов функции в 22 строчке:
SendSentenceToAllInstruments( OCPN_DBP_WEIGH, bascula_weigh, "kg" );
Тут происходит выбор виртуального дисплея или инструмента (яхтенный сленг) для вывода полученных данных – bascula_weigh. Причем указываются единицы измерения килограммы – “kg”. Отображение информации происходит в момент её получения.
Все задержки связаны только с работой нашего устройства и физических протоколов передачи через COM->USB. И не зависят от Бакенд сервера. Поэтому можно считать что мы на своём дашборде контролируем и получаем информацию в реальном режиме времени. Так как на нашем заводе не будет более 10 таких устройств (на текущий момент всего 2 устройства), то бакенд для доступа к базе данных не нужен. Можно забирать необходимые данные напрямую.
Реализацию класса DashboardInstrument_Weight я сделал по аналогии с уже готовым стандартным одиночным (одно значение) инструментом. Посмотреть его можно в файле instrument.cpp.
Заглянем в файл sentence.cpp. Разница в методах Field1 и Field заключена всего в одной строчке которая определяет первый разбираемый символ и выборе другого разделяющего символа. Это 8 строчка, которая говорит что мы считаем символы с нулевой позиции (в Си и С++ индексы нумеруются с 0).
onst wxString& SENTENCE::Field1( int desired_field_number ) const
{
// ASSERT_VALID( this );
static wxString return_string;
return_string.Empty();
int index = 0; // Keep over the G/U at the begining of the sentence
int current_field_number = 0;
int string_length = 0;
string_length = Sentence.Len();
while( current_field_number < desired_field_number && index < string_length )
{
if ( Sentence[ index ] == ' ' )
{
current_field_number++;
}
if( Sentence[ index ] == '+')
return_string += Sentence[ index ];
index++;
}
if ( current_field_number == desired_field_number )
{
while( index < string_length &&
// Sentence[ index ] != '+' &&
Sentence[ index ] != ' ' &&
// Sentence[ index ] != ',' &&
Sentence[ index ] != '+' &&
Sentence[ index ] != 0x00 )
{
return_string += Sentence[ index ];
index++;
}
}
return( return_string );
}
А еще мы запятую ‘,’ заменили на пробел ‘ ‘, а звездочку ‘*’ на плюс ‘+’ в полном соответствии с протоколом весов.
Вызов этого парсинга происходит через функцию Double1 из нашего класса Gw.
bool GW::Parse( const SENTENCE& sentence )
{
/*
UW - Unit Waigh
1 2 3 4 5
| | | | |
$--VLW,x.x,N,x.x,N*hh<CR><LF>
Field Number:
1) Total cumulative distance
2) N = Nautical Miles
3) Distance since Reset
4) N = Nautical Miles
5) Checksum
*/
/*
** First we check the checksum...
*/
// if ( sentence.IsChecksumBad( 5 ) == TRUE )
// {
// SetErrorMessage( _T("Invalid Checksum") );
// return( FALSE );
// }
// TotalMileage = sentence.Double( 1 );
UnitWeighKg = sentence.Double1( 2 );
// UnitWeighKg = 20.0;
// TripMileage = sentence.Double( 3 );
return( TRUE );
}
Как видно все комментарии требуют рефакторинга, который я планировал сделать после подключения другого вида весов, чтоб уловить общие закономерности в китайских протоколах и сделать этот метод разбора более гибким. То есть добавить дополнительные проверки и условия.
Среди инструментов создан еще один класс DashboardInstrument_ProgressDialog который предназначен для вывода модального окна с индикатором веса (аналогичного индикатору копирования файлов). Оно всегда висит сверху и не закрывается даже при закрытии родительского окна.
Идея в том что когда работник из пакета насыпает мелкие детальки на весы, ему не нужно их считать и не нужно нажимать дополнительные кнопки на весах для каждой новой позиции в заказе. Кроме того система учитывает размеры полных пакетов и даёт информацию по остатку неполного пакета, который проходит через весы. Тем самым сокращается время на рутинные операции.
Формула расчета положение индикатора находится в файле instrument.cpp.
wxProgressDialog* DashboardInstrument::GetPprog( double bascula_weigh, double db_weigh, double db_quantity )
{
int cur_count;
cur_count = wxRound( pd_count * bascula_weigh / (db_weigh * db_quantity) );
if (cur_count > 90) { cur_count = 95; }
wxString msg5;
msg5.Printf(_T("%d * %d / ( db_weigh * db_quantity ) = %d "),
pd_count, wxRound(bascula_weigh), wxRound(db_weigh * db_quantity));
ppprog->Update(cur_count, msg5);
return ppprog;
}
Индикатор доходит до 95% только, потому что после 100% он исчезает, где исправить это поведение я не знаю. Нужно чтоб этот диалог всегда находился на своём месте. Перерисовывать его каждый раз при выборе новой позиции считаю не рациональным по затратам времени.
Так же распечатывает необходимые этикетки. И делает это все в базе данных в рабочей ERP, состояние которой видит весь офис и может отслеживать выполнение заказа. Под офисом я понимаю отделы кладовщика, продажников, логистику, администратора и начальника.
Весь новый интерфейс пользователя сосредоточен в отдельном втором основном модальном окне. Весь код которого находится в одном файле myframe1.cpp.
Доступ к базе данных оформлен внутри этого файла, но позже надо будет разделить и подумать чтоб в далёкой перспективе эту часть можно заменить на ORM или API.
Принтер управляется отдельными классами. Для построения списка распечатываемых этикеток и управления самим принтером есть специальные файлы: Label.cpp, LabelPoint.cpp, Select.cpp, labelprintout.cpp. В них все более или менее стандартно. Необходим опыт использования системы, чтоб понять в какую сторону двигаться.
В системе есть функции построения QR кодов (как растровых, так и текстовых), отрисовки изображения (как на экране, так и на этикетке).
Если будут интересны детали отрисовки окон с таблицами на wxWidget напишите в комментариях, тогда я дополню статью или напишу дополнительную по графическому интерфейсу пользователя, поведенческим вызовам или обработчикам мышки, клавиатуры, тачпанели.
Чтоб подключить несколько устройств USB (тачпаннель, принтер, весы, wifi, bt для безпроводной клавиатуры и мышки) к OLinuxino A20 с всего лишь двумя USB разъёмами, нужно подключать USB hub. Но подобные хабы через один USB кабель при передаче данных могут обеспечить ограниченное питание на каждый порт\устройство.
Поэтому рядом с кабелем USB на них имеется специальный разъём для питания в 5 вольт всего мультиплексора. Сейчас такие блоки питания редкие.
Вероятно они использовались раньше для многих старых мобильных телефонов. Если вам не удастся подобрать штекер, то придется перепаивать на гнездо большего размера и дорабатывать корпус хаба под это гнездо.
Есть вариант изготовления своей собственной платы периферии и стандартного модуля Olimex, подключаемого по шине расширения. В механическом плане это примерно плюс 5 мм -10 мм к толщине алюминиевого профиля необходимого для тачпанели и LCD (надеюсь что меня поправят опытные механики-электроники). Все конечно зависит от соединений плат внутри корпуса. Если взять с запасом на неудачные толстые кабели, то в целом 15 мм достаточно с запасом для интеграции всех готовых Olimex плат внутри металлического корпуса. Итого толщина профиля должна быть между 24 мм и 40 мм.
Примерно 30 лет назад, мы все в МИЭТ (год основания 1965) сдавали курсовик по начерталке на тему изготовления корпуса стандартного электронного устройства. Вероятно, технологии которые я использую для корпуса устройства, сопоставимы с возрастом моей новой яхты. East Anglian MkII изготовленной из дерева в Англии в 1961 году. Фотографии данного класса яхт есть в предыдущей стататье. Естественно у меня также имеются все оригинальные полные чертежи этой яхты, сделанной на заказ. Таким образом конструкция этой яхты, как и дизайн моего навигатора является Open-source hardware (OSH).
Уверен что в ближайшие годы Olimex найдет способ использовать микропроцессор с открытым дизайном, если такой появится на рынке. Существуют с 2000 года бесплатные программные продукты для дизайна микропроцессоров. Например, Static Free Software Home Page. В этом проекте мы с коллегами участвовали как русскоязычные тестеры и переводчики документации. И тогда веский аргумент о полной недоступности открытого во всех смыслах микропроцессора (включая устройство ядра) уйдет в прошлое. Предположительно говорю о ядре RISC-V. Наиболее вероятный чип для будущей платы Olimex на весну 2021 это Allwinner AP (application processor) SOC c открытм ISA (open standard instruction set architecture) для RISC-V. Вот тут подробнее. Оригинал статьи тут.
IMHO останутся вопросы по графическим сопроцессорам OpenGL, но со временем и их дизайн будет открыт.
Использование OpenCPN для автоматизации производства / Хабр (habr.com)
IT техническая сторона яхтинга / Хабр (habr.com)
Шпаргалка, которая нужна на яхте / Хабр (habr.com)
IT Релокация на яхте. Из Швеции в Испанию / Хабр (habr.com)
Есть хороший сайт с дистрибутивом для сборки кросс компилятора под основные платформы. Особенно различные ARM, которые популярны на большинстве современных устройств с Android и Linux.
В текущий момент сертификаты на нём не обновлены. Будем решать эту проблему.
Если у вас Debian GNU/Linux то можно добавить ссылку на репозиторий Debian в источники пакетов и поставить любой готовый тулчейн который подходит для компиляции под вашу платформу:
По выше приведенной ссылке есть все инструкции.
Вначале скачиваем дистрибутив.
https://www.pengutronix.de/en/software/ptxdist.html
Распаковываем в домашней директории в поддиректории local. Заходим в распакованную диеркторию,
./configure
make
sudo make install
После чего папку с дистрибутивом можно удалить, так как она уже скопирована в /usr/local.
Затем выбираем тулчейн с той же датой что и дистрибутив:
https://pengutronix.de/en/software/toolchain.html
Распаковываем в папку local в домашней директории пользователя. Заходим в директорию и вводим выбранную конфигурацию из имеющегося подкоталога ptxconfigs:
ptxdist select <ptxconfigs>
ptxdist go
Дистрибутив сам начинает скачивать необходимые исходники и выстраивает цепочку перекомпиляции компиляторов. Возможно ваша система уведомит об устаревших сертификатов этого сайта.
Для этого вначале настроим git чтобы он не проверял сертификаты:
Далее заходим в поддиректории, устанавливаем дистрибутив и собираем тулчейн.
cd ptxdist./autogen.sh && ./configure && makesudo make installcd ../OSELAS.Toolchainptxdist select ptxconfigs/arm-v7a-linux-gnueabi_gcc-11.1.1_clang-12.0.0_glibc-2.33_binutils-2.36.1_kernel-5.12.4-sanitized.ptxconfigptxdist go
Чтобы нас не беспокоили сертификаты при загрузке исходников через wget или curl добавим 2 строчки в файл /usr/local/lib/ptxdist-2022-*/scripts/lib/ptxd_make_get.sh
Добавляем примерно в 22 строчку, сразу после инициализации переменных в функции ptxd_make_get_http()
opts[${#opts[@]}]=”–no-check-certificate”
curl_opts[${#curl_opts[@]}]=”–insecure”
Новая версия ptxdist требует для компиляции ядра Linux ряд библиотек:
apt install -y libgmp-dev libisl-dev libmpc-dev libssl-dev liblzma-dev
Возможно какие то ещё компоненты потребуются, если они не установлены на вашей системе. Следите за сообщениями скриптов компиляции ptxdist.
15 января 2020 года я опубликовал статью: “IT техническая сторона яхтинга”
IT техническая сторона яхтинга / Хабр (habr.com)
Которая вызвала интерес у читателей. В этой статье я продолжаю тему автоматизации яхты. И на конкретном примере рассказываю о развитии популряной программы OpenCPN/OpenCPN: A concise ChartPlotter/Navigator. A cross-platform ship-borne GUI application supporting * GPS/GPDS Postition Input * BSB Raster Chart Display * S57 Vector ENChart Display * AIS Input Decoding * Waypoint Autopilot Navigation (github.com), которая по сути является индустриальной программой написанной в хорошем стиле. Кроме того в силу использования wxWidget весть код нативный и может собираться на нескольких целевых платформах. Таких, как Linux, Windows, Android, macOS.
Продолжение этой статьи Все «тайны» настройки софта для модулей и периферии OpenCPN / Хабр (habr.com)
На производстве используются электронные весы для подсчета количества отгруженных мелких деталек. Нужно было усовершенствовать эти весы, чтобы они отображали в реальном режиме времени прогресс диалог на основе веса детальки, числовое значение веса которой достаётся из базы данных.
Или другими словами задача замены ордера на производство его электронной версией с функциями контроля отгрузки и распечатки этикеток с QR кодами.
Вспомнив, что популярная и лёгкая программа OpenCPN уже имеет реализацию для настройки гибкого и быстрого окружения пользователя. Что она подходит для работы на непроизводительном железе. И самое главное имеет реализацию протокола работы с COM->USB интерфейсом для GPS, который во многом схож с протоколом электронных китайских весов.
Так как я интересуюсь яхтингом и у меня есть задача создания навигационной системы с тачэкраном. И для весов также был нужно управление путем тыканья одним пальцем по экрану. То я и выбрал OpenCPN для этой задачи.
Для прототипа были использованы компоненты компании Olimex.
A20-OLinuXino-Micro.pdf (olimex.com)
В частности ARM компьютер на базе процессора AllWiner. Я использовал A20, так как у меня был один в запасе. Позже я приобрел наиболее продвинутую плату A20-MICRO с индустриальным диапазоном температур на основ процессора T2, который в точности соответствует по геометрии и функционалу процессору A20. Плата имеет emmc память, поэтому прошивка устройства загружается и работает прямо с микросхемы, без посредсва микро SD карты.
Так же была заказана LCD панель (LCD-OLinuXino-15.6FHD – Open Source Hardware Board (olimex.com)) максимального размера и разрешения и ультразвуковой тачскрин (LCD-TS15.6 (olimex.com)), который может работать в неблагоприятных условиях. Например во время сильного дождя. Или под ударами волн, в случае надежной изоляции от воды всей электронной начинки. Это кусок стекла, с прикрепленными по 3 углам 4 пьезоэлементами и специально рассчитанными лазерными рисками по периметру. Риски служат для отражения ультразвуковой волны и их плотность связана с вкладом в частоту конечного сигнала.
LCD панель подключается кабелем аналогичным IDE-40. Подобные шлейфы-кабели использовались для подключения флоппи драйва, DVD и жестких дисков предыдущего до SATA стандарта.
Так же был куплен металлический бокс и жесткий диск на 2 терабайта для хранения различных имиджей. Так как прошивок за более 5 лет производства Olinuxino накопилось довольно много. Не на всех прошивках все устройства поддерживаются, так как болгарская компания Olimex и её владелец Цветан и его брат не вкладывают деньги в подготовку и тестирование фирменных прошивок непосредственно. Но проводит несколько конференций для разработчиков в направлении Опен Соурсе Софтваре и Опен Соурсе Хардваре.
Для нашего экрана и нашей платы подошёл только вот старый имидж Debian для Olimex A20.
Изготовление корпуса устройства и подбор подходящего блока питания — это отдельная задача. Дело в том что устройству необходимо 3 источника питания в диапазоне от 5 до 12 вольт. Скорее всего подойдёт, по возможности узкий, блок питания для компьютера.
Для трех плат управления (OLinuxino A20, контроллер LCD, Контроллер тачскрина) был собран шлейф с разъёмами совместимыми с блоком питания. Причем на контроллер VGA подаётся 5 вольт по рекомендации документации, хотя в теории эта плата может работать и от 12 вольт, остальные платы запитаны напряжением 12 вольт. На большом разъеме ITX блока питания зеленый провод соеденен с землёй перемычкой для включения самого блока питания. В нашем случае устройству не требуется дополнительная кнопка включения питания. На яхте для этого есть тумблер подачи питания на картплотер, а на производстве проще выключить устройство из розетки при завершении эксплуатации.
Так как наш завод выпускает готовые механические наборы частей окон для безрамного остекления (claroflex.ru) по проектам которые готовятся на нашей ERP системе. Поэтому корпус монитора решено было сделать из профиля, который используется для одного из наших новых продуктов.
Стороны “рамки” соединенны посредством алюминиевых уголков, которые туго входят в профиль и заклёпочного соединения с одной стороны. Одна из узких сторон может быть выдвинута (там нет заклёпок), она туго сидит в собранном виде, но соединение будет усилено через саморезы вкручиваемые по периметру задней крышки корпуса в места расположения деревянных вставок внутри профилей.
В каком то смысле это прототип окна будущего, где каждая точка поверхности “чувствует” прикосновение. Естественно эти возможности на производстве будут использоваться для управления и автоматического распечатывания стикеров с QR кодами.
Если следовать документации на ультразвуковой тачскрин и экран, то заступы могут быть до полутора сантиметров с каждой стороны экрана. Соответственно сама LCD панель меньшего размера.
Внутри профиля остается запас места для кабеля сенсоров и прочности достаточно для крепления корпуса самого микрокомпьютрера Olimex.
Различные опции по герметизации корпуса. Мы используем специальный клей для резиновых прокладок.
В наших профилях предусмотрены места для установки различного вида и толщины прокладок из резины, которые закрепляются фирменным клеем. Этого достаточно для производства или для окон в помещениях. Но, по мнению специалистов, лучшим способом гидроизоляции остается силикон в руках опытного специалиста.
Первая версия устройства будет работать в запыленном помещении и которое возможно иногда со стороны экрана будут протирать с водой во время уборки. Поэтому по периметру корпуса в месте касания тач-панели (ободок экрана) мы использовали самый тонкий резиново-пластиковый уплотнитель.
Между экраном и тач-панелью по длинным сторонам так же располагаются мягкие резиновые уплотнители, которые идут в комплекте с LCD панелью.
Металлические ушки LCD панели крепятся к L-образным скобкам, которые в свою очередь закреплены кубическими деревянными вкладками внутри нашего профиля. Всего таких деревянных вкладок восемь, по две на каждую сторону. В зависимости от имеющегося у вас крепления можно рассчитать наиболее удачное положение этих вкладок на длинной стороне, так как LCD панель имеет четыре точки крепления, то и L- образных скобок четыре штуки.
На наиболее протяженных сторонах тыльной части LCD панели укреплены мягкие резиновые губки, которые обеспечивают мягкий упор панели и не допускают её деформацию при любом положении экрана. Они способны демпфировать любые случайные нагрузки при монтаже задней панели или во время эксплуатации.
Тыльная сторона устройства прикрыта сплошным листом в котором сделен выпил для LCD кабеля IDE-40 и 2 кос питания. Одна для LCD – 5V, другая для акустической тач-панели. Металлические корпуса блока питания и OLinuxino A20-Micro крепятся заклепками или любым другим крепежом к задней крышке устройства.
С внутренней стороны задней крышки размешается контроллер тачпанели. Так как панель металлическая то необходима пластиковая изоляционная прокладка. Макет которой и видно на фотографии выше. У контроллера есть отдельный проводок для общего заземления, он закрепляется небольшим болтиком за крышку устройства изнутри.
Для яхты я планирую делать традиционный плоский монтаж на стене. Каждый блок отдельно со своей отдельной герметизацией. А блок питания от 220 вольт опциональное устройство на яхте. Так как пользоваться им можно будет только на стоянке. Но на яхте можно поставить отдельный сервисный аккумулятор специально для питания навигационного устройства и рации.
Первым делом была изучена часть кода, которая отвечала за разбор GPS протокола. И по аналогии был создан разбор протокола от автоматических весов.
uw · Ignat99/OpenCPN@3364ddf (github.com)
В результате нескольких итераций, распознавание было настроено с первого символа, а парсинг осуществлялся по пробелу. Для автоматических весов конкретной марки этого достаточно.
space · Ignat99/OpenCPN@112db20 (github.com)
Далее была выбрана библиотека для поддержки MySQL в C++ и все необходимые файлы были добавлены к коду OpenCPN.
DB work · Ignat99/OpenCPN@1e32d96 (github.com)
Давно хотел добавить базу данных к OpenCPN для хранения треков и прокладок курсов для яхты, а так же для хранения конфигурации оборудования и помощи в управлении. Можно использовать Базу данных и для бортового журнала и для автоматического заполнения данных о погоде взятых с погодной станции.
Оставшиеся коммиты были созданы для создания отдельной панели для доступа к базе данных и связывания в UI таблиц. Так, например, можно с помощью элементов поиска выбрать необходимые проекты, а уже кликнув на нужный проект найти записи по компонентам данного проекта.
Точно таким же образом в базе данных можно сохранять информацию по внутреннему устройству яхты, особенно всё что связано с принципиальными схемами электроники, электрики и механики. В будущем, возможно, акустические и магнитные схемы транспорта могут быть востребованы.
Это расширение основной программы. По сути каждый плугин это динамическая библиотека с несколькими стандартными вызовами со стороны основной программы OpenCPN.
Весь интерфейс сделан на основе фреймворка компонентов wxWidget (wxWidgets/wxWidgets: Cross-Platform GUI Library – Report issues here: https://trac.wxwidgets.org/ (github.com) ).
Основная точка входа для плугинов находиться в файле OpenCPN/src/pluginmanager.cpp. Этот класс PlugInManager отвечает за составление списка плугинов, за их инициализацию и передачу потока управления (нажатие на мышку и клавиатуру) в пулгины.
Также в этом файле находятся интерфейсы для передачи данных от устройств по специфическим протоколам. Рассмотрим для примера метод PlugInManager::SendNMEASentenceToAllPlugIns.
OpenCPN/pluginmanager.cpp at master · OpenCPN/OpenCPN (github.com)
Эта функция проходит по списку всех плугинов, проверяет флаги и в случае совпадения типа передает полученную от устройства часть данных в функцию, которая реализована уже внутри динамической библиотеки плугина.
Эта функция хорошая точка для вставки функции для тестирования потока данных от виртуального устройства. Именно в начале этой функции можно задать тестовую посылку, которая может потребоваться на этапе создания плугина.
Код самих плугинов находится в отдельной папке (OpenCPN/plugins at master · OpenCPN/OpenCPN (github.com)). Это связано с тем что плугины создают различные вендоры и по сути это папка платформы OpenCPN в которой располагаются различные плугины. Плугины можно сравнить с приложениями в Android или Windows.
Требования для компилятора плугинов и состава библиотек могут не соответствовать старым версиями OpenCPN, поэтому компиляция отдельных плугинов может оказаться отдельной задачей.
Рассмотрим для примера плугин dashboard_pi. Помимо папки с исходными кодами, есть папка для i18n, где содержатся переводы строк текста на различные языки. В папке src могут находиться дополнительные каталоги для библиотек различных протоколов и сериализации JSON. Часто эти библиотеки просто копируют из основного кода.
Обратим внимание на файл dashboard_pi.cpp и метод dashboard_pi::SetNMEASentence(OpenCPN/dashboard_pi.cpp at v4.0.0 · OpenCPN/OpenCPN (github.com) ). По образу этого метода можно создать свой метод для поддержки разбора данных от вашего уникального устройства.
Ключевыми являют 2 строчки кода. Первая осуществляет сравнение префикса сообщения с образцом (OpenCPN/dashboard_pi.cpp at v4.0.0 · OpenCPN/OpenCPN (github.com)). И еще одна строчка осуществляет отправку полученной информации в конкретный инструмент (OpenCPN/dashboard_pi.cpp at v4.0.0 · OpenCPN/OpenCPN (github.com)).
Инструменты на яхтенном жаргоне это дисплеи которые выводят параметры. Например скорость, силу и направление ветра, координату, расстояние до цели, наличие преград и опасностей в заданном радиусе и т.д.
Описание основных инструментов для данного плугина нахоиться в файле instrument.cpp (OpenCPN/instrument.cpp at v4.0.0 · OpenCPN/OpenCPN (github.com))
Каждый инструмент содержит несколько стандартных методов. А именно: Инициализатор, Установку размера, Отрисовку и обновление Данных.
Если вы хотите создать свой уникальный инструмент, который выбирается из меню Дашбордов, то необходимо просто поменять содержимое этих функций под ваши задачи. Например тип получаемы данных, фоновое изображение, единицы измерения. Так же можно добавить любые другие методы обработки данных или отрисовки.
Естественно для мониторинга параметров был использован механизм плугинов, что позволило создать специальный дашборд с набором инструментов необходимых для поддержания автоматических электронных весов. Так потребовались данные из базы для веса и количества каждого компонента, а так же универсальная формула для расчета индикатора ProgressDialog в процессе взвешивания необходимых элементов.
Аналогичные диалоги можно использовать для вывода показаний ветра и автоматического расчёта оптимального курса на каждый момент времени. Эти данные помогут создать необходимые настройки, уникальные для каждой конкретной яхты и погодных условий, для автопилота.
Мне известны 4 основных типа автопилота. Причем один из них, я бы назвал его первым, он легендарный. Таким автоконтролем обладала лодка Джошуа Слокам – Спрей. Устойчивость на курсе обеспечивалось симметричностью носовых и кормовых обводов.
Этим же типом автоконроля обладают современные лодки и проекты Виктора Языкова. Например мой любимый проект WIND M. Обычно такие лодки в состоянии построить очень опытные моряки с навыком самодельного строительства по самым современным технологиям и на лучшем технически современном уровне. Обводы этих яхт, плюс размещение мачт, тип парусного снаряжения, смещенный к корме киль, а так же выдвигаемый шверт или шверты позволяют тонко настраивать яхту на любой курс ветра при любом волнении. По сути эти яхты управляются “по воле мысли” (Конечно, не мыслью, а ручками настаиваешь яхту на прямолинейный ход), без специальных механических устройств. Можно сказать так – “При длительной практике в несколько месяцев руки настраивают яхту на автомате, без особых размышлений — достаточно только одной мысли о настройке”.
Второй тип — стандартное механическое ветроподруливающе устройство. Такое стоит на моей яхте.Суть устройства простая — при давлении ветра с одной стороны, специальное дополнительное перо руля поворачивает в противоположную сторону и возвращает лодку на заданный курс относительно ветра. То есть если ветер идёт по дуге, то яхта так же будет двигаться в соответствии с ветром, но в направлении киля, который сдерживает боковой дрейф на курсах галфинд и бакштаг. Кстати, именно галфинд самый не удобный в плане стабильности лодки на курсе.
Чаще всего выходит из строя сложная механика или механические предохранители снятия нагрузки при порывах ветра. Устройство баллера и пера руля так же более подвержены механическим повреждениям в случае наваливание на препятствие, чем более массивный штатный руль.
Именно для стабильности на галфинде и экономии места большое распространение получил третий тип – электрорулевой (электроподруливающее устройство с гироскопом). Внутри электромотор, пасики, червячная передача, электрогироскоп. Усилие на руле на этом типе сравнимое с усилием человека на хорошо сбалансированной яхте. Когда сила давления на парус ветра уравновешивается силой давления воды на перо руля. На не больших яхтах оно крепится одним концом к корпусу яхты, а другим к румпелю или штурвалу и управляет непосредственно основным пером руля через баллер как заправский вахтенный. Можно догадаться что в шторм электрорулевые слишком слабые.
Основная поломки это обрыв пасика и\или стачивание пластиковых микрошестерёнок из-за черезмерного усилия на румпеле во время порывов ветра. Соответственно для дальних переходов надо иметь запасные части для вашего типа электрорулевого.
На больших яхтах и мотоселерах, а также моторных яхтах устанавливают автопилот на гидравлике с приводом непосредственно на баллер (ось) руля. Чаще гидро, но есть и электроприводы на авторулевых. И чаще непосредственно на баллер, но есть и на румпель или штурвал.
Гидроавторулевые хорошо работают в шторм, до момента поломки. Чаще всего это прорыв старых шлангов высокого давления от сильного импульса переданного волной при ударе в перо руля или другие стандартные поломки техники с гидравликой.
К четвертому виду автоподруливающих устройств, я бы отнёс, электронные автопилоты. Внутри схемы находиться микропроцессор, MEMS акселерометр, GPS и т.д. Естественно, сенсоры могут быть вынесены в любое место на яхте и посредством проводов или беспроводной связи по специальным протоколам передают данные в центральный микропроцессор. Такие автопилоты способны менять программу управления в зависимости от проложенного курса, показания GPS, состояния ветра, AIS, зарегистрированных помех радаром (невидимых) или видеокамерой (видимых). Именно такого автопилота можно сделать на основе устройства (OLinuxino A20 Olimex), которое я использовал на своей яхте.
Поломки этого типа оборудования связаны с повреждением солёной водой непосредственно электронной платы внутри корпуса. Поэтому эти устройства либо должны быть защищены водостойкими корпусами, и водостойкими разъёмами, либо находится внутри сухого корпуса яхты, водоизолированного отсека яхты или водонепроницаемого внешнего контейнера. Так как управление непосредственно обеспечивается через электроавтопилот третьего типа, то добавляются еще и характерные поломки связанные с обрывом пасика и стачиванием пластмассовых механических частей внутри электропилота.
Ещё одно направление это подключение SDR для мониторинга окружающих судов через AIS и коррекция курса в соответствии с полученными данными.
Для начала можно сделать софт, который будет давать рекомендации. Если после длительного использования эти программы будут протестированы временем на безопасность, то можно добавить этот код для автоматического маневра посредством автопилота.
Ещё одно направление — это интеграция OpenCPN через BT с внешними интеллектуальными устройствами. Вот таким хорошим примером может быть личная радиостанция с функций человек за бортом, которая составляет важный элемент безопасности экипажа. Так как подобные личные радиостанции закреплены физически на каждом участнике перехода, который выходит на вахту.
Есть возможность подключить трекер головы Um-5. Во время ночной вахты у одиночника на лбу всегда нацеплен фонарик, который очень хорошо совпадает с ультразвуковым фонариком трекера. Поэтому с этим устройством достаточно одного взгляда на экран для промотки карты. И можно использовать направление взгляда для просмотра навигационной карты на одном экране в большем масштабе.
Именно поэтому мы выбрали Olimexino A20-MICRO, так как этой плате не требуется шильдик для подключения стандартного микрофона, а звуковые сигналы можно вывести прямо на обычные динамики. Кроме того звуки на яхте значат очень много. По сути контроль движения яхты происходит именно по звуковому интерфейсу. Капитан точно может идентифицировать все звуки. А появления нового шумового сигнала обычно является командой к действию. Например новый звук протекания воды или скрип стоячего такелажа – все подобные звуки являются сигнализацией неисправности, которая требует срочного исправления или коррекции.
Благодарю моих коллег по предприятию: Пако за предоставленную возможность выполнить такой проект, Хави за многочисленные консультации по техническим вопросам, опытного сотрудника предприятия – мастера Луиса за качественное изготовление корпуса.
Благодарю мастера нашего завода и капитана моторной яхты Хесуса за помощь с дополнительными материалами и профессиональную изоляцию силиконом второго корпуса чартплотера.
Эдуардо за помощь в установке тяжёлого ветроподруливающего устройства за кормой моей яхты. Так же там надо еще диагональные нержавеющие перехваты в раме приварить.
Моему товарищу Павлу за проводку электрики и подключение электроавтопилота к сети питания яхты.
Давнему надёжному другу Лео за реализацию трекера в железе и за многолетнее терпение в ожидании этого проекта.
А также яхтенного капитана Виталия Елагина (oceanschool.ru) за консультации по технической части автопилотов и соавторство по тексту абзацев во время его морского перехода в районе севера: Архангельск – Соловецкие острова.
Когда вы несете вахту ночью и вокруг только звезды и где-то в паре метров от вас слегка подсвеченный компас. В этот момент для полного комфорта управления желательно иметь под рукой надежное навигационное устройство.
Водостойкое (достигается помещением планшета в водонепроницаемый прозрачный пакет) и с возможностью установки дополнительных программ, которые позволяют скоротать время на вахте. Таких, как Stellarium-android, андроид интерфейс для SunSDR2 радио и т.д.
В предыдущих статьях я написал как сделать стационарное устройство с вложением 300 евро. А сегодня разберём как сделать такое устройство с нулевыми вложениями, при условии, что у вас уже есть любое Android устройство и опыт в кросс-компиляции.
Начинать лучше всего с краткой инструкции. К сожалению, местами она устарела, а местами очень краткая. Поэтому первым делом предлагаю поставить Android SDK вот таким способом через IDE Eclipse.
Я сознательно не использую Android Студио, так как код который мы будем разбирать был сделан 5 лет назад. Во избежания недоразумений я использую GNU/Linux Debian Wheezy. Так как все библиотеки в этом олдолдстабле дистрибутиве соответствуют Android NDK от 10 релиза (r10e). Полный список всех доступных 64 битных релизов NDK находиться тут.
Будте внимательны, если у вас 32 битный компьютер, то вам не надо заниматься компиляцией тулчейна с нуля (по крайней мере для известного железа, всё уже собрано). 32 битные NDK для вашего целевого компьютера Linux можно скачать тут.
Ignat99/OpenCPN at wxqt (github.com)
Ignat99/wxWidgets at wxQT (github.com)
В указанных репо выложен код, который использовался для подготовки этой статьи. Звук закомментирован, OpenGL не включен, плагины OpenCPN не собраны. Кое какие функции приводят к падению приложения. Но приложение собирается и запускается и с этой точки можно продолжить работу над приложением.
Например нужно подобрать подходящий более современный исходный код для OpenCPN под Android, так как существует множество репозитариев с множеством веток кода, которые не совместимы между собой. IMHO Найти более подходящий рабочий исходный код – это отдельная задача.
У меня другая задача – добится стабильной работы на андроиде именно функций и плагинов, которые мною были созданы под GNU/Linux Debian.
Создаём необходимые директории
mkdir ~/Projects/
mkdir ~/Projects/android-ndk/
sudo mkdir /opt/android_toolchain
sudo chown -R <user_name>/<user_group> /opt/android_toolchain
Разархивируем в созданную директорию android-ndk-r10e-linux-x86_64.zip или android-ndk-r10e-linux-x86.bin. И запускаем команду, которая установит кросскомпилятор нужного типа для выполнения:
~/Projects/android-ndk/android-ndk-r10e/build/tools/make-standalone-toolchain.sh \
--toolchain=arm-linux-androideabi-4.8 --platform=android-19 \
--install-dir=/opt/android_toolchain
Установка и использование независимого от IDE тулчейна новых версий невозможна. Поэтому мы используем старые версии.
Кроме того, наше головное устройство навигации имеет тачпанель, которая вместе с SVGA экраном поддерживается только олдолдстабле версией GNU/Linux Debian Wheezy на платформе Olimex OLinuXino A20.
По этим причинам OpenCPN выбрана версии 4.0, так как компилятор как раз соответствует старой версии Debian Linux. И именно в это время была написана поддержка Android для OpenCPN.
Qt5 – это известный коммерческий ферймворк, который был “всегда”. То есть существовал до 2004 года. До года секретного начала проекта Android в Америке. И сейчас мы возвращаемся к истокам. В нашем приложении будет микс Qt5 и wxWidget. Чисто гипотетически NDK Android позволяет написать свою операционную систему. Например, Tizen. Но мы этого делать не будем. Тем более уже на этом шаге мы попадаем в зависимость от Qt5, что уже исключает радужные перспективы такой новой ОС. Так как появляется зависимость от сторонней группы разработчиков, которая обычно является фатальной. IMHO
Старые архивы находятся тут. Нужно выбрать тот архив, который соответствует вашей системе. У автора работающего кода bdbcat прописана в настройках CMakeLists.txt директория 5.3. У меня собралось с версией Qt5.3.1, но пришлось в исходниках Qt в заголовочных файлах в подкаталоге QtWidgets поменять название макроса Q_ENUM на Q_ENUMS.
wget https://download.qt.io/new_archive/qt/5.2/5.2.1/qt-opensource-linux-android-x86-5.2.1.run
sudo apt-get install build-essential
sudo apt-get install libfontconfig1
sudo apt-get install mesa-common-dev
sudo apt-get install libglu1-mesa-dev -y
sudo chmod +x ~/Downloads/qt-opensource-linux-x86-5.2.1.run
sudo bash ~/Downloads/qt-opensource-linux-x86-5.2.1.run
Cледуем установкам по умолчанию в инсталляторе Qt. В результате получаем в меню Приложений новое приложение Qt Creator (Opensource). По умолчанию он ставится в папку /opt/Qt5.2.1. Эту папку я использовал для версии без андроида. А нужную версию поставил в папку /opt/Qt.
По ссылке из начала абзаца можно найти информацию как вручную создать запускающий файл Qt-Creator.desktop в папке .local/share/applications. Часто в Linux библиотеках интегрирование между приложениями осуществляется через вызов этих файлов. Так же наиболее легкие и мобильные оконные менеджеры под Linux используют эти файлы для связывания приложения с расширением и автоматического вызова нужного приложения из wxWidget.
Это фреймворк, который отрисовывает кнопки и окна, интегрирует принтеры и другие периферийные устройства. Достаточно быстрый, чтоб работать на очень слабых устройствах, подобных Olimex OLinuXino A20.
cd ~/Projects
mkdir wxqt
cd wxqt
sudo apt-get install git -y
git clone https://github.com/bdbcat/wxWidgets.git
cd ~/Projects/wxqt/wxWidgets
git submodule update --init src/zlib
git submodule update --init src/png
git submodule update --init src/jpeg
git submodule update --init src/expat
git submodule update --init 3rdparty/catch
Компиляция с использованием сценария из Qt:
mkdir build_android
cd build_android
export PKG_CONFIG_PATH=/opt/Qt5.2.1/5.2.1/android_armv7/lib/pkgconfig
export CPPFLAGS=-D__ANDROID__
export PATH=/opt/android_toolchain/bin:$PATH
export CC=arm-linux-androideabi-gcc
export CXX=arm-linux-androideabi-g++
export QT5_CUSTOM_DIR=/opt/Qt5.2.1/5.2.1/android_armv7/
../configure --with-qt --build=x86_64-unknown-linux-gnu \
--host=arm-linux-androideabi --enable-compat28 --disable-shared \
--disable-arttango --enable-image --disable-dragimage \
--disable-sockets --with-libtiff=no --without-opengl \
--disable-baseevtloop --disable-xrc --disable-cmdline \
--disable-miniframe --disable-mdi --enable-debug --disable-stc \
--disable-ribbon --disable-propgrid --disable-timepick \
--disable-datepick --disable-xlocale --disable-intl
Перед компиляцией нужно исправить несколько проблем.
Так в файлах
нужно добавить #include <wx/scopedptr.h>.
В файле include/wx/evtloop.h в 19 строке добавить условие defined( _ _ANDROID_ _) чтоб определялась переменная wxUSE_EVENTLOOP_SOURCE в 1 для нашей директивы при конфигурации связанной с операционной системой _ _ANDROID_ _ .
В файле src/qt/evtloop.cpp в 254 строке добавить в условие || !wxUSE_EVENTLOOP_SOURCE. Этот блок кода был написан в 2003 году нашим соотечественником, который работал для поддержки wx в Виндоус и вызывает метод из проприетарной dll для Windows. То есть это просто устаревшее наследие и надо ещё будет посмотреть как базовый класс этого приложения будет работать с консолью и общим циклом приложений в Android.
Или даже проще закомментировать кусок кода связанный с Виндоус, потому что строкой выше находится точно такой же кусок кода, но уже через класс реализованный в wx без опоры на сторонние dll.
make
Достаём исходный код из репозитория и переключаемся на ветку исходников wxqt. Попутно убираем на запас новый плагин, в котором один файл по какой-то причине не закоммичен. Этот плагин нас пока не интересует, поэтому отложим его в tmp каталог.
sudo apt-get install cmake
sudo apt-get install gettext
cd ~/Projects
git clone https://github.com/OpenCPN/OpenCPN
mkdir tmp
cd OpenCPN
mv ./plugins/chartdldr_pi ../tmp
git checkout wxqt
Пприводим в соответствие с нашими каталогами файл ~/Projects/OpenCPN/buildandroid/build_android.cmake
#Toolchain and options definition file for OPenCPN Android build
# Locations of the cross-compiler tools
# this one is important
SET(CMAKE_SYSTEM_NAME Generic)
#this one not so much
SET(CMAKE_SYSTEM_VERSION 1)
# specify the cross compiler
SET(CMAKE_C_COMPILER /opt/android_toolchain/bin/arm-linux-androideabi-gcc)
SET(CMAKE_CXX_COMPILER /opt/android_toolchain/bin/arm-linux-androideabi-g++)
# Location of the generic wxWidgets base
SET(wxQt_Base /home/<ваш_юзернейм>/Projects/wxqt/wxWidgets)
#Location of the specific wxWidgets build (for Qt_Androidd)
SET(wxQt_Build build_android)
#Location of the root of the Qt installation
SET(Qt_Base /opt/Qt5.2.1)
В файле ~/Projects/OpenCPN/src/s57chart.cpp, который отвечает за отрисовку карт в формате CMAP (CM93) в строке 7056 используется вызов сортировки через функцию CMPFUNC, определенную через шаблоны. Компилятор для Андроида спотыкается на этой строчке. Я её просто закомментировал до момента, когда мне потребуется посмотреть на Андроиде отсортированные Маяки.
Аналогично комментируем строчку 1481 в файле routemanagerdialog.cpp.
Так как параметр CMAKE_TOOLCHAIN_FILE на моей машине не всегда корректно интерпретируется кросс компилятором, то мы прямо разместим пару мягких ссылок (ярлыков) на необходимые заголовочные файлы Qt в директории include в wxqt.
ln -s /opt/Qt5.2.1/5.2.1/android_armv7/include/QtGui /home/<ваш_пользователь>/Projecs/wxqt/wxWidgets/include/QtGui
ln -s /opt/Qt5.2.1/5.2.1/android_armv7/include/QtCore /home/<ваш_пользователь>/Projecs/wxqt/wxWidgets/include/QtCore
И компилируем статические библиотеки:
cd ~/Projects/OpenCPN
mkdir build_android
cd build_android
cmake -D_wx_selected_config=androideabi-qt -DCMAKE_TOOLCHAIN_FILE=../buildandroid/build_android.cmake ..
make
Это почти детективная история в стиле Google. В Реадми файле Андроид проекта OpenCPN указано, что нужна эта библиотека. Написана она одним человеком с именем Стив, но все репозитории удалены. И прямых ссылок Гугл не выдаёт. Но по gist.github.com удалось найти пару человек которые касались этой библиотеки и скрипта, который делает то же самое что написано в этой статье. Хорошо что сохранился форк репозитория создателя этого скрипта, где есть исходники этой библиотеки.
Она состоит из двух частей java и С. Си код просто даёт доступ к временной директории, а Java код позволяет оперативно переносить в заданную директорию необходимые данные. Такие, как значки для карты, иконки и стили для размещения иконок. Все эти перечисленные ресурсы изначально запаковываются в APK файл нашего приложения.
Так же сохранился другой gist-отчёт для одного пользователя из университета в городе Манила. И репозиторий этого проекта. Google возможно намеренно не показывает ссылки связанные с возможной уязвимостью андроид устройств, либо со старыми версиями библиотек.
Так же есть исходники этой библиотеки в ветке android основного репозитария. Эта ветка менялась 2 года назад и является более свежей, поэтому попробуем эту ветку позже.
Нам нужно скопировать этот каталог в аналогичное место нашей ветки. Выполнить команду ndk-build и расположить построенную библиотеку в каталоге ~/Projects/OpenCPN/buildandroid/. Выбор каталога связан с дефолтными настройками в файле ~/Projects/OpenCPN/buildandroid/opencpn.pro
mv ~/Projects/mitchd/OpenCPN/buildandroid/assetbridge ~/Projects/OpenCPN/buildandroid
cd ~/Projects/OpenCPN/buildandroid/assetbridge/
export PATH=/opt/android_toolchain/bin:$PATH
export CC=arm-linux-androideabi-gcc
export CXX=arm-linux-androideabi-g++
export NDK_PROJECT_PATH=/home/<ваш_пользователь>/Projects/OpenCPN/buildandroid/assetbridge/
/home/<ваш_пользователь>/Projects/android-ndk/android-ndk-r10e/ndk-build
cp ./libs/armeabi/libassetbridge.so ..
Эта библиотека даёт возможность C++ коду забирать файлы упакованные в APK (иконки, символы, стили для иконок) из директории на Android устройстве /data/data/org.opencpn.opencpn/cache/.
Прежде всего надо отредактировать файл /home/<ваш_юзернейм>/Projects/OpenCPN/buildandroid/opencpn.pro. Следующие строчки требуют изменения:
wxQt_Base=/home/<ваш_юзернейм>/Projects/wxqt/wxWidgets
wxQt_Build=build_android
OCPN_Base=/home/<ваш_пользователь>/Projects/OpenCPN/
OCPN_Build=build_android
Вот эту дополнительную строчку оставим на последующие эксперименты. Дело в том что например на старом имидже Debian от Olimex A20 с чипом Allwiner OpenGL не работает. Таковы издержки того что эта прекрасная компания (точнее директор компании Цветан Узанов из Болгарии город Пловдив) непосредственно не нанимала программистов, а только поддерживала свободных разработчиков скидками и эвентами, а также иногда приглашала в ресторан, как своих друзей.
Что так же объясняется тем что нанять хорошего разработчика в Пловдиве, выдерживая конкуренцию по зарплате с Американской компанией по безопасности практически не возможно.
LIBS += $${OCPN_Base}/$${OCPN_Build}/lib/libGLU.a
Готовимся собрать динамическую библиотеку и выполняем следующие команды:
cd ~/Projects/OpenCPN/build_android
export PATH=/opt/android_toolchain/bin:$PATH
export ANDROID_NDK_ROOT=/home/<ваш_пользователь>/Projects/android-ndk/android-ndk-r10/
export ANDROID_SDK_ROOT=/home/<ваш_пользователь>/android-sdk-linux
/opt/Qt5.2.1/5.2.1/android_armv7/bin/qmake -makefile ../buildandroid/opencpn.pro -o Makefile.android -r -spec android-g++ CONFIG+=debug
В результате работы qmake будут сгенерированы два файла в каталоге ~/Projects/OpenCPN/build_android
Для того чтоб следующий шаг был успешен. Нужно до компиляции wxWidget откатиться на предыдущую ветку библиотеки libpng и кое-что подсократить в старой версии OpenCPN. Сейчас точно не указываю какие изменения были сделаны, так как они просто связаны с комментированием того что не компилировалось без разбирательства как подружить части между собой.
cd ~/Projects/wxqt/wxWidget/src/png
git checkout libpng16
Далее скопировать 3 файла необходимых из старой весии.
В основном они связаны с переименованием функций
и исправление одного бага свзяанного
с Neon https://forums.wxwidgets.org/viewtopic.php?t=42087
Мы получим libopencpn.so в текущем каталоге размером около 74 мегабайт.
Переходим к финальным командам, ради которхых всё и затевалось.
cd ~/Projects/OpenCPN/build_android
make -f Makefile.android
make -f Makefile.android install INSTALL_ROOT=./apk_build
/opt/Qt5.2.1/5.2.1/android_armv7/bin/androiddeployqt --input ./android-libopencpn.so-deployment-settings.json --output ./apk_build --android-platform android-19 --deployment bundled
Получаем файл ~/Projects/OpenCPN/build_android/apk_build/bin/QtApp-debug.apk
Будем использовать командную строку и adb.
cd ~/Projects/OpenCPN/build_android/apk_build/bin
~/android-sdk-linux/platform-tools/adb kill-server
~/android-sdk-linux/platform-tools/adb start-server
~/android-sdk-linux/platform-tools/adb device
~/android-sdk-linux/platform-tools/adb uninstall org.opencpn.opencpn
~/android-sdk-linux/platform-tools/adb -s <id вашего Adroid устройства> install ./QtApp-debug.apk
В дальнейшем надо попытаться подобрать лучшие (максимально новые) версии wxWidget и OpenCPN. Но максимально совместимые с нашим кодом на основе OpenCPN 4.0
Несколько наиболее важных частей – Командная строка, libpng, wxSound были в стадии обновления и несколько лет эту часть кода в этих версиях никто не менял. Поэтому возможно придётся сделать промежуточный патчь для OpenCPN нашей версии, но который совместим с максимально новым wxWidget и Qt именно под Android.
Так как проект OpenCPN это по сути 4 различные версии кода под основныне операционные системы. Они отделены друг от друга директивами #define и #if #else #endif. Одна из которых Android.
В инструкции написанной автором, другой пользователь GitHub (возможно физически это тот же человек), кто продолжил работу над кодом для Android обрезал часть связанную с кодами.
Во первых эта процедура устарела для новых приложений под Play Store, а во вторых она содержит часть индивидуальных ключей автора. Но я решил привести ссылку на неё. Возможно кто-то решит повторить эту часть, либо подскажет лучший мануал по этой теме, актуальный на сегодняшний день.
The further notes use links to the textbook Physics, Pearson Education Canada 2009
Chemistry Zumdahl, 7 ed. Houghton Mifflin Company Boston New York
Алхимия как род науки появилась до Химии. При дворах богатых вельмож иногда по приглашению Алхимики организовывали свои лаборатории.
Современная Химия изучает процессы круговорота химических элементов в природе. Хороший пример – из семени произрастает растение. Растение является фабрикой берущей из почвы воду и из воздуха углекислый газ и производящей белки, жиры, крахмал, сахар, витамины.
Понятие структуры и иерархии элементов, которое использовали Алхимики, есть и в современной химии. В молекуле ДНК, которую изучает биологическая химия 4 уровня представления структур.
На каждом из уровней молекула может подвергаться воздействию путем изменения физических параметров. Например при нагревание белок из яйца меняет свой цвет и становиться твердым, а при взбивании с сахаром – так же меняются физические свойства. Если мы поместим в печку взбитый с сахаром белок то получим хрупкое печенье. Изначально в белке нет большого содержания сахара, но человек может добавить сахар добытый благодаря переработке сахарного тростника.
Часть химических реакций протекает гораздо лучше при наличие катализаторов (специальных химических соединений, ускорящих реакцию), электричества или определенных физических параметров (давление, плотность, температура, объем, наличие электрического потенциала или магнитного поля, ультразвука).
Например в известной реакции химического маятника Белоусова-Жаботинского (автоколебательная реакция ферриин ↔ ферроин), если заморозить раствор в определенной цветовой фазе (вязкость при этом возрастет), то химический маятник можно тормозить и ускорять магнитным полем. Такое воздействие может быть ключем к управлению биологическими химическими процессами.
Сейчас выпускается множество искусственных веществ, которые вырабатываются из нефти, газа и каменного угля. Именно из каменного угля с использованием дополнительной энергии в Моде алхимия мы можем получить искусственный Бриллиант идентичный обычному алмазу, добываемому в шахтах.
Попробуем создать Бриллиант с помощью алхимического оборудования. Для этого надо разложить химический элемент содержщий карбон (каменный уголь) на составляющие. Выбрать 8 стаков по 64 карбона и при наличии прибора Химический Синтезатор синтезировать брильянт, выложив их по кругу.
Надо разделять состояние вещества. Газообразное, жидкое и твердое. Так же огонь мы относим к четвертому состоянию – плазма. Жидкие и газообразные вещества состоят из молекул. Вещества с кристаллическими решетками (например, кварц) состоят из атомов (кремния, связанные химически с атомами кислорода).
Одинаковыми ли физическими свойствами обладают кристаллы сахара полученные из различных источников – из сахарного тростника, из алхимической машины или колдуньи (страница 25 химического учебника)?
Современные машины по преобразованию веществ и энергии строятся из сверхчистых веществ (вещества, в которых доля примеси – доля посторонних атомов и молекул в которых не привышает одной миллионной процента 1/1 000 000). Такая чистота вещества необходима чтобы микроявления, такие как поглощение фотона стали заметны на микроуровне. При подобной чистоте на один миллиметр материала попадает не более 100 атомов примеси.
Именно поэтому каждая алхимическая машина состоит из кристалла, блока кристалов, либо редких минералов типа обсидиана, которые можно добыть только с помощью алмазной кирки (на которую уходит 3 алмаза). Для своей работы по преобразованию веществ большинство алхимических установок требует эенргии.
Каждая алхимическая машина должна быть подключена к источнику Майнкрафт RF энергии.
На 3 странице учебника Химии можно посмотреть типичные химические уравнения для Электролизера.
Сколько молекул воды потребуется для получения одной молекулы водорода и одной молекулы кислорода?
С помощью этого устройства можно разлагать металлы в кислотной среде с помощью увеличения скорости движения йонов под действием электрического тока.
Требуется 2 кварцевых блока (8 блоков кварцевой руды), 2 слитка золота, 4 слитка железа и 1 поршень.
Алхимический растворитель веществ или химическая цинтрифуга. Позволяет разлагать любые вещества на составляющие химические чистые вещества. Для постройки этой машины нужно 2 поршня, 6 слитков железа, Magma block ( 4 Magna cream).
Magma ball состоит из Огненного порошка и Рисового шарика.
Для получения Рисового шарика требуется металлическое ведро на которое уходит 3 слитка железа, но ведро многоразовое его можно использовать для доения коров, доставки воды в кофе машину (хотя у нас есть специальная машина для выкачивания воды из водоема – можно сказать насос водный), для переноса Лавы в печь или для лавого генератора энергии.
Вот так можно приготовить Рисовое тесто для Рисового шарика.
Вещества в природе не являются чистыми. Обычно это смесь веществ. Тип смеси бывает различный например суспензия или раствор.
Хороший пример смеси это молоко, под микроскопом видно что это частички жира плавающие в жидкости (p. 490 учебника по Химии).
В смесях физические свойства отдельных веществ сохрняются. Вещества в смеси порошка можно разделить если одно вещество тонет в воде а другое плавает, или если одно притягивается магнитом а на другое вещество магнитное поле не действует (Страница 26 учебника по Химии).
Можно с помощью фильтра выделить из раствора сахар?
Физическими явлениями называют те при которых не происходит преврашение одних веществ в другие. Химический комбинатор напротив создан именно для превращения одних веществ в другие химическим (алхимическим игровым) путем.
Пример химической реакции в Майнкрафте, если мы возмем дерево и обозжем его в печи, то мы получим каменный уголь. Древесина сгорая превращаеся в воду и углекислый газ. Кроме того, в этой реакции после затрат энергии на возгарание, происходит выделение энергии достаточное для самоподдержания реакции горения до тех пор пока не закончиться уголь. Таким образом с помощью алхимических установок можно получить больше ресурсов и больше энергии, чем с помощю обычных ванильных печей или обычного крафтинга. Газ и примеси из смесей улавливаюся в алхимических установках и формируют побочные блоки вещества. Побочные вещества так же можно использовать в разнообразных химических превращениях веществ.
Химический синтезатор веществ требует для постройки 1 бриллиант (не волнуйтесь с помощью этой машины вы можете сделать столько бриллиантов на сколько у вас хватит угля и других материалов его содержащих), 1 блок Обсидиана (если вы построите этот прибор то сможете сгенирировать любое количество блоков Обсидиана если у вас будут исходные химические вещества для него), 1 Поршень и 6 слитков железа.
Обсидиа́н или вулканическое стекло — магматическая горная порода, состоящая из вулканического стекла при содержании воды не более 1 %; однородное вулканическое стекло, прошедшее через быстрое охлаждение расплавленных горных пород. Более богатые водой вулканические стёкла, вспучивающиеся при нагревании, относят к перлитам.
Обсидиан состоит из
Оксида Магния (страница 58 учебника по Химии)
Хлорида Калия
Оксида Аллюминия
Диоксида Кремния
И, возможно, других примесей, от которых зависит цвет конкретного образца обсидиана.
Алмаз (Бриллиант) состоит только из Атомов Углерода (на странице 244 учебника по Химии можно посмотреть на кристаллическую решетку алмаза).
Испаритель используется для получения молекул вещества из раствора (не путать со смесью) с помощью их кристаллизации путем испарения связывающей их жидкости раствора. Или другими словами установка осуществляющая процесс фазового перехода жидкого теплоносителя в паробразное и газообразное состояние за счет подвода внешней энергии. Если процесс происходит на поверхности – то это испарение, если во всей глубине жидкости с образованием паровых пузырьков – то это называется кипение.
Чем смесь отличается от раствора (страница 25 учебника по химии)?
Испаритель – просто каменная ванна заполненная нагреваемой водой и покрытая металлическим сосудом вогнутой формы в которой под воздействием энергии нагревателя (может быть огонь или электрическая энергия. Для микронагревания хорошо подходит лазерный нагреватель.
В результате работы испарителя на стенках металлического сосуда образуются кристаллы вырастающие из раствора налитого в сосуд.
Если перемешать сахор с водой – то мы получим раствор. Кристаллы сахара можно получить обратно из раствора сахара испарив воду. Кроме того на вкус это сладкая жидкость.
Частички сахара не возможно увидеть в растворе сахара под микроскопом. Так как сахар разделяется на молекулы, которые распределяются между молекулами воды.
Загадочность химических реакций образовли позволили Алхимикам стяжать денежные средства у покровителей и образовать культы и окультные учения наподобие Герметической философии (страница 39, 40, 46, 47 учебника Химии).
Можно ли сфотографировать атомы и молекулы (страница 2 учебника Химии)?
Изумрудная скрижаль гласит: «То, что находится внизу, аналогично тому, что находится наверху». Действительно нижний мир в Майнкрафте аналогичен верхнему. Для того чтоб попаст в нижний мир, надо построить портал из Обсидина и запустить реакцию горения с помощью огнива.
Ответы:
одинаковыми
2 молекулы воды.
Сахар выделить фильтрованием из раствора нельзя.
В растворе вещество раздроблено на отдельные молекулы.
Сфотографировать можно атомы будут выглядеть как расплывчатые пятна, а молекулы как сочетания таких пятен.
Для фотографирования нужен Микроскоп – который можно найти в нашем моде Minechem v6.
https://drive.google.com/file/d/19hfwx_TQqHoNURyEpq4Si7Vpv2VmJ7sX/view?usp=sharing
In PostgreSQL, we create the insikt database and restore the tables from the dump.
Keystore db
Also is needed restore the keystore db.
We need in our local restore it from a dump with
pg_restore -h {ip} -U postgres -W insikt1.sql -d insikt
Note: Database must be already created
systemctl enable systemd-resolved
systemctl start systemd-resolved
https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html
sudo docker run -p 9200: 9200 -p 9300: 9300 -e “discovery.type = single-node” docker.elastic.co/elasticsearch/elasticsearch∗.6.15
After this we need to go to Kibana though browser in IP_SERVER: 5601
Once Kibana is loaded go to the sidebar menu and click on Dev Tools.
You will see kibana console
Open kibana (/ app / kibana # / dev_tools / console? _G = ())
Dev Tools – Console
Insert script code
PUT demo
{
“settings”: {
“number_of_shards”: 6,
“number_of_replicas”: 1,
“analysis”: {
“analyzer”: {
“default”: {
“type”: “standard”,
“tokenizer”: “lowercase”,
“filter”: [
“asciifolding”
]
}
}
},
“index.requests.cache.enable”: true
},
“mappings”: {
“tweet”: {
“_source”: {
“enabled”: true
},
“properties”: {
“analysis”: {
“properties”: {
“threatScore”: {
“type”: “long”,
“doc_values”: true
},
“concepts”: {
“properties”: {
“concept”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“docSentiment”: {
“type”: “double”,
“index”: true,
“doc_values”: true
},
“emotions”: {
“properties”: {
“emotion”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“entities”: {
“type”: “nested”,
“properties”: {
“entity”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“entityType”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“type”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“hashtags”: {
“properties”: {
“text”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“keyIdeas”: {
“properties”: {
“keyIdea”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“screenName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“topics”: {
“type”: “nested”,
“properties”: {
“topic”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“category”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
}
}
},
“createdAt”: {
“type”: “date”,
“index”: true,
“doc_values”: true,
“format”: “dateOptionalTime”
},
“detectedLang”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“geoLocation”: {
“properties”: {
“latitude”: {
“type”: “double”,
“index”: true,
“doc_values”: true
},
“longitude”: {
“type”: “double”,
“index”: true,
“doc_values”: true
}
}
},
“coordinates”: {
“index”: true,
“type”: “geo_point”
},
“geoname”: {
“properties”: {
“countryCode”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“geonameid”: {
“type”: “integer”,
“index”: true,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“hashtagEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“text”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“id”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“idLong”: {
“type”: “long”,
“doc_values”: true
},
“mediaEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“mediaURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“mediaURLHttps”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
}
}
},
“place”: {
“properties”: {
“boundingBoxCoordinates”: {
“properties”: {
“latitude”: {
“type”: “double”,
“index”: true,
“doc_values”: true
},
“longitude”: {
“type”: “double”,
“index”: true,
“doc_values”: true
}
}
},
“boundingBoxType”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“country”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“countryCode”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“fullName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“id”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“placeType”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“retweetedStatus”: {
“properties”: {
“createdAt”: {
“type”: “date”,
“index”: true,
“doc_values”: true,
“format”: “dateOptionalTime”
},
“geoLocation”: {
“properties”: {
“latitude”: {
“type”: “double”,
“doc_values”: true
},
“longitude”: {
“type”: “double”,
“doc_values”: true
}
}
},
“hashtagEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“text”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“id”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“mediaEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“mediaURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“mediaURLHttps”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
}
}
},
“place”: {
“properties”: {
“boundingBoxCoordinates”: {
“properties”: {
“latitude”: {
“type”: “double”,
“doc_values”: true
},
“longitude”: {
“type”: “double”,
“doc_values”: true
}
}
},
“boundingBoxType”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“country”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“countryCode”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“fullName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“id”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“placeType”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“source”: {
“type”: “keyword”,
“index”: true
},
“symbolEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“text”: {
“type”: “keyword”,
“index”: true
}
}
},
“text”: {
“type”: “keyword”,
“index”: true
},
“urlEntities”: {
“properties”: {
“displayURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“end”: {
“type”: “long”,
“doc_values”: true
},
“expandedURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“user”: {
“properties”: {
“createdAt”: {
“type”: “date”,
“doc_values”: true,
“format”: “dateOptionalTime”
},
“description”: {
“type”: “keyword”,
“index”: true
},
“favouritesCount”: {
“type”: “long”,
“index”: true,
“doc_values”: true
},
“followersCount”: {
“type”: “long”,
“index”: true,
“doc_values”: true
},
“friendsCount”: {
“type”: “long”,
“index”: true,
“doc_values”: true
},
“id”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“lang”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“location”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true,
“fields”: {
“raw”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“profileImageUrl”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“screenName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“statusesCount”: {
“type”: “long”,
“index”: true,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“userMentionEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“id”: {
“type”: “long”,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true
},
“screenName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
}
}
}
}
},
“savedAt”: {
“type”: “date”,
“doc_values”: true,
“format”: “dateOptionalTime”
},
“source”: {
“type”: “keyword”,
“index”: true
},
“symbolEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“text”: {
“type”: “keyword”
}
}
},
“text”: {
“type”: “keyword”,
“index”: true
},
“unifiedText”: {
“type”: “text”,
“index”: true
},
“unifiedUrls”: {
“type”: “keyword”
},
“urlEntities”: {
“properties”: {
“displayURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“end”: {
“type”: “long”,
“doc_values”: true
},
“expandedURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“user”: {
“properties”: {
“createdAt”: {
“type”: “date”,
“doc_values”: true,
“format”: “dateOptionalTime”
},
“description”: {
“type”: “keyword”,
“index”: true
},
“favouritesCount”: {
“type”: “long”,
“doc_values”: true
},
“followersCount”: {
“type”: “long”,
“doc_values”: true
},
“friendsCount”: {
“type”: “long”,
“doc_values”: true
},
“id”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“lang”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“location”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true,
“fields”: {
“raw”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“profileImageUrl”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“screenName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“statusesCount”: {
“type”: “long”,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“urlEntity”: {
“properties”: {
“displayURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“end”: {
“type”: “long”,
“doc_values”: true
},
“expandedURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
}
}
},
“userMentionEntities”: {
“properties”: {
“end”: {
“type”: “long”
},
“id”: {
“type”: “long”
},
“name”: {
“type”: “keyword”
},
“screenName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“start”: {
“type”: “long”
}
}
}
}
}
}
}
sudo apt install python-pytest python-elasticsearch
Inside the script, I switched the ES_CONN variable to the IP address 172.18.0.2
python test_smoke.py
Check
GET demo / _search
{
“query”: {
match_all: {}
}
}
There is a file in the tmp / pyalerts directory, you need to comment out the creation of indexes (if this file is used for the first time)
mysql-tested.sql
Run the command, write to the password request: test
mysql -h 172.18.0.4 -u test -p insikt <mysql-tested.sql
Then go to the MySQL console and create 2 more tables:
mysql -h 172.18.0.4 -u test -p insikt
CREATE TABLE language (id INT auto_increment PRIMARY KEY, name text, status tinyint (1));
CREATE TABLE network_analysis (id INT auto_increment PRIMARY KEY, project_id VARCHAR (256) DEFAULT NULL, start date, end date, source varchar (1000), status tinyint (4));
sudo docker logs deploy_backend_1
sudo docker logs deploy_frontend_1
sudo docker ps
Container list
ps axf
you can see the list of converters in the process
docker restart – restart the container in memory
docker update – with updating parameters
sudo docker exec -it {container_name} bash
go inside the container
DB_PASS_POSTGRESQL = “Pbdivbknn123”
Setting up postgress on locahost
How to allow remote connections to PostgreSQL database server
register listen_addresses = ‘*’ in /etc/postgres/10/main/postgres.conf
As well as valid IP addresses from which the inputs to the BD are in the /etc/postgres/10/main/pg_hbd.conf file
In the docker-composet.yml file for accessing Kafke containers in broker service environment variables:
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT: // broker: 29092, PLAINTEXT_HOST: // broker: 9092
for external access to kafka without a container:
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT: // broker: 29092, PLAINTEXT_HOST: // localhost: 9092
System restart
cd deploy
sudo docker-compose down – cut down all containers
sudo docker stop {container name} – stop
sudo docker rm {container name} – delete
sudo docker-compose up -d – run all containers from the docker-composet.yml file
https://streamparse.readthedocs.io/en/stable/quickstart.html
The script for the automatic installation of Storm from the local Linux system via ssh is located in the ~ / tmp / supervisord / storm / storm.py directory
You also need an archive with the Storm distribution version 1.0.6 – c.tar.gz
and the demon archive for running Storm called supervisord – s.tar.gz.
In addition, there is also Oracle Java – jdk-8u192-linux-x64.tar.gz
Both archives are saved in ~ / tmp / supervisord /
To install Java, use the command:
apt install default-jdk
Then for the bundle we put Oracle Java in the / usr / lib / jvm directory next to OpenJdk, sometimes the original Java is more suitable.
To use Oracle Java, it is enough to set the environment variable in the necessary configs:
JAVA_HOME = / usr / lib / jvm / jdk1.8.0_192
Add path PATH = ”/ opt / storm / current / bin: $ PATH” to ~ / .profile
To start storm type:
sudo /etc/init.d/supervisor start
To stop Stopm, the same command as above, with the word stop.
storm version
http://ip:8080/index.html
https://github.com/technomancy/leiningen#leiningen
You do not have to create an additional bin directory in the ~ home directory.
cd ~
mkdir bin
cd ~ / bin
or
cd ~ / .local / bin
wget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
chmod + x ~ / bin / lein
or
chmod + x ~ / .local / bin
Further
lein version
sudo pip3 install streamparse
sparse quickstart wordcount
cd wordcount
In the project.clj file, you need to change the version of Storm in line 6:
: dependencies [[org.apache.storm / storm-core “1.0.6”]
Check the performance:
sparse run
To run the task on the Storm cluster, and not on the local library, use the command (IPs configuration is required in the config.json file):
sparse submit
For the first acquaintance with the capabilities of neural networks, this link is suitable:
https://www.tensorflow.org/tutorials/keras/classification?hl=en
Copy the NLP_Engine_v2.tar.gz archive to any place on the disk where there is free space.
Unzip to the same directory. This is important as the model is voluminous:
tar -zxvf NLP_Engine_v2.tar.gz -C.
The extreme point in the command means to unzip to the current directory.
Then you need to install the necessary Python packages:
sudo pip3 install nltk numpy regex stanfordnlp joblib lmdb vaderSentiment polyglot pycld2 morfessor keras tensorflow sklearn elasticsearch pandas
sudo apt install python3-mysql.connector python3-pycurl
Then go to the NLP_Engine_v2 directory and execute the command:
source env / bin / activate
Pay attention to the nlp directory. This is the python module that analyzes.
After that, you need to write the paths for the local python module nlp:
nano nlp_engine / src / bolts / tweet_analysis.py
In another file, you need to correct the environment variables, in principle, if you run through the container, you need to do this in the docker-compose.yml file.
nano nlp_engine/src/spouts/tweets.py
Then go to the nlp_engine directory and run the command:
sparse run
To run on the Storm cluster, you need to adjust the IP addresses in the config.json file and use the command:
sparse submit
To run machine analysis, go to the directory … and run srun.sh
This command can be used to deflate a site. The resulting directories can be used to test containers for parsing to isolate information.
To compile a map or site index, in principle, you can use the standard features of Storm.
If you successfully filter this content, then it can be used to train the neural network.
wget -m -l 10 -e robots = off -p -k -E –reject-regex “wp” –no-check-certificate -U = “Mozilla / 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit / 537.36 (KHTML, like Gecko) Chrome / 68.0.3440.106 Safari / 537.36 “forum.katera.ru
A trained neural network can be used to generate messages to maintain dialogue. For any questions, immediately give a link to the source on this forum.
В PostgreSQL создаём базу данных insikt и востанавливаем таблицы из дампа.
Keystore db
Also is needed restore the keystore db.
We need in our local restore it from a dump with
pg_restore -h 75.126.254.59 -U postgres -W insikt1.sql -d insikt
Note: Database must be already created
systemctl enable systemd-resolved
systemctl start systemd-resolved
https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html
sudo docker run -p 9200:9200 -p 9300:9300 -e “discovery.type=single-node” docker.elastic.co/elasticsearch/elasticsearch:5.6.15
After this we need to go to Kibana though browser in IP_SERVER:5601
Once Kibana is loaded go to the sidebar menu and click on Dev Tools.
You will see kibana console
Открываем kibana (/app/kibana#/dev_tools/console?_g=())
Dev Tools – Console
Вставляем код скрипта
PUT demo
{
“settings”: {
“number_of_shards”: 6,
“number_of_replicas”: 1,
“analysis”: {
“analyzer”: {
“default”: {
“type”: “standard”,
“tokenizer”: “lowercase”,
“filter”: [
“asciifolding”
]
}
}
},
“index.requests.cache.enable”: true
},
“mappings”: {
“tweet”: {
“_source”: {
“enabled”: true
},
“properties”: {
“analysis”: {
“properties”: {
“threatScore”: {
“type”: “long”,
“doc_values”: true
},
“concepts”: {
“properties”: {
“concept”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“docSentiment”: {
“type”: “double”,
“index”: true,
“doc_values”: true
},
“emotions”: {
“properties”: {
“emotion”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“entities”: {
“type”: “nested”,
“properties”: {
“entity”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“entityType”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“type”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“hashtags”: {
“properties”: {
“text”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“keyIdeas”: {
“properties”: {
“keyIdea”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“screenName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“topics”: {
“type”: “nested”,
“properties”: {
“topic”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“category”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
}
}
},
“createdAt”: {
“type”: “date”,
“index”: true,
“doc_values”: true,
“format”: “dateOptionalTime”
},
“detectedLang”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“geoLocation”: {
“properties”: {
“latitude”: {
“type”: “double”,
“index”: true,
“doc_values”: true
},
“longitude”: {
“type”: “double”,
“index”: true,
“doc_values”: true
}
}
},
“coordinates”: {
“index”: true,
“type”: “geo_point”
},
“geoname”: {
“properties”: {
“countryCode”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“geonameid”: {
“type”: “integer”,
“index”: true,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“hashtagEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“text”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“id”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“idLong”: {
“type”: “long”,
“doc_values”: true
},
“mediaEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“mediaURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“mediaURLHttps”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
}
}
},
“place”: {
“properties”: {
“boundingBoxCoordinates”: {
“properties”: {
“latitude”: {
“type”: “double”,
“index”: true,
“doc_values”: true
},
“longitude”: {
“type”: “double”,
“index”: true,
“doc_values”: true
}
}
},
“boundingBoxType”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“country”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“countryCode”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“fullName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“id”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“placeType”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“retweetedStatus”: {
“properties”: {
“createdAt”: {
“type”: “date”,
“index”: true,
“doc_values”: true,
“format”: “dateOptionalTime”
},
“geoLocation”: {
“properties”: {
“latitude”: {
“type”: “double”,
“doc_values”: true
},
“longitude”: {
“type”: “double”,
“doc_values”: true
}
}
},
“hashtagEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“text”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“id”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“mediaEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“mediaURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“mediaURLHttps”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
}
}
},
“place”: {
“properties”: {
“boundingBoxCoordinates”: {
“properties”: {
“latitude”: {
“type”: “double”,
“doc_values”: true
},
“longitude”: {
“type”: “double”,
“doc_values”: true
}
}
},
“boundingBoxType”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“country”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“countryCode”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“fullName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“id”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“placeType”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“source”: {
“type”: “keyword”,
“index”: true
},
“symbolEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“text”: {
“type”: “keyword”,
“index”: true
}
}
},
“text”: {
“type”: “keyword”,
“index”: true
},
“urlEntities”: {
“properties”: {
“displayURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“end”: {
“type”: “long”,
“doc_values”: true
},
“expandedURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“user”: {
“properties”: {
“createdAt”: {
“type”: “date”,
“doc_values”: true,
“format”: “dateOptionalTime”
},
“description”: {
“type”: “keyword”,
“index”: true
},
“favouritesCount”: {
“type”: “long”,
“index”: true,
“doc_values”: true
},
“followersCount”: {
“type”: “long”,
“index”: true,
“doc_values”: true
},
“friendsCount”: {
“type”: “long”,
“index”: true,
“doc_values”: true
},
“id”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“lang”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“location”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true,
“fields”: {
“raw”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
}
}
},
“profileImageUrl”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“screenName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“statusesCount”: {
“type”: “long”,
“index”: true,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“userMentionEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“id”: {
“type”: “long”,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true
},
“screenName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
}
}
}
}
},
“savedAt”: {
“type”: “date”,
“doc_values”: true,
“format”: “dateOptionalTime”
},
“source”: {
“type”: “keyword”,
“index”: true
},
“symbolEntities”: {
“properties”: {
“end”: {
“type”: “long”,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“text”: {
“type”: “keyword”
}
}
},
“text”: {
“type”: “keyword”,
“index”: true
},
“unifiedText”: {
“type”: “text”,
“index”: true
},
“unifiedUrls”: {
“type”: “keyword”
},
“urlEntities”: {
“properties”: {
“displayURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“end”: {
“type”: “long”,
“doc_values”: true
},
“expandedURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“user”: {
“properties”: {
“createdAt”: {
“type”: “date”,
“doc_values”: true,
“format”: “dateOptionalTime”
},
“description”: {
“type”: “keyword”,
“index”: true
},
“favouritesCount”: {
“type”: “long”,
“doc_values”: true
},
“followersCount”: {
“type”: “long”,
“doc_values”: true
},
“friendsCount”: {
“type”: “long”,
“doc_values”: true
},
“id”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“lang”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“location”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“name”: {
“type”: “keyword”,
“index”: true,
“fields”: {
“raw”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
},
“profileImageUrl”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“screenName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“statusesCount”: {
“type”: “long”,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“urlEntity”: {
“properties”: {
“displayURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“end”: {
“type”: “long”,
“doc_values”: true
},
“expandedURL”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
},
“start”: {
“type”: “long”,
“doc_values”: true
},
“url”: {
“type”: “keyword”,
“index”: false,
“doc_values”: true
}
}
}
}
},
“userMentionEntities”: {
“properties”: {
“end”: {
“type”: “long”
},
“id”: {
“type”: “long”
},
“name”: {
“type”: “keyword”
},
“screenName”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“start”: {
“type”: “long”
}
}
}
}
}
}
}
sudo apt install python-pytest python-elasticsearch
Внутри скрипта переключил переменную ES_CONN на IP адресс 172.18.0.2
python test_smoke.py
Проверка
GET demo/_search
{
“query”: {
“match_all”: {}
}
}
В директории tmp/pyalerts есть фай, надо закоментить создание индексов (если этот файл используеться впервые)
mysql-tested.sql
Выполнить команду, на запрос пароля написать : test
mysql -h 172.18.0.4 -u test -p insikt < mysql-tested.sql
Затем зайти в консоль MySQL и создать еще 2 таблицы:
mysql -h 172.18.0.4 -u test -p insikt
CREATE TABLE language (id INT auto_increment PRIMARY KEY, name text, status tinyint(1));
CREATE TABLE network_analysis (id INT auto_increment PRIMARY KEY,project_id VARCHAR(256) DEFAULT NULL, start date, end date, source varchar(1000), status tinyint(4));
sudo docker logs deploy_backend_1
sudo docker logs deploy_frontend_1
sudo docker ps
Список контейнеров
ps axf
можно посмотреть список контерйнеров в процессе
docker restart – рестарт контейнера в памяти
docker update – с обновлением параметров
sudo docker exec -it {container_name} bash
заходим внутрь контейнера
DB_PASS_POSTGRESQL = “Pbdivbknn123”
Настройка postgress на locahost
https://bosnadev.com/2015/12/15/allow-remote-connections-postgresql-database-server/
прописать listen_addresses = ‘*’ в /etc/postgres/10/main/postgres.conf
А так же допустимые IP адреса с которых входм в BD в файле /etc/postgres/10/main/pg_hbd.conf
В файле docker-composet.yml для доступа к Kafke контейнеров в переменных окружения сервиса broker:
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:29092,PLAINTEXT_HOST://broker:9092
для внешнего доступа к кафке без контейнера :
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:29092,PLAINTEXT_HOST://localhost:9092
Перезапуск системы
cd deploy
sudo docker-compose down – вырубаем все контейнеры
sudo docker stop {имя контейнера} – остановить
sudo docker rm {имя контейнера} – удалить
sudo docker-compose up -d – запускаем все контейнеры из docker-composet.yml файла
https://streamparse.readthedocs.io/en/stable/quickstart.html
Скрипт для автоматической установки Storm с локальной Линукс системы через ssh находиться в каталоге ~/tmp/supervisord/storm/storm.py
Так же вам нужен архив с дистрибутивом Storm версии 1.0.6 – c.tar.gz
и архив демона для запуска Storm, который называеться supervisord – s.tar.gz.
Кроме того, там же находиться Oracle Java – jdk-8u192-linux-x64.tar.gz
Оба архива сохранены в ~/tmp/supervisord/
Для установки Java используем команду:
apt install default-jdk
Затем для комплекта положим Oracle Java в каталог /usr/lib/jvm рядом c OpenJdk, иногда оригинальный Java больше подходит.
Для использования Oracle Java достаточно задать переменную среды окружения в нужных конфигах:
JAVA_HOME=/usr/lib/jvm/jdk1.8.0_192
Добавить путь PATH=”/opt/storm/current/bin:$PATH” в файл ~/.profile
Для старта storm набрать:
sudo /etc/init.d/supervisor start
Для остановки Stopm такаяже команда как выше, со словом stop.
storm version
http://75.126.254.59:8080/index.html
https://github.com/technomancy/leiningen#leiningen
Можно не создавать дополнительный каталог bin в домашнем каталоге ~.
cd ~
mkdir bin
cd ~/bin
или
cd ~/.local/bin
wget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
chmod +x ~/bin/lein
или
chmod +x ~/.local/bin
далее
lein version
sudo pip3 install streamparse
sparse quickstart wordcount
cd wordcount
В файле project.clj надо изменить версию Storm в 6 строчке:
:dependencies [[org.apache.storm/storm-core “1.0.6”]
Проверим работоспособность:
sparse run
Для запуска задачи на кластере Storm, а не на локальной библиотеке используют команду (требуеться конфигурация IPs в файле config.json ):
sparse submit
Для первого знакомство с возможностями нейросетей подойдет вот эта ссылка:
https://www.tensorflow.org/tutorials/keras/classification?hl=ru
Скопировать архив NLP_Engine_v2.tar.gz в любое место на диске, где есть свободное место.
Разархивировать в той же директории. Это важно так как модель объёмная:
tar -zxvf NLP_Engine_v2.tar.gz -C .
Крайняя точка в команде обозначает разорхивировать в текущую директорию.
Затем надо установить необходимы Питон пакеты:
sudo pip3 install nltk numpy regex stanfordnlp joblib lmdb vaderSentiment polyglot pycld2 morfessor keras tensorflow sklearn elasticsearch pandas
sudo apt install python3-mysql.connector python3-pycurl
Затем зайти в каталог NLP_Engine_v2 и выполнит команду:
source env/bin/activate
Обратите внимание на каталог nlp. Это модуль питона который занимаеться анализом.
После этого надо прописать пути для местного питон модуля nlp:
nano nlp_engine/src/bolts/tweet_analysis.py
В другом файле надо подправить переменные среды окружения, в принципе, если запускать через контейнер, это нужно делать в docker-compose.yml файл.
nano nlp_engine/src/spouts/tweets.py
Затем перейдите в каталог nlp_engine и выполните команду:
sparse run
Для запуска на кластере Storm, надо корректировать IP адреса в файле config.json и использовать команду:
sparse submit
Для запуска машинного анализа заходим в каталог … и запускаем srun.sh
docker-compose.yml
storm: image: storm:latestvolumes:- /home/ubuntu/deploy/storm/suite:/suiteenvironment:- POSTGRES_HOST=postgresql- POSTGRES_PORT=5432 – POSTGRES_DBNAME=inviso – POSTGRES_USER=postgres – POSTGRES_PASS=demo restart: always networks: default: ipv4_address: 172.18.0.25 |
Dockerfile
FROM ubuntu
RUN mkdir -p /home/ubuntu WORKDIR /home/ubuntu RUN apt-get -y -q update && apt-get install -y wget sudo git libicu-dev python htop curl python3 python3-pip python3-pycurl #INSTALL JAVA 8 COPY jdk1.8.0_192 jdk1.8.0_192 RUN sudo mkdir -p /usr/lib/jvm RUN sudo ln -s /home/ubuntu/jdk1.8.0_192 /usr/lib/jvm/java-8-oracle #STORM COPY apache-storm-1.0.6 apache-storm-1.0.6 COPY nlp nlp COPY nlp_engine nlp_engine RUN sudo echo ‘JAVA_HOME=”/usr/lib/jvm/java-8-oracle”‘ >> /etc/environment RUN echo ‘PATH=”/home/ubuntu/apache-storm-1.0.6/bin:$PATH”‘ >> /etc/environment RUN sudo pip3 install -U git+https://github.com/aboSamoor/polyglot.git@master RUN sudo pip3 install mysql-connector kafka-python streamparse flask nltk numpy regex stanfordnlp joblib lmdb vaderSentiment pycld2 morfessor keras tensorflow sklearn elasticsearch pandas WORKDIR /home/ubuntu RUN wget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein RUN sudo chmod +x lein RUN sudo cp /home/ubuntu/lein /usr/local/bin ENV JAVA_HOME /usr/lib/jvm/java-8-oracle ENV JAVACMD /usr/lib/jvm/java-8-oracle/bin/java ENV PATH “/home/ubuntu/apache-storm-1.0.6/bin:/usr/lib/jvm/java-8-oracle/bin/:$PATH” ENV LEIN_ROOT true COPY start.sh start.sh CMD bash start.sh |
start.sh
#!/bin/bash
storm version lein version sparse quickstart wordcount sleep 50000 |
Эту команду можно применить для выкачивания сайта. Полученные директории можно использовать для тестирования контейнеров по парсингу для вычленения информации.
Для составления карты или индекса сайта, в принципе можно использовать стандартные возможности Storm.
Если удачно отфильтровать этот контент, то его можно использовать для обучения нейросетки.
wget -m -l 10 -e robots=off -p -k -E –reject-regex “wp” –no-check-certificate -U=”Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36″ forum.katera.ru
Обученную нейросетку, можно использовать для генерации сообщений для поддержания диалога. При любых вопросах сразу давать ссылку на первоисточних на этом форуме.
Categories (3) Deploy Inviso Created 12 days ago, last updated 8 days ago
Clone repository git clone https://github.com/InsiktIntelligence/insikt-deploy-entrega.git
Create Swarm Now we need to create the swarm nodes (master and slaves) and join them as a cluster Go to insikt-deploy-entrega directory and execute swarm.sh cd insikt-deploy-entrega/ bash swarm.sh
Note: Is recommended that all swarms must have 8GB of memory RAM. Actually in the file some nodes on the swarm have just 4GB because there’s not enough memory on the server which is deployed. Check result:
docker-machine ls
Expected output: Image
Swarm deployment We need to execute swarm.sh file. For this step we need: Configure aws CLI Match swarm certificates directory Check out in which directory is getting configuration source
Configure aws CLI Just execute the next command and follow the steps aws configure
Match swarm certificates directory
In the deploy.sh file, is needed that next constant can search swarm-1 cert
export DOCKER_CERT_PATH=”ABSOLUTE_PATH_TO_CERT”
Note: Normally, cert file is located on ~/.docker/machine/machines/swarm-1
Check out in which directory is getting configuration source
Currently, in the file which creates the services, the paths configuration source are harcoded.
This file is in insikt-deploy-entrega/insikt-swarm/ci/docker-staging.yml
A good example would be: configs:
frontendconfig:
file: /home/ubuntu/tmp/insikt-deploy-entrega/insikt-swarm/config/nginx/nginx.conf kibanaconfig: file: /home/ubuntu/tmp/insikt-deploy-entrega/insikt-swarm/config/kibana/kibana.yml elasticconfig: file: /home/ubuntu/tmp/insikt-deploy-entrega/insikt-swarm/config/elasticsearch/elasticsearch.yml logstashconfig: file: /home/ubuntu/tmp/insikt-deploy-entrega/insikt-swarm/config/logstash/logstash.conf
In this example, the /home/ubuntu/tmp path should be replaced for the good one.
Once all thiese prerequisites are done, we can deploy the services.
In the terminal execute:
eval $(docker-machine env swarm-1)
bash swarm.sh
If all went well, after execute it, the ending of the output in the terminal should be some thing like:
staging_elasticsearch
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
staging_database
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
Expose Swarm nodes
Using iptables
To expose the node to the outside, we need to forward the requests. This should be possible using iptables.
The file port_forward.sh in insikit-deploy-entrea/ adds the rules to iptables.
Note: Before use it, check that the variable wan_addr is your server WAN IP
How it works:
bash port_forward.sh IP_CONTAINER PORT_CONTAINER
Ex: bash port_forward.sh 192.168.99.100 9090
This command will forward the request from your_wan_ip_server:9090 to 192.168.99.100:9090 If does not work If does not work you need to check many things: iptables port forward option is enabled
Check if the option is allowed with sysctl net.ipv4.ip_forward Execute: sysctl net.ipv4.ip_forward Expected output: net.ipv4.ip_forward = 1
If is 0 you must need to execute: sysctl -w net.ipv4.ip_forward=1 printf “net.ipv4.ip_forward = 1” >> /etc/sysctl.conf
There is another firewall In Ubuntu servers must be probable that ufw is enabled. Check it with: Execute: ufw status Expected output: Status: inactive
If is active, execute ufw disable and restart the server.
Python alerts db We go to create the database for alerts in python. First we need to copy the repository git clone https://github.com/InsiktIntelligence/insikt-backend-pyalerts.git
To continue, we need to follow the next steps: Configuration values are retrieved from this config file. Application reads that config file from the path stored within environment variable INSIKT_APP_SETTINGS. If that variable is not set then relative path ../config/default.app.cfg is used. In order to provide your own values for config properties listed within default ./config/default.app.cfg file, make a copy of that file and set path to this copy as value for INSIKT_APP_SETTINGS environment variable. For example, you can create local copy of default config:
cd insikt-backend-pyalerts cp ./config/default.app.cfg ./config/be-local-dev-env.app.cfg export INSIKT_APP_SETTINGS=../config/be-local-dev-env.app.cfg
mysql -h 192.168.99.100 -u test -p insikt < mysql-tested.sql
This will instruct the Flask to read configs from your local copy of default config file. Note, your local copy will not be recognized by git, as there is a gitignore configuration to omit all copies of default config gile, except the default config itself. So, if you need to change some default configuration parameters you will need to edit ./config/default.app.cfg file and commit this changes. You also need to create a table language and network_analysis. CREATE TABLE language (id INT auto_increment PRIMARY KEY, name text, status tinyint(1)); CREATE TABLE network_analysis (id INT auto_increment PRIMARY KEY,project_id VARCHAR(256) DEFAULT NULL, start date, end date, source varchar(1000), status tinyint(4));
Keystore db Also is needed restore the keystore db. We need in our local restore it from a dump with
pg_restore -h 95.216.97.242 -U postgres -W insikt1.sql -d insikt
Note: Database must be already created
Create Elasticsearch demo index We need to expose Kibana with port_foward.sh file bash port_foward.sh 192.168.99.100 5601
After this we need to go to Kibana though browser in IP_SERVER:5601 Once Kibana is loaded go to the sidebar menu and click on Dev Tools. You will see kibana console Image
You need to copy this code to create the demo index.
PUT demo {
“settings”: { “number_of_shards”: 6, “number_of_replicas”: 1, “analysis”: { “analyzer”: { “default”: { “type”: “standard”, “tokenizer”: “lowercase”, “filter”: [ “asciifolding” ] } } }, “index.requests.cache.enable”: true }, “mappings”: { “tweet”: { “_source”: { “enabled”: true },
“properties”: { “analysis”: { “properties”: { “threatScore”: { “type”: “long”, “doc_values”: true }, “concepts”: { “properties”: { “concept”: { “type”: “keyword”, “index”: true, “doc_values”: true } } }, “docSentiment”: { “type”: “double”, “index”: true, “doc_values”: true },
“emotions”: { “properties”: { “emotion”: { “type”: “keyword”, “index”: true, “doc_values”: true } } }, “entities”: { “type”: “nested”, “properties”: { “entity”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “entityType”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “type”: { “type”: “keyword”, “index”: true, “doc_values”: true }
} }, “hashtags”: { “properties”: { “text”: { “type”: “keyword”, “index”: true, “doc_values”: true } } }, “keyIdeas”: { “properties”: { “keyIdea”: { “type”: “keyword”, “index”: true, “doc_values”: true } } },
“screenName”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “topics”: { “type”: “nested”, “properties”: { “topic”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “category”: { “type”: “keyword”, “index”: true, “doc_values”: true } } } } },
“createdAt”: { “type”: “date”, “index”: true, “doc_values”: true, “format”: “dateOptionalTime” }, “detectedLang”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “geoLocation”: { “properties”: { “latitude”: { “type”: “double”, “index”: true, “doc_values”: true }, “longitude”: { “type”: “double”, “index”: true, “doc_values”: true } } }, “coordinates”: {
“index”: true, “type”: “geo_point” }, “geoname”: { “properties”: { “countryCode”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “geonameid”: {
“type”: “integer”, “index”: true, “doc_values”: true }, “name”: {
“type”: “keyword”, “index”: true, “doc_values”: true } } },
“hashtagEntities”: { “properties”: { “end”: { “type”: “long”, “doc_values”: true }, “start”: { “type”: “long”, “doc_values”: true }, “text”: { “type”: “keyword”, “index”: false, “doc_values”: true } } },
“id”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “idLong”: { “type”: “long”, “doc_values”: true }, “mediaEntities”: { “properties”: { “end”: { “type”: “long”, “doc_values”: true }, “mediaURL”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “mediaURLHttps”: { “type”: “keyword”, “index”: false, “doc_values”: true },
“start”: { “type”: “long”, “doc_values”: true } } }, “place”: { “properties”: { “boundingBoxCoordinates”: { “properties”: { “latitude”: { “type”: “double”, “index”: true, “doc_values”: true }, “longitude”: { “type”: “double”, “index”: true, “doc_values”: true } } },
“boundingBoxType”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “country”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “countryCode”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “fullName”: { “type”: “keyword”, “index”: true, “doc_values”: true },
“id”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “name”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “placeType”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “url”: { “type”: “keyword”, “index”: false, “doc_values”: true } } },
“retweetedStatus”: { “properties”: { “createdAt”: { “type”: “date”,
“index”: true, “doc_values”: true, “format”: “dateOptionalTime”
}, “geoLocation”: { “properties”: { “latitude”: {
“type”: “double”, “doc_values”: true },
“longitude”: { “type”: “double”, “doc_values”: true } } },
“hashtagEntities”: { “properties”: { “end”: { “type”: “long”, “doc_values”: true }, “start”: { “type”: “long”, “doc_values”: true }, “text”: { “type”: “keyword”, “index”: true, “doc_values”: true } } }, “id”: { “type”: “keyword”, “index”: true, “doc_values”: true },
“mediaEntities”: { “properties”: { “end”: { “type”: “long”, “doc_values”: true }, “mediaURL”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “mediaURLHttps”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “start”: { “type”: “long”, “doc_values”: true } } },
“place”: { “properties”: { “boundingBoxCoordinates”: { “properties”: { “latitude”: { “type”: “double”, “doc_values”: true }, “longitude”: { “type”: “double”, “doc_values”: true } } }, “boundingBoxType”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “country”: { “type”: “keyword”, “index”: true, “doc_values”: true },
“countryCode”: { “type”:”keyword”, “index”: true, “doc_values”: true }, “fullName”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “id”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “name”: { “type”: “keyword”, “index”: true, “doc_values”: true },
“placeType”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “url”: { “type”: “keyword”, “index”: false, “doc_values”: true } } }, “source”: { “type”: “keyword”, “index”: true }, “symbolEntities”: { “properties”: { “end”: { “type”: “long”, “doc_values”: true },
“start”: { “type”: “long”, “doc_values”: true }, “text”: { “type”: “keyword”, “index”: true } } }, “text”: { “type”: “keyword”, “index”: true }, “urlEntities”: { “properties”: { “displayURL”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “end”: { “type”: “long”, “doc_values”: true },
“expandedURL”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “start”: { “type”: “long”, “doc_values”: true }, “url”: { “type”: “keyword”, “index”: false, “doc_values”: true } } },
“user”: { “properties”: { “createdAt”: { “type”: “date”, “doc_values”: true, “format”: “dateOptionalTime” }, “description”: { “type”: “keyword”, “index”: true }, “favouritesCount”: { “type”: “long”, “index”: true, “doc_values”: true }, “followersCount”: { “type”: “long”, “index”: true, “doc_values”: true },
“friendsCount”: { “type”: “long”, “index”: true, “doc_values”: true }, “id”: {
“type”: “keyword”,
“index”: true,
“doc_values”: true
},
“lang”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “location”: { “type”: “keyword”, “index”: true, “doc_values”: true },
“name”: { “type”: “keyword”, “index”: true, “fields”: { “raw”: { “type”: “keyword”, “index”: true, “doc_values”: true } } }, “profileImageUrl”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “screenName”: { “type”: “keyword”, “index”: true, “doc_values”: true },
“statusesCount”: { “type”: “long”, “index”: true, “doc_values”: true }, “url”: { “type”: “keyword”, “index”: false, “doc_values”: true } } }, “userMentionEntities”: { “properties”: { “end”: { “type”: “long”, “doc_values”: true }, “id”: { “type”: “long”, “doc_values”: true },
“name”: { “type”: “keyword”, “index”: true }, “screenName”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “start”: { “type”: “long”, “doc_values”: true } } } } }, “savedAt”: { “type”: “date”, “doc_values”: true, “format”: “dateOptionalTime” },
“source”: { “type”: “keyword”, “index”: true }, “symbolEntities”: { “properties”: { “end”: { “type”: “long”, “doc_values”: true }, “start”: { “type”: “long”, “doc_values”: true }, “text”: { “type”: “keyword” } } }, “text”: { “type”: “keyword”, “index”: true },
“unifiedText”: { “type”: “text”, “index”: true }, “unifiedUrls”: { “type”: “keyword” }, “urlEntities”: { “properties”: { “displayURL”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “end”: { “type”: “long”, “doc_values”: true }, “expandedURL”: { “type”: “keyword”, “index”: false, “doc_values”: true },
“start”: { “type”: “long”, “doc_values”: true }, “url”: { “type”: “keyword”, “index”: false, “doc_values”: true } } }, “user”: { “properties”: { “createdAt”: { “type”: “date”, “doc_values”: true, “format”: “dateOptionalTime” }, “description”: { “type”: “keyword”, “index”: true },
“favouritesCount”: { “type”: “long”, “doc_values”: true }, “followersCount”: { “type”: “long”, “doc_values”: true }, “friendsCount”: { “type”: “long”, “doc_values”: true }, “id”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “lang”: { “type”: “keyword”, “index”: true, “doc_values”: true },
“location”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “name”: { “type”: “keyword”, “index”: true, “fields”: { “raw”: { “type”: “keyword”, “index”: false, “doc_values”: true } } }, “profileImageUrl”: { “type”: “keyword”, “index”: false, “doc_values”: true },
“screenName”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “statusesCount”: { “type”: “long”, “doc_values”: true }, “url”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “urlEntity”: { “properties”: { “displayURL”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “end”: { “type”: “long”, “doc_values”: true },
“expandedURL”: { “type”: “keyword”, “index”: false, “doc_values”: true }, “start”: { “type”: “long”, “doc_values”: true }, “url”: { “type”: “keyword”, “index”: false, “doc_values”: true } } } } },
“userMentionEntities”: { “properties”: { “end”: { “type”: “long” }, “id”: { “type”: “long” }, “name”: { “type”: “keyword” }, “screenName”: { “type”: “keyword”, “index”: true, “doc_values”: true }, “start”: { “type”: “long” } } } } } }
}
Create a new project Once ES index is created is time to create a Inviso project.
Expose the frontend First we need to expose the Inviso frontend to login in the app.
bash port_forward.sh 192.168.99.100 443
And go to the next url: https://SERVER_IP
You will see the login screen Image Login with: User: parronator Password: 123456Aa
Once you are logged, follow the next steps to create a project Click on the button Add a new project Key project Fill the options project as you prefer, but twitter must be selected from Sources option Click on Create button
You will see a green toast pointing that project was created and you will redirect to projects dashboard with the new project created Image
Load test data
In insikt-deploy-entrega/ directory, there is a fille named test_smokees.py. You just need to execute it with:
python test_smokees.py
Note: If you get a “Magic numbers” error, you must delete the file with .pyc extension in the same directory as test_smokees.py file. You can use find . -name \*.pyc -delete Also inside test_smokees.py, delete: from insiktes import search, search2, search4, search_top, \ mysql_elk, get_id_list, get_source_list, get_top_list, notification To check if it works you just need to go to Dev Tools in Kibana and execute: GET demo/_search { “query”: { “match_all”: {} }
}
If worked, you must get results at in total of hits with at least 32 Image 0 comments
SOLID – Single responsibility, Open–closed, Leaf substitution, Interface segregation и Dependency inversion
SRP – Let’s take an example Active Oberon and take into account my classification of functions (first 4 levels).
const moduleA = {
state: {}, - FSM
mutations: {}, - switch
actions: {}, - parser
getters: {}
- repository
} const moduleB = { state: {}, mutations: {}, actions: {}, getters: {} } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } })
store.state.a // -> module state moduleA
store.state.b // -> module state moduleB
SpringBootGraphQL/Feed.java at main · Ignat99/SpringBootGraphQL (github.com)
So, Lombok + Feing
https://objectcomputing.com/resources/publications/sett/january-2010-reducing-boilerplate-code-with-project-lombok
https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html
1. Object oriented ( the suffix is added to the roots КА)
2. FSM - state machine or (ЦА)
3. Parallel computing as Zenon (ЛА) ----------------------------------------------
4. Parsing (P)
5. Registers and DMA (ИТЬ)
6. Timing diagrams as in Buran (ТИ)
7. Data storage or writing to database(ХО)
Buran ciclogram:![]()
OCP – it’s easier to consider using the example of 3 multiplication tables among Old Believers (на, же, и)
на – normal multiplication of numbers
же – three-dimensional multiplication
и – time multiplication
If we want to implement all three multiplication tables, we will inherit from the class НА through class ЖЕ to the class И.
If we want to keep the interfaces, then this will be polymorphism.
LSP – this leaf-substitution principle will require some hierarchy of functions. For example, the stacking function will be common for all cells, but if the cells intersect, then contracts will be required to obtain the final result in the case of using leaf.
ISP – so that there are not many arguments in the constructor, it is better to refactor a large class in such a way that in each interface there is an implementation of only one level of the above, then at the upper levels (starting from Registered Transfers or Brokers or Tires or SOA/SOAP).
DIP – here we are talking about the interaction of objects \ perdmet through abstract interfaces, which, as it were, provide an interaction environment at each level. In fact, the complete set of these interfaces can be put into a matrix, and then optimized based on domain analysis (combined in pairs or three at a time, under the condition of uniformity of arguments in the constructor).
The object-oriented paradigm is a concept based on the C language precompiler, which combined variables and functions (methods) into a single structure. Moreover, due to the complication of linking, memory savings were achieved. In particular, various departments have been added for the new type of code. Later, mechanisms for dynamic linking of libraries and directives to the precompiler related to allocation in memory and the work of the garbage collector were added. In order to add modular architecture, the ability to define a namespace has been added. The combination of all these additions led to the emergence of templates, especially in conjunction with the implementation of the STL library – which was borrowed from Lisp and was very convenient in the 2000s for implementing vector and matrix objects.
Based on all these innovations, design patterns emerged.
So, for example, from the global variables of the SI – sigletons turned out. Their difference from just global variables is that in the additional Boost library, references to the allocated memory areas were automatically counted, and when the reference counter was zeroed, the object was automatically deleted.
Hashes were often used for associative storage of string data with access by a string key, so they began to make registries, which, however, could be combined into trees or pools. Now brokers are already used for this, since all this must still be done asynchronously and in a thread.
In particularly severe cases of full-text fast search, they now use ElasticSearch or PostgreSQL with a tree inverse index.
After the spread of local networks, the temptation arose to run functions on one microprocessor, and execute on another remote. This is how the patern factory came into being.
But there was a problem with long names of different classes on different machines, so the builder pattern arose. It’s just a chain of different operations that we can put into a conveyor or a factory method.
Etc. – lazy initialization, injected dependency, service locator. Adapter, bridge, linker, decorator, facade, single point of entry, opportunist, proxy. Chain of Responsibility, Action, Interpreter, Iterator, Mediator, Keeper, Listener, Bulletin Board, Sideboard, State, Strategy, Specification, Catheterization, Visitor and One-Time Visitor, Hierarchical Visitor (for working with trees and subtrees – just making sense of heap sort).
It arose on the basis of the LISP language, which became possible due to the presence of a hardware implementation of the FILO call address stack instead of a queue. This was done to reduce the size of the typed code, before that they practiced the sewing code on the FIFO. Later, not only return addresses, but also variables were transferred to the stack. This is how the Fort language arose, which is still perfectly used on processors with a stack architecture. In this language, we explicitly define the depth of the substack for variables.
As you know, real programmers do not use not only the stack, but also general registers. This is a joke, in fact, such a programmer was the only one, and apparently he was a genius.
Thus, if one function changes variables in another function, confusion can arise when these functions are called repeatedly when returning values from the stack at the return point of the function. To prevent this from happening, now hypervisors are used on AMD and Intel microprocessors, which save absolutely all state registers of the microprocessor automatically.
But you can do without a hypervisor if you define a complete list of passed arguments in the function and return all of them when the function finishes executing. Thus, the function does not in any way affect the environment and does not store any states inside itself.
A further development of this direction is free grammars, but unfortunately, their full implementations in the form of a Mealy automaton are quite cumbersome, in contrast to Markov chains of a Moore automaton. Therefore, we are waiting for the quantum computer to become personal and that’s where we will expand. Joke 🙂
Java is a very good programming language that supports multiple inheritance and many other features. We have been using it for 20 years since the creation of this language at Sun Microsystems. The main feature, according to the creators, of the language was a single microcode. Such a pseudo-assembler, somewhat close to the modern assembler of ARM microprocessors. As you might have guessed, these microprocessors were extensions of the stack architecture.
More precisely, it was scaling (when simple stacked microprocessors were put in several pieces in a line and a pipeline or RISC architecture was obtained). They also had more registers and a register window, that is, small changes in the addressing logic (in the MIPS architecture). But they did not have hardware instructions for multiplication and division.
Also, the Java language has a very large machine word, which makes it possible to allocate memory at the compilation stage. Which makes garbage collection easier. In general, these systems were created for the design of larger microprocessors, since the cost of addressing errors in memory while working in such programs is very high.
Unfortunately, the creator of the language made a mistake and we got a lot of JVMs of virtual machines and even families of virtual machines. And in general Java bytecode is not portable.
Java provides a new additional package in Java 8 called java.util.stream.
It is a Pipeline that does not store objects. You can use stream to filter, collect, print, and convert from one data structure to other etc.
https://www.javatpoint.com/kafka-streams-vs-spark-streaming
To save objects for 2 weeks (approximately), you can use Kafka.
interfaces (Set, List, Queue, Deque) and classes (ArrayList, Vector, LinkedList, PriorityQueue, HashSet, LinkedHashSet, TreeSet)
https://www.javatpoint.com/collections-in-java
Two interfaces for implementing Map in java: Map and SortedMap, and three classes: HashMap, LinkedHashMap, and TreeMap.
These are functionals when arguments of the same function are passed to the input of a function. This is especially developed in Kotlin. Such implementations also resemble JS.
https://www.javatpoint.com/kotlin-higher-order-function
It’s a good language, but building its implementation for SmartTV was a chore, since the options to the compiler compiler were tricky for a number of functions.
Комментарии 20
ignat9920.01.2022 в 10:56
Традиционно гимн Си-шников.
Научно-технический рэп – Папа может в си – YouTube
AlexSelivanoff20.01.2022 в 16:12
Как начинающий пользователь яхты хочу спросить, в чем преимущество OpenCPN? В сравнении с навиониксом на планшете и стационарными картплоттерами типа всяких гарминов.
ignat9920.01.2022 в 17:18
Благодарю за вопрос.
Если бы вы посмотрели предыдущие статьи, то заметилибы что я воовсе не делаю программу навигации, я по совместительству автоматизирую производство на том что мне интересно.
Нам не нужен OpenGL. И у меня к нему в основном спортивный интерес.
Так же бы вы заметили что программа была использована на Olimex OlinuXino a20, потому что я это сделал ещё 5 лет назад и это было довольно экономное (25 евро) и производительное решение.
Сейчас меня привлекает эта система именно как пример использования wxWitgets вместе с Qt и особый фреймворк OpenCPN котороый подходит для задачь логирования и парсинга в реальном времени данных с UART (или COM портов попросому).
Короткий ответ – привлекает лицензией, скоростью, языком С, наличием плугинов и естественно полностью открытым кодом, который можно переделать например в спортивный автопилот или другие специфические задачи. Тоесть возможностью модификации кода под свои нужды.
AlexSelivanoff21.01.2022 в 14:58
Спасибо!
В целом понял, пойду другие статьи почитаю.
>> спортивный автопилот
А чем спортивные автопилоты отличаются от обычных круизёрских?
ignat9921.01.2022 в 15:07
Если предпочитаете в исходном коде то тут tactics_pi/src at master · bdbcat/tactics_pi (github.com)
Если с картинками Tactics [OpenCPN Manuals]
Если моими словами. То ветер меняется и волны меняются. А яхта в долгой гонке идёт сутками. Поэтому в каждой точке исходя из 2-х дневного прогноза можно определить несколько путей с примерно одинаковым временем. Но из за погоды, бывает важно пройти быстро или вообще не заходить в штилевую зону.
Так вот тактические дисплеи строят оптимальный теоретически предсказанный путь исходя из полученных свежих данных в режиме реального времени.
На коротких дистанциях для спортивных лодок важны только точные обновлённые карты, чтоб тупо в свежеобразовавшуюся помеху невьехать. Причем точность должна быть менее 5 метров, чтоб можно было вписаться в манёвр до помехи.
Для этого дисплеи ставят в кокпите. (Потому что пока бежишь от штурманского столика на пост, яхта может и 10 метров и даже несколько корпусов пройти при свежем ветре). Именно поэтому и возникла необходимость в Андроид устройстве, которое способно работать и с картами и с различными плугинами.
Круизёры при заходе в порт в очень свежий ветер. Когда надо обойти мели при входе, находятся практически в положении спортсменов. Надо расчитать маневр и пройти на безопасной глубине возле мели. Так как ветер часто наваливает яхту на мель.
Подробнее по ссылкам выше.
Про эпюры ещё забыл добавить. Яхты бывают разные. Некоторые лучше бакштагом идут, а некоторые под фордевинд заточены (дракары) или бейдевинд (мотосейлеры). Причём зависит и от поставленых парусов и от волнения. Все эти данные учитываются при прогнозе.
black_list_man20.01.2022 в 17:00
В свое время, будучи студентом очень сильно помучался в попытках собрать OpenCPN под андроид, и безуспешно. На одной из стадий была ошибка и я не знал как её решить. На, cruisersforum создал тему, и мне по этому поводу коротко ответили что мол версия для андроид более не бесплатная. Мне в общем то нужен был минимальный функционал (отображение карт s57, судна и ais целей) для научной лаборатории, где я тогда уже параллельно работал. При этом требовалась поддержка большого количества платформ, в том числе Android и желательно IOS. С этого момента началась моя эпопея с созданием собственного картографического движка. В качестве GUI выбор сразу пал на Qt. Сначала рендер карты осущетвлялся при помощи QPainter, затем полностью переделан под OpenGL (cовместимость с ES 2.0). Сейчас хочу и вовсе “оторвать” весь код от конкретного фреймворка (специфичные классы и методы) со всеми его лицензиями, чтобы для работы требовались лишь OpenGL контекст и ввод. Мне вообще кажется что OpenCPN довольно сильно устарел: wxWidgets с его лишь частичной кроссплатформенностью; первобытный fixed-pipeline OpenGL, чего только стоят glLineWidth и GL_LINE_STIPPLE.
ignat9920.01.2022 в 17:09
Благодарю за диалог.
В новой версии, поддержкой которой занимался человек, который удалил ключи автора из репозитария
Correct GL Vector symbol extents to allow cursor pick on entire rende… · OpenCPN/OpenCPN@b939f30 (github.com)
Он же отказывался отвечать на вопросы куда делся вот этот файл
https://github.com/bdbcat/wxWidgets/blob/master/include/wx/qt/private/wxQtGesture.h
Который тянет за тсобой wxGLCanvas для андроид.
Вообщем действительно собрать с ключём OpenGL версию OpenCPN под Android это проблема. Вот он практически отказался работать бесплатно. Идея была в том что все сами будут присылать автору деньги, но видимо она не сработала по причине что рынок очень узкий и мало людей ходят на яхте и ещё меньше используют OpenCPN.
Android version – segment violation · Issue #826 · OpenCPN/OpenCPN (github.com)
Android version – segment violation · Issue #826 · OpenCPN/OpenCPN (github.com)
If this is the most current version, I believe it should be wxWidgets 3.1.1 which is what the OS linux, windows and macos versrion 4.99 uses, otherwise if it is or Opencpn version 4.8.2 it should be wxWidgets 3.0.2 . You do not state which version you are trying to compile.
ignat9921.01.2022 в 13:15
Implement wxGestureEvent support for wxQt · wxWidgets/wxWidgets@a3d58da (github.com)
Вот тут обсуждение реализации wxQtGesture для Виндоус, тем самым человеком который убрал из Readme androidbuild информацию о том как ранее можно было зарегистрировать в Play Store приложение.
Кроме того все ветки и теги Android в официальном репозитории OpenCPN (начиная с первого Release android_v1.0.0 · OpenCPN/OpenCPN (github.com) ) строго для кода wx более позднего чем 3.0.0. Например можно попробовать использовать wxWidgets 3.0.2
Я же использовал другой репозитарий в этой статье bdbcat/wxWidgets: Cross-Platform GUI Library – Report issues here: http://trac.wxwidgets.org/ (github.com)
Основная проблема это изменение реализации wxGLCanvas. Так же подключения дополнительных возможностей вокруг шрифтов и настроек опций OpenGL.
ignat9920.01.2022 в 17:26
Qt это фреймворк кроссплатформенного софта. У него есть ГЮИ (GUI) – Qt Creatot
GUI в этом контексте это wxWidget
А рендер и фреймворк это OpenCPN (в котором уже есть конфигурация, списки объектов, принтера, модульная система драйверов сенсоров и дашборд через плагины).
Если вам нужен быстрый рендер, то почему не использовать что то типа CUDA? Или сразу Unity3D?
Вообщем вы определитесь с терминами. То что вы перешли на Qt связано с тем что все перешли с GTK+ туда после смены лицензии Qt около 2014 года?
black_list_man20.01.2022 в 19:23
Под GUI я имею в виду средство для создания кросплатформенного графического интерфейса. И в этом смылсе я противопостовляю wxWidgets – Qt. Понятно что Qt это больше чем просто GUI, но тем не менее это основная его задача – создание кросплатформенного софта с графическом интерфейсом.
Выбрал Qt в перую очредь из за большого количества поддерживаемых платформ и простоты сборки. Поменял таргет в среде(Qt Creator это все же просто среда разработки с точки зрения терминологии) c Windows на Android и вот ты уже собираешь проект под андроид или IOS. Без проблем. К тому же сам графический инфтефейс куда более кастомизируемый и визуально приятный. Особенно QML. wxWidgets в этом плане выглядит совсем уж аскетично.
CUDA же это про параллельные вычисления на картах NVIDIA а не про рендеринг, развне нет? Unity все-таки игровой движок, и скриптуется C# а не C++. Пришлось бы интегрировать С++ библиотеки (а большая часть библиотек из этой предметной области написана именно на C/C++ ). К тому же опыта работы с Unity и С# у мне не было и нет.
Меня в общем то в Qt устраивает все. Кроме лицензии пожалуй. LGPL с одной стороны позволяет использовать софт в коммерчеких целях, но там какие-то сложные моменты, типа того что нельзя линковать библиотеки статически, а IOS зарпещеат линковаться динамически, и еще много тонкостей и органичений.
По поводу быстрого рендеринга: я использую непосредственно OpenGL/ES, объединяю всю похожую геометрию в группы(batch). Все символы на карте также рисуются за 1 вызов. Линии тесселируются на CPU, а сглаживаются во фрагментном шейдере. В итоге производительность раза в 3 выше чем в OpenCPN при значительно более качественной графике. Навряд ли можно сделать быстрее, чем с помощью непосредственно графического API. https://www.youtube.com/watch?v=msDhjk1dndk
ignat9920.01.2022 в 19:37
Производительсность не может быть выше в 3 раза. Возможно у вас был кастрированный OpenCPN на сравнении.
И там и там OpenGL. Если говорить что OpenCPN медленние, то надо точно указывать со ссылкой на профаил в каких именно операциях он теряет. Может это просто свойство той платформы\железа на котором вы тестовый запуск делали.
Кроссплатформенность именно из за применения wxWidgets достигается. Причём найтивная. Потому что несколько разработчиков в различное время по сути сделали wxWidgets аналоги под основые 4 операционные системы. Кроме того, он есть на почти всех языках программирования в виде вызываемых библиотек.
Возможно в вашем проекте просто не используются сложные диалоги и формы, нет интернационализации и т.д.
Из вашего видео видно, что вы сравниваете аппаратное ускорение с симулятором софтварным. Вообщем очень жаль, что вы даже этого и не заметили.
К слову на хороших современных аппаратных ускорителях можно смотреть 3D сцену одновременно с нескольких точек зрения.
Моё мнение, что если собрать правильно OpenCPN c поддержкой ускорителя, то разница в скорости будет связана только с отрисковкой дашборда, которого у вас на экране нет. То что стоит сбоку от карты – это отдельная аппаратная область вывода.
Тут статья про OpenCPN. Давайте больше не отклонятся от заявленной темы. OpenCPN это не про отрисовку карты, а про прокладку пути, редактирование списков и подключение в одном дашборте кучи инструментов. Познакомтесь с руководством по OpenCPN.
И я понимаю вас, что очень сложно без привычки разбираться в чужом коде, что гораздо проще написать своё. Но когда написанное с нуля достигнет такого же функционала как OpenCPN оно будет уже никому не нужно, так изначально ориентировано на OpenGL, который был сделан просто для потдержки VRML, а не для отрисовки реалистичных сцен. Для которых уже используют CUDA вычисления и более современные технологии.
CUDA это не совсем чистый СИ.
А если вам нужна скорость настоящая надо смотреть в сторону современных ПЛИС (FPGA).
black_list_man20.01.2022 в 21:02
С чего Вы взяли что в OpenCPN на видео отключего ускорение OpenGL? Оно включего по умолначни, в меню-> отображение -> дополнительно-> использовать ускорение OpenGL. Сравнение вполне коррентное. OpenCPN 5.2.4 из официального сайта, я его не собирал самостоятельно. Без ускорения было бы в районе 5 FPS (я сейчас попробовал отключить). На видео видно что в некорых сценах FPS падает ниже 60, судя по плавности, счетчик почему-то не работает, хотя включен в опциях (карта GTX 1060). В моем рендере FPS почти никогда не опускатеся ниже 180 даже в самых нагруженых сценах, в среднем больше 200. Настройки парамтеров отображения карты оналогичны. Сравнивал производительность на разных устойствах. Отошение примерно такое, как я сказал.
А как функционал влияет на fps? Он есть, где-то там. Но не включен же постоянно, т.е. не влияет ни на время формирование кадра ни на отрисовку. Я не думаю что дашборд вообще может как-то сущетвенно влияеть на производительность. По сравнению с картой, сотоящей из миллиона полигонов, сотен тысяч вершин, и тысячи спрайтов, одновременно находящихся на экране это несущественно. Ровно как и наличие диалогов с формами. Как факт их наличия может оказывать влияние на производительность, особенно в части отрисовки карты? При сравнении я стараюсь создавать одинаковые условия, ни там ни там не открыти ни диалоги, ни дашборды. И кстати, сайдбар сбоку: что значит отдельная область вывода? Он отрисовывется в том же контексте, что и вся карта. QML сначала передает контекст мне, я рисую все что нужно – а потом, сверху уже рисуется весь интерфейс. Но я не думаю что он “съедает” больше 1 FPS.
Разница в производительности обосновата как минимум тем, что OpenCPN не объединяет похожую геометрию в batch. Тысячи объектов на экране = равно тысячи вызовов отрисовки. Batching – это самый очевидный способ оптимизации рендера. Использует glBegin – glEnd вместо, того чтобы рисовать геометрию из вершинного буфура (VBO). Совершенно не задействуется многопоточность при подготовке кадра. Вот она и трехкратная разница в производительности . Я в коде OpenCPN где-то на протяжении года ковырялся и вполне себе разобрался. Изначально именно на его базе делался весь функционал, для нужд лаборатории. На видео 2018 года еще осталась та самая версия на базе OCPN.
https://www.youtube.com/watch?v=SwgmZaP3HGU
ignat9921.01.2022 в 11:00
У вас отключена аппаратня OpenGL для OpenCPN. Разбирайтесь сами.
По поводу своего спама пишите свою статью.
OpenCPN это работа с базой данных, форматами карт, внешними устройствами и источниками данных. Так же связь с другими яхтами и т.д.
Прочитайте вначале мануал прежде чем тут еще раз что либо говорить.
OpenCPN Books/Manuals
black_list_man21.01.2022 в 01:37
И кстати, я до сих пор не могу понять причем тут CUDA? Точно ли ту СUDA, Вы имеет в виде, что SDK от Nvidia? CUDA – во-первых работает только на картах Nvidia, во-вторых, предназначена для выполнения параллельных вычислений общего характера и не имеет вообще никакого отношения к рендеру. Это тоже самое что вычислительный шейдер. Или OpenCL. Вычислительный шейдеры давно есть в современном OpenGL/ES, как Вы предлагаете их использовать в данной задаче? Разве можно CUDA вообще противопоставлять графическим API, типа OpenGL?
ignat9921.01.2022 в 11:01
Запишитесь, на курсы компьютерной грамотности. Задайте там вопрос про вокселы.
OpenCPN это в первую очередь не про отрисовку сцены, а про прокладку курса и про реагирования на события и данные подгружаемые в буферы в реальном времени. Читайте вначале мануал OpenCPN Books/Manuals
Ваша поделка близко к этим задачам пока не подошла и не подойдёт, если у вас в команде будет единственный программист, который вместо работы занимается троллингом.
black_list_man21.01.2022 в 11:47
Пержде чем поучать удосужтесь ответить хотя бы на один из вопросов. Я еще раз справшиваю, на каком основании Вы утверждаете что в моей версии OpenCPN отключена поддержка OpenGL? Я Вам дал развернутый ответ о том, где я взал эту версию, показал пункт меню, в котором отчетливо видно, что OpenGL включен. Его можно отключить и заметить разницу. А Вы почему-то продолжаете утверждать что это не так. Почему? В мануле, который Вы мне зачем-то даете, и который я в свое время прочитал вдоль и поперек, нет ответа ни на один из вопросов.
Что значит спам? Я оставил один единсвтенный комментарий под этой статьей, в котором рассказал своем опыте работы с OCPN и сборки под Android. Дальнейший диалог Вы развиваете сами. Сами же затронули вопрос о “быстром рендере” и производительности. И эта ветка диалога именно об этом.
Что касается грамотности, я уверен что это Вам нужно внимательно изучить хотя бы терминилогию, и понять что же из себя предсвляет CUDA и в каких отношениях она находится с графическими API. Я не уверен что вообще могу Вас понять. Намешали все вместе, карты, воксели, CUDA, OpenGL. Как это связано? Скажите честно, Вы имели опыт работы с OpenGL и в полной мере понимаете о чем идет речь?
Моя “поделка” (почему в таком унизительной тоне?) выполняет ровно те задачи, для которых создавалсь и обладает ровно тем функционалом, который от нее требуется. Почему одна должна повторять функционал OpenCPN? Это два разных софта, котоые я сравниваю лишь в части производительности рендера.
Не хотите продолжать диалог – не продолждайте более. Я лично не привык оставлять обвинения в мой адрес неотвечеными.
ignat9921.01.2022 в 12:26
Сложно говорить с технически безграмотным в области компьютерных вычислений человеком.
Вам никто ничего не обязан. Вы официально тролль и это крайнее сообщение вам.
Вам сейчас не более 29 лет и да, вы IT самозванец без опыта. Это вам мой фидбак. Хотели получить. Получите и распишитесь. Джуниором я бы вас не взял, и практикантом тоже. И стажёром. И даже учеником за доплату.
ignat9920.01.2022 в 17:50
wxWidgets/glcanvas.h at master · bdbcat/wxWidgets (github.com)
Вот этот файл, похоже, хватает ветка android OpenCPN. Как я понял этот файл цепляет Windows библиотеки. Не уверен что это правильно в контексте Android.
ignat9920.01.2022 в 18:09
universal binary for macOS · Issue #2486 · OpenCPN/OpenCPN (github.com)
Вот тут обсуждение, товарищи не могут даже отключить потдержку OpenGL, хотя ранее все хорошо работало в этом плане (в плане отключения лишнего).
ignat9924.01.2022 в 15:59
Для того чтоб OpenGL заработал в Android, нужно собрать соответствующие библиотеки под ARM.
GL/gl.h, Qt5 and arm: FTBFS (debian.org)
Ответы:
Re: GL/gl.h, Qt5 and arm: FTBFS (debian.org)
Re: GL/gl.h, Qt5 and arm: FTBFS (debian.org)
И это не столько проблема закрытых драйверов, сколько проблема закрытых Даташитов. Потому что там информация о багах внутри реализации графических ядер и их встраивания в SoC. Корпорации на момент выпуска устройства скрывают косяки в изделии, даже от большинства своих сотрудников (по крайней мере младших чем 4 ранг и работающих в другой области кода).
А косяки производителя, закрытые драйвера + особенности и тайны встроенного гипервизора создают поистине гремучую смесь. И 5 лет назад приходилось выбирать Qt5 или аппаратный OpenGL …