...

суббота, 25 сентября 2021 г.

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

Инсулинорезистентность повышает риск возникновения большого депрессивного расстройства, гласит исследование нидерландских ученых, опубликованное в издании The American Journal of Psychiatry

Под руководством Нидерландского Института депрессии и тревоги ученые изучили данные 601 пациента возрастом от 16 до 65 лет (средний возраст участников составил 41 год) без диагностированной депрессии и тревоги на момент начала долгосрочного девятилетнего исследования случаев возникновения депрессивных эпизодов.

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

Результаты исследования показали, что увеличение содержания липопротеинов высокой плотности в крови прямо пропорционально сказывалось на уровне психического здоровья исследуемых: риск возникновения большого депрессивного эпизода возрастал вплоть до 89 %. Следующим в рейтинге риска для ментальной стабильности оказался уровень глюкозы: так, повышение ее содержания в крови на в среднем на 18 мг приводило к учащению возникновения симптомов депрессии на 37 %. Меньше всего на психическом здоровье участников исследования сказывался объем талии: при увеличении в среднем на 5 см опасность обнаружить признаки депрессивного эпизода возрастала лишь на 11 %.

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

Adblock test (Why?)

Что же не так с любыми электронными голосованиями?

Данная публикация написана по мотивам поста «Что же не так с ДЭГ в Москве?». Его автор описывает, как можно выгрузить и расшифровать данные по электронному голосованию, а также приводит целый список замечаний к его текущей системе.

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

Аномалии в динамике распределения голосов

Во-первых, я последовал инструкции, выгрузил дамп с голосами по одномандатному голосованию, и сделал вот такие интерактивные визуализации по каждому округу:

Как менялось распределение голосов за три дня голосования в Ленинградском округе Москвы
Как менялось распределение голосов за три дня голосования в Ленинградском округе Москвы

Обратите внимание, что по вертикали здесь отложены проценты голосов за каждый 20-минутный период, а не абсолютное число голосов. Поэтому в ночные периоды эти проценты сильно «скачут» — просто из-за того, что голосов там мало. А вот что более интересно — это динамика доли голосов за административного кандидата. Во-первых, виден скачок в самом начале, который постепенно убывает с течением времени (то есть по какой-то причине сторонникам провластного кандидата хотелось проголосовать как можно раньше — особенно в самые первые часы первого дня голосования). Во-вторых, в третий день наблюдается ещё более заметный «горб» с 2 часов ночи до примерно 2 часов дня — с перерывом с 12 до 13. Какая естественная причина могла сподвигнуть избирателей дружно выбрать такой период для голосования за подобных кандидатов — остается лишь гадать.

На приведённых графиках можно спрятать любой из сегментов, и вот как меняются соотношения, если спрятать кандидата, занявшего первое место:

Динамика распределения голосов без учета голосов за административного кандидата
Динамика распределения голосов без учета голосов за административного кандидата

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

Суммарное соотношение голосов за кандидатов на 1-м, 2-м и т.д. местах в каждом округе Москвы
Суммарное соотношение голосов за кандидатов на 1-м, 2-м и т.д. местах в каждом округе Москвы

Добавлю, что я не первый, кто провёл этот анализ — я лишь перепроверил (и чуть иначе визуализировал) выводы, сделанные командой Анастасии Брюхановой, которая побеждала в Ленинградском округе, но (как и ряд кандидатов в других округах) проиграла из-за этих необъяснимых аномалий. Вот их видео с разбором этих проблем:

Отмечу также, что я также обнаружил на Гитхабе ещё один инструмент для выгрузки этих данных по Москве, и ещё одни графики, построенные по ним в DataLens. Можно убедиться, что они совпадают с моими наблюдениями и наблюдениями команды Брюхановой. ЦИК же, ожидаемо, никаких проблем в них не увидел.

Почему электронное голосование всегда будет хуже бумажного

Критики в сторону текущей реализации ДЭГ очень много. Напомню вкратце основные отмеченные проблемы:

  • В базе голосов присутствуют как актуальные, так и отменённые из-за переголосований бюллетени. Сейчас нет никакого публичного способа их отличить, а следовательно корректно перепроверить итоги выборов.

  • На выборах в Госдуму даже не была публично завершена расшифровка всех бюллетеней — хотя их и возможно дорасшифровать самостоятельно. Отдельно замечу, что один бюллетень (с хэшом f07ee512b57bc7d6176592ee6a4ab2526c025af2d57cd9e636c038e61b57db06) не удается расшифровать в принципе. Я пока объяснений не видел (и у меня нет гипотез), как он попал в блокчейн, но это выглядит нехорошим звоночком.

  • Итоги были подведены спустя значительное время после завершения выборов. При этом наблюдатели лишились возможности следить за процессом непосредственно в момент окончания приема голосов (19 сентября в 20:00) из-за истекшего сертификата. То есть никакого контроля за работой системы не осуществлялось, а результаты были просто представлены позднее независимо от неё.

  • Не скрывается, что за выдачу вышеупомянутых сертификатов была ответственна ФСБ. Не удивлюсь, если в целом их позиция в том, что в любой окологосударственной электронной системе, использующей криптографию, должны быть предусмотрены бэкдоры для них. Это вызывает опасения как в плане предвзятости самой службы в пользу текущей власти, так и потенциального использования бэкдоров третьими лицами.

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

  • Нет никакого способа удостовериться, что опубликованные исходные коды ДЭГ соответствуют тем, которые применяются фактически. Я не слышал, чтобы кто-то проводил её независимый аудит.

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

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

Если послушать интервью с главным «локомотивом» ДЭГ Алексеем Венедиктовым, то можно понять, что все замечания к этой системе он воспринимает как обычные багрепорты, которые просто можно пофиксить в следующей версии (и тогда у нас наступит светлое электронное будущее). Тех же, кто выступает против электронных голосований как таковых, он приравнивает к антиваксерам и прочим маргиналам, выступающим против прогресса.

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

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

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

Сравните роль наблюдателей на традиционном и электронном голосованиях. Наблюдатель на участке видит живого человека, с паспортом, который получает бюллетень, ставит в нём галочку, опускает в опечатанную урну, а затем следит за тем, как эти бюллетени подсчитывают. Что видит наблюдатель в электронном голосовании? Как в некую базу данных откуда-то прилетают некие бюллетени. Продолжая аналогии, это как если бы наблюдение велось не за всем происходящим на участке, а только за содержимым урны — мы только видим, что в неё неизвестно откуда сыпятся бюллетени (и вроде ничего не высыпается — но в текущей системе даже это неверно).

Если максимально упрощать, избиратель — это всегда объект физического мира. Чтобы взаимно однозначно перевести его в электронное представление, необходим какой-то компонент, которому мы доверяем. В Эстонии, например, государство выдает ID-карты для этой цели, а у нас — насколько я понимаю, Госуслуги передают информацию об авторизованном избирателе в ГАС Выборы. Когда мы сравниваем такие системы, нужно сравнивать и степень доверия, соответственно, этим компонентам. Но самое важное это то, что традиционное голосование не требует такого доверия к единому компоненту — процесс можно контролировать независимо извне (наблюдатель видит именно живого человека, а не заверенную кем-то цифровую подпись).

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

И, наконец, вредоносное программное обеспечение. Если бы речь шла лишь о применении КОИБов для «цифровизации» выборов, можно было бы надеяться, что их начинка не искажает подсчёт голосов (хотя это тоже требует доверия к её разработчикам, а по факту в ней уже находили ряд уязвимостей). Но сейчас для голосования применяются компьютеры самих избирателей, которые вполне могут быть подвержены заражению вирусами. Компроментация конечного устройства сводит на нет всю защиту «по пути» — если, скажем, у пользователя стоит расширение, переставляющее на веб-страничке галочки местами, то никакая криптография его не спасёт. И это фальсификации, которые возможно делать не в масштабах одного участка, а в масштабах всей страны. Что характерно, заниматься этим может уже не только государство, а любые злоумышленники (привет государственной паранойе на тему иностранных вмешательств :)

Заключение

Нынешняя реализация ДЭГ — плохая. К ней зафиксировано много претензий, а в результатах — много фальсификаций. Все, кстати, обращают внимание на московскую, а шесть других округов (в которых использовалась несколько другая реализация) остаются в тени. Но проблема не столько с текущей реализацией, сколько с электронными голосованиями в принципе. В отличие от бумажных голосований, они требуют гораздо больше доверия к организаторам выборов и собственному государству, поскольку не дают даже теоретических инструментов для независимого наблюдения в той степени, в которой оно возможно в традиционных выборах.

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

Напоследок предлагаю также посмотреть вот это видео Тома Скотта с критикой электронных голосований — в первую очередь в Великобритании, но приводит те же аргументы, что привёл и я, которые распространяются на любую такую систему:

Adblock test (Why?)

Бывшие модели OnlyFans создают свои собственные сайты

Когда ресурс для взрослых OnlyFans объявил о намерении отказаться от порно на площадке, а затем отменил данное решение, многие модели начали создавать свои собственные сайты. На эти шаги их подвигли опасения остаться без стабильного дохода.

«Недавний запрет OnlyFans на контент для взрослых показал, что у нас нет гарантий занятости», — отмечают модели.

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

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

Кроме того, моделей беспокоят проблемы с оплатой. Они отмечают, что не могут работать с платежными системами Visa и PayPal.

Платформы одновременно принимают жесткие меры в отношении контента для взрослых из-за Закона о борьбе с секс-торговлей в Интернете (FOSTA) и Закона о запрете секс-торговцев (SESTA). «Хотя предполагаемой целью закона была торговля секс-услугами, он оказался невероятно неэффективным, но вместо этого к нему регулярно прибегают технологические компании при цензуре и удалении контента, которым делятся секс-работники, или даже просто пользователей, которые делятся контентом сексуального характера», — отмечает Мэрайя Грант, директор по исследованиям проекта The Sex Workers Project of the Urban Justice Center.

Несмотря на препятствия, многие секс-работники все же отказываются от централизованных платформ для обретения независимости. «Я надеюсь создать свой собственный веб-сайт с информационным рассылками по электронной почте в ближайшие несколько месяцев», — рассказала модель, работающая в секс-индустрии более восьми лет. — «Это способ обеспечить максимальную стабильность, но он действительно работает только в том случае, если у вас уже есть трафик для привлечения людей. Я хочу сделать больше контента SFW (Safe For Work) на Twitch, TikTok или YouTube, чтобы получить больше трафика».

Другая модель отмечает, что создает собственный веб-сайт, чтобы не иметь дел с платежными системами. Она планирует наладить работу с ElevatedX или VXPages, чтобы получить собственную систему обработки платежей. Кроме того, модель собирается наладить рассылки по почте, чтобы оставаться на связи с фанатами даже в случае блокировки ее сайта. По ее мнению, секс-работники будут все чаще принимать оплату в виде криптовалют.

Несмотря на общее недоверие к крупным платформам, большинство секс-работников пока не уходят оттуда. Некоторые после истории с OnlyFans перешли к конкурентам, таким как Fansly и ePlay.

В мае ВВС опубликовала расследование о присутствии большого количества детского порно на платформе OnlyFans. Кроме того, там нашли профили с пропавшими без вести детьми, принимавшими участие в съемке откровенных материалов.

OnlyFans объявила 19 августа, что с 1 октября запретит своим пользователям размещать откровенно сексуальный контент. При этом фото и видео с обнаженкой обещали сохранить, если они удовлетворят новой политике компании. Однако никаких уточнений по поводу этой политики не было.

В качестве причины запрета на порно основатель и генеральный директор OnlyFans Тим Стокли называл деятельность банков. Он пояснил, что сразу три крупных банка отказались работать с компанией из-за материалов сексуального характера — Bank of New York Mellon, Metro Bank, JPMorgan Chase.

Позднее площадка отменила сбор инвестиций до того момента, пока не разрешит ситуацию с порно.

Одновременно с этим создатели сервиса сообщили, что услышали негативные отклики пользователей и приостановят запланированное на 1 октября изменение политики площадки.

Adblock test (Why?)

[Перевод] Кунг-фу стиля Linux: файловые системы пользовательского пространства теперь доступны и в Windows

Одной из приятных черт философии Unix, которую унаследовала Linux, является модульная организация файловой системы. И это, на самом деле, очень хорошо, так как в типичной установке ОС могут понадобиться различные файловые системы, вроде ext4, reiserfs, btrfs, или даже сетевые файловые системы — вроде nfs. Кроме того, в Linux существуют и виртуальные файловые системы, вроде /sys и /dev, которые помогают Linux сделать так, чтобы всё в ней выглядело бы как файл. Слабая сторона средств работы с файловыми системами в Linux заключается в том, что для создания механизмов, обеспечивающих работу файловой системы, нужно вносить изменения в ядро, или, как минимум, создавать загружаемые модули. Это, правда, не так уж и сложно, но, всё же, немного сложнее, чем разработка обычных программ. Решить эту проблему призван интерфейс FUSE (Filesystem in USErspace — файловая система в пользовательском пространстве). В частности, речь идёт о модуле файловой системы, который позволяет создавать новые файловые системы путём написания вполне обычного кода.


Мои любимые файловые системы пользовательского пространства


Существует несколько FUSE, которые способны принести тем, кто их применяет, реальную пользу. Вот некоторые из моих любимых:
  • sshfs — монтирует удалённую файловую систему, используя лишь ssh-доступ.
  • rclone — позволяет организовывать доступ ко многим удалённым файловым системам и осуществлять их монтирование.
  • tagsistant — файловая система, основанная на тегах, облегчающая работу с большим количеством файлов.
  • fuse-zip — позволяет монтировать zip-файлы в виде файловых систем.
  • gitfs — позволяет монтировать в виде файловых систем git-репозитории.

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

А как насчёт Windows?


FUSE в Linux — это весьма полезная штука. А есть ли что-то подобное в Windows? Да, нечто такое есть и в Windows. Называется оно WinFsp и выглядит как интересный механизм для работы с файловыми системами. Правда, прямой совместимости с FUSE у него нет. Но имеются слои совместимости с FUSE (один — для версии 2.8, и ещё один — для версии 3.2), которые упрощают портирование существующего FUSE-кода на WinFsp.

Это — достаточно новый проект такого рода. Но существует ещё один подобный проект — Dokan, авторы которого говорят о наличии интерфейсов к его API для FUSE. Правда, если верить бенчмаркам, выполненным в рамках проекта WinFsp, оказывается, что WinFsp отличается более высокой производительностью.

Итоги


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

Например, у вас может быть некая система для логирования данных. Вы решили, что хотите представить результаты её работы в виде файловой системы. Сделать это не так уж и сложно. Так, например, имеются некоторые структуры данных, которые нужно заполнить, причём, заполнять нужно далеко не все эти структуры. Нужно написать функции, которые будут использоваться в виде инструментов для чтения и записи данных, представляющих директории и файлы. Вот — пример, написанный на C. А вот — C++-обёртка, которая позволит создать файловую систему, написав меньше кода, чем при выборе C. В этом примере имеется всего четыре простых функции. Так что — если вам нужна собственная файловая система пользовательского пространства — вы, что для Linux, что для Windows, вполне можете создать её своими силами.

Возникала ли у вас когда-нибудь необходимость в создании собственной файловой системы?

Adblock test (Why?)

[Личный опыт] Жизнь и удаленная работа во Вьетнаме: почему работать со сдвигом на 4 часа — это хорошо

Вьетнам — одна из самых популярных стран среди туристов и удаленщиков. Сюда едут за идеальным климатом, теплым морем, низкими ценами и свежей едой. И готовятся мириться с плохим интернетом, опасным дорожным движением, отсутствием культурных развлечений и другими минусами «неразвитых» стран.

Чтобы разобраться, как живется во Вьетнаме на самом деле, мы пообщались аналитиком, которая с 2013 года живет здесь с супругом и не собирается никуда уезжать. Она расскажет, какие тут на самом деле цены, как обстоят дела с развлечениями и медициной и в чем главное отличие Вьетнама от других стран Юго-Восточной Азии.

Как мы оказались во Вьетнаме и почему вернулись сюда из других стран

Привет, меня зовут Лана, и мы с мужем приехали во Вьетнам в 2013 году. Сначала хотели просто пожить здесь и отправиться путешествовать дальше — оба IT-инженеры, работаем удаленно и не планировали нигде оставаться надолго.

Пожив во Вьетнаме, мы попытались отсюда уехать: в Камбоджу, на Филиппины, в другие теплые страны. Вроде бы похожий климат, цены, уровень жизни. Но во всех других местах нам не хватало именно вьетнамцев.

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

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

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

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

Чем Вунгтау отличается от других вьетнамских городов

Во Вьетнаме мы жили на Фукуоке, в Далате, в Дананге и в Хошимине. Но выбрали в итоге Вунгтау — первый город, с которого и началось наше знакомство с Вьетнамом. У него есть несколько интересных особенностей.

Хошимин под боком. Рядом крупнейший город страны с международным аэропортом. Можно съездить развлечься, удобно летать в другие страны. 

Туристический город для местных. Вунгтау практически неизвестен российским туристам. В основном тут любят отдыхать местные, либо туристы из Китая или Кореи. У многих жителей Хошимина тут «дачи», а некоторые просто приезжают на пляжи и к морю на выходные. Лично я считаю, что море в Вунгтау некупабельное — в городе 8 портов и много рыбацких судов. Но можно забраться подальше от портов или вообще уехать в соседний городок Лонгхаи и искупаться там.

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

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

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

Много других экспатов. Вунгтау город современный и богатый, поэтому тут в целом много иностранцев, в том числе живущих постоянно. Есть целая улица, где живут пенсионеры из США и Австралии — они сюда приезжают пожить в теплом климате. Много преподавателей английского языка, спрос на них велик по всей стране.

В общем, в Вунгтау экспату жить удобно.

Что во Вьетнаме с ценами: не дешево, но и не слишком дорого

Если послушать тревел-блогеров, создается впечатление, что Вьетнам — очень дешевая страна. Здесь действительно легко снять плохое жилье почти за копейки и питаться рисом с овощами. Но такое можно сказать про любую страну.

На самом деле уровень цен во Вьетнаме почти такой же, как в России. Снять неплохую квартиру с видом на море в Вунгтау стоит в районе 30,000 в пересчете на рубли. В Хошимине в два раза дороже. 

Продукты тоже стоят примерно как у нас: азиатские макароны по 100 ₽ за пачку, свинина 400–500 ₽ за килограмм вырезки. Рис стоит около 300 ₽ за 5 кг — и это хороший азиатский рис, гораздо вкуснее российского. 

Нетипичные для Вьетнама блюда чуть дороже. Наша картошка стоит около 100 ₽ за кг, молоко в районе 150 ₽, оно тоже импортное, привычные европейские макароны от 150 ₽ за пачку. Зато местные овощи и фрукты в среднем дешевле, чем аналогичные в России.

Цены на транспорт, развлечение, медицину тоже почти как в России. То есть Вьетнам, конечно, дешевле Европы или США, но точно не самая дешевая страна на свете. Если планируешь жить на приличном уровне, а не сидеть в лачуге и есть только рис с бамбуком.

Языковой барьер: он есть, но не слишком мешает

В Вунгтау многие вьетнамцы понимают английский, а некоторые и русский. Еще 8 лет назад английский не был так популярен, а теперь практически все стараются его учить. По моим ощущениям ситуация лучше, чем в России — у нас далеко не любой кассир или полицейский может объясниться по-английски, а в Вунгтау с этим проблем почти нет.

Кроме того, вьетнамцы отлично пользуются гугл-переводчиком, да и язык жестов всегда выручает.

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

Кстати, если прийти на рынок и спросить «Сколько стоит килограмм манго?» на вьетнамском, цена будет одна. Даже если выглядишь как европеец. А если спросить на английском или русском — назовут цену гораздо выше. Так что лучше закупаться в супермаркетах — там цены фиксированные и для новичка все выйдет дешевле, чем на рынке.

Дорожное движение: никуда без мотобайка, а на дорогах довольно безопасно

Чтобы полноценно жить во Вьетнаме, нужно иметь мотобайк и уметь его водить. Без байка будет сильно сложнее. Городского транспорта как такового в Вунгтау нет. Есть какой-то автобус, но как он ездит и куда — непонятно, и я не знаю никого, кто бы на нем катался. Междугороднее сообщение развито отлично, а вот внутри города без мотоцикла делать нечего. Сейчас есть дешевое граб-такси на мотоциклах и скутерах, но это не то — его обычно вызывают на небольшие расстояния, и просто так на нем не покатаешься.

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

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

Дорожное движение со стороны тут кажется полным хаосом, особенно в Хошимине. Здесь ездят по встречке, игнорируют двойную сплошную — с точки зрения европейцев не соблюдают правила вообще. Но когда ты в это движение входишь, ты вдруг обнаруживаешь, что все логично и удобно. Есть неписаные правила, а участники движения неагрессивные и всегда оставят за тобой право проехать первым. Есть даже вьетнамская поговорка: «По дороге, которую ты уступил другому, легче идти».

Еще в основной массе ездят не быстро. Ограничение по городу 30 км/ч, примерно так и ездят. За городом 60 км/ч, там отдельная дорога для мотобайков и отдельная для машин. 

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

Плюсы жизни во Вьетнаме: погода, еда и кофе

Никакого снега и сильных холодов. Я не люблю снег во всех проявлениях и то, какие ограничения он накладывает на жизнь. От набора одежды до невозможности завтракать на балконе. Во Вьетнаме тепло, снега нет, и отношение к жизни другое. Не боишься простыть, промочив ноги под дождем. Не переживаешь из-за гололеда. Не нужно постоянно кутаться в сто одежек. Это очень расслабляет.

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

Если сравнивать с другими странами Юго-Восточной Азии, то во Вьетнаме ситуация гораздо лучше. На Филиппинах, например, кокос может висеть на пальме — а в магазине, который прямо под этой пальмой, продаваться только консервированный. Плюс там все любят курицу-гриль и прочий фастфуд. А во Вьетнаме вся еда очень здоровая: рис, мясо, овощи и фрукты, всегда много зелени.

Овощи здесь очень разнообразные. Например, те же кабачки, но много видов. Или зелень — свежая, упругая, ее часто готовят как отдельное блюдо, а не только добавляют в салаты. Несколько видов капусты. А вот помидоры и огурцы тут так себе. Западная картошка хорошая, но дорогая. Местная картошка очень сладкая, к ней нужно привыкнуть.

Фрукты типичные тропические: манго, маракуйя, дуриан и прочие. Все гораздо вкуснее, чем то, что удается найти в России. Арбузов и бананов здесь несколько сортов. Кстати, бананы бывают с косточками.

А вот экстремальной еды тут не бывает. Иногда у блогеров можно найти, что в Азии едят тараканов или скорпионов. На самом деле, это какая-нибудь одна глухая деревня, где такое практикуют, но обычные люди едят обычную еду.

Конечно, есть и непривычные для нас вещи, вроде маринованных медуз или шелковых червячков. Но и российская еда для иностранцев непривычная. Например, сметану тут почти не продают, стоит она дорого, и для местных она пахнет грязными носками =)

Рай для аллергиков. Я аллергик, и здесь у моря мне живется гораздо лучше: чище и приятнее воздух, нет пыли, меньше раздражителей. И вообще на балконе, который выходит к морю, получается бесплатный спа-салон.

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

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

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

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

Справа — тот самый дорогой чай. Который вкусный, а не из пакетов
Справа — тот самый дорогой чай. Который вкусный, а не из пакетов

Хороший интернет. В нормальном жилье, в квартирах в современных домах, последняя миля хорошая. Работать удаленно вполне комфортно.

Минусы жизни во Вьетнаме: дорогое электричество, солнце и высокая плотность населения

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

Расход электричества кондиционера зависит от разницы температур. Если на улице +30 °С, а дома ты выставил +18 °С, то за месяц можешь отдать больше 200 долларов только за кондиционер. Многие этого не знают и удивляются. Советую ставить 25-27 °С на кондиционере.

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

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

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

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

Немного об удаленной работе: никакого «ноутбука на пляже» и сдвинутый график

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

Другой момент — часовые пояса. Мы с мужем работаем с Москвой, то есть сдвиг на 4 часа. Но я в этом вижу прелесть. Каждый день просыпаешься без будильника, что-то делаешь для себя, гуляешь, пьешь кофе, плаваешь в бассейне. А потом расслабленной и отдохнувшей в час дня начинаешь работать. Для меня это серьезный плюс — мне проще начать днем и закончить в 11 вечера. Еще я договариваюсь на двухчасовой «обеденный» перерыв, чтобы можно было успеть и покататься на мотоцикле во время заката и поужинать. 

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

Ну а друзей здесь найти легко — много клубов по интересам, есть групповые пешие походы, фото-прогулки. Можно даже просто пойти гулять по пляжу и обязательно с кем-то познакомишься. Никого нигде нет только в обед. Жарко.

Adblock test (Why?)

Британские регуляторы берут на карандаш ситуацию с низкими выплатами со стороны стриминговых платформ

Рассказываем, что собирается осуществить регулятор, чем отвечают стриминговые сервисы и как на все это реагируют исполнители. Подробности — под катом.

Фотография: Dewet Willemse. Источник: Unsplash.com
Фотография: Dewet Willemse. Источник: Unsplash.com

Нерешенный вопрос

Размер роялти стриминговых сервисов — это горячий вопрос в музыкальной индустрии. Суммы сами по себе невелики, при этом существенную долю выручки забирают лейблы и дистрибуторы. До авторов зачастую доходит менее цента за прослушивание трека. Недавно британская виолончелистка Тасмин Литтл рассказала, что за полгода она получила от сервиса потоковой передачи музыки всего семнадцать долларов. Что интересно, с проблемой сталкиваются не только инди-исполнители, но и именитые представители музыкальной сцены — их доходы со стриминга редко превышают 150–300 долларов в год. Что удивительно, пандемия усугубила обстановку. Число стримов хитов сократилось на 11%.

Однако попытки исправить ситуацию все-таки предпринимают. Еще в 2018 году в США вступил в силу закон Music Modernization Act. В его рамках был сформирован госорган, который договаривается со стриминговыми платформами о размерах выплат. Первые результаты есть — роялти получают авторы произведений, записанных до 1972 года [раньше платформы могли не делать такие выплаты].

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

Британская инициатива

В начале года Пол Маккартни, Крис Мартин и Кейт Буш написали открытое письмо британскому правительству. Позже к нему присоединились The Rolling Stones и Том Джонс. Исполнители попросили премьер-министра обратить внимание на плачевную ситуацию с выплатами стриминговых сервисов. К письму также присоединился глава организации Musicians' Union, которая представляет права 30 тысяч британских исполнителей. Он отметил, что английское законодательство не поспевает за технологическим развитием музыкальной сферы — в стране действует закон об авторских правах (Copyright Act) от 1988 года — и его нужно модернизировать.

Авторы письма предложили ограничить размер комиссий сервисов и уравнять роялти с суммами, которые выплачивают радиостанции [от 10 до 100 долларов за минуту воспроизведения трека в эфире].

Фотография: Jacob Hodgson. Источник: Unsplash.com
Фотография: Jacob Hodgson. Источник: Unsplash.com

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

Без внимания не оставили и лейблы — им рекомендовали последовать примеру Sony Music, списавшей долги тысячам музыкантов, подписавших контракт до 2000 года. Теперь они смогут начать зарабатывать деньги со стримов. Инициативу поддержали в союзе Ivors Academy, отстаивающем права исполнителей в Европе.

Что делают стриминговые площадки

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

В марте SoundCloud начал выплачивать инди-исполнителям долю от подписок, которые оформляют слушатели. В свою очередь, шведский сервис запустил сайт Loud & Clear, где собрал всю информацию о формировании роялти, а в Apple Music увеличили минимальную выплату за прослушивание до одного цента.

Музыканты берут ситуацию в свои руки

Пока регуляторы изучают вопрос, а стриминговые сервисы прорабатывают разного рода компромиссы, музыканты ищут дополнительные способы заработка и привлекают внимание к проблеме. Британский коллектив While She Sleeps запустил в продажу одежду с надписью: «Одна футболка = 6500 прослушиваний на Spotify». В то же время некоторые авторы экспериментируют с методами монетизации — например, прибегают к модели pay-what-you-want, подразумевающей продажу альбома или трека без посредников по выбранной самим слушателем цене. Хотя прошлый опыт Radiohead показывает, что это не самый эффективный подход.

Фотография: Markus Spiske. Источник: Unsplash.com
Фотография: Markus Spiske. Источник: Unsplash.com

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


Дополнительное чтение — в нашем «Мире Hi-Fi»:


Adblock test (Why?)

Московские школьники создали альтернативу кислородному баллону для пожарных

Старшеклассники московской школы №2065 разработали регенеративный патрон для пожарных, который может стать альтернативой кислородному баллону. Патрон взрывобезопасен и работает на основе пероксокомплексов Ti(IV) на поверхности наночастиц оксида титана в полиакрилатной матрице с нанооксидом марганца в качестве катализатора.

Коммерсантъ
Коммерсантъ

Нынешние кислородные баллоны имеют ряд недостатков, в том числе большой вес и небольшой объем кислорода, которого хватает всего на десять минут.

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

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

«Когда проект протестируют и одобрят, его смогут взять на вооружение пожарные части, а нам останется только гордиться школьниками, которые в таком юном возрасте создают полезные и социально значимые проекты»,— отмечает спасатель и руководитель Тверского областного регионального отделения Всероссийского студенческого корпуса спасателей Андрей Кудашов.

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

Чтобы ускорить поступление кислорода, школьники добавили в запускаемую по щелчку капсулу специальный катализатор, диоксид марганца, а также щелочь. Данные вещества ускоряют реакцию, и кислород вырабатывается намного быстрее. А в качестве реагента использовались более устойчивые и невзрывоопасные пероксокомплексы титана. Это примерно в 20 раз уменьшает вес баллона. Таким образом, он будет весить не 12 кг, а 500 г. Плюс, новые комплексные соединения не боятся высоких температур и солнечного света, а ярко-желтый цвет выступает индикатором годности устройства.

Модель корпуса патрона напечатали на 3D-принтере. Спектрофотометр использовали, чтобы изучить свойства пероксидов, а сканирующий зондовый микроскоп — чтобы выяснить микроморфологию нанообъектов. С помощью датчиков кислорода и рH школьники охарактеризовали состав, а датчиком объема газа определили, что объем кислорода равен 340 мл. Именно этот показатель и повлиял на уменьшение веса прибора до 500 г.

Научный сотрудник Института фундаментальных проблем биологии РАН, кандидат биологических наук Азат Абдуллатыпов отметил также, что для создания модели использовали не АБС-пластик, а полилактид — биоразлагаемый пластик из молочной кислоты. Это делает корпусы патронов биоразлагаемыми.

Adblock test (Why?)

Она могла стать Первой: история процессорной архитектуры Alpha (часть 3)


Уверен, поклонники серии ждали с нетерпением! Не будем тянуть, пора продолжить наш мини-сериал. В предыдущих сериях (часть 1, часть 2), мы познакомились с первым и вторым поколением Digital Alpha, теперь же перед нами модель 21264 — основная и единственная линейка третьего поколения архитектуры и нам пора окунуться во все тяжкие!
Третье поколение было объявлено в 1996 году, всего через год после того, как второе стало доступно на рынке. Однако только в феврале 1998 года, незадолго до краха Digital, первые процессоры стали появляться в кремнии. К тому моменту своих фабрик у нее уже не осталось — согласно условиям сделки, процессоры выпускались на фабрике Intel Fab6, ранее принадлежавшей Digital.

Часть процессоров выпускалась на мощностях Samsung, которая стала не только партнером по выпуску, но и лицензировала архитектуру. Всего через четыре месяца, остатки Digital перешли под контроль Compaq и первые машины на Alpha 21264/EV6 вышли уже под брендом нового владельца.

Оставшись на прежнем, 0.35 мкм техпроцессе, ядро EV6 получило значительно переработанную микроархитектуру. Количество транзисторов достигло 15.2 миллиона при площади кристалла 314 мм2. Сильно возросло энергопотребление — до 73 Вт. Самым важным изменениям стало внедрение механизма внеочередного исполнения команд, причем с возможностью переименования регистров.

Микроархитектура процессора Alpha 21264. Источник

Также появились дополнительные новые инструкции, вырос до 128 Кбайт кэш L1. Кэш L2 остался внешним и все также для подключения использовал выделенную 128-битную шину, частота задавалась делителем — от ⅛ до ⅔ от частоты ядра, поддерживались микросхемы SSRAM (синхронная статическая память произвольного доступа) и DDR SSRAM. Внешняя шина (FSB) осталась 64-битной (плюс 8 бит для ЕСС), но впервые была внедрена технология DDR (та самая Double Data Rate), при которой данные передавались дважды за такт — по фронту и спаду тактового сигнала.

Alpha + AMD = ?


Новая системная шина стала важнейшей вехой в развитии Alpha, она могла дать ей, наконец, дорогу в мир ПК. Одной из причин высокой стоимости готовых Alpha-систем были сложные (и быстрые, конечно!) чипсеты, к тому же выпускаемые небольшими тиражами. Очень нужны были недорогие и массовые, пусть и более скромные в своих возможностях, платформы. «Родные» чипсеты 21272 (Tsunami, до 2 CPU) и 21274 (Typhoon, до 4 CPU) оставались многочиповыми решениями. Минимальный набор состоял из четырех чипов, не считая стороннего южного моста.

Еще при жизни Digital, AMD приобрела лицензию на шину еще находящегося в разработке EV6, чтобы использовать ее своих грядущих Athlon. И, к счастью, AMD применила ее практически без изменений. Alpha использовала 166 и 200 МГц варианты, а AMD — 200 и, в дальнейшем, 266 и более высокие частоты. Таким образом, вышедшие для Athlon чипсеты AMD 750 «Irongate» и AMD 760 «Irongate II» стали общими для EV6 и Athlon. Адаптировать свои чипсеты для работы с Alpha была готова и VIA, но для того должна была быть воля Compaq. Увы, руководство Compaq не увидело потенциала ни в недорогих Alpha, ни даже в рабочих станциях.

Рабочие станции Compaq выпустил по остаточному принципу — теперь это были просто младшие модели серверов с установленными видеоадаптерами и звуковыми картами. Таковы, например, были AlphaStation XP900/DS10. Единственным исключением стала AlphaStation XP1000, базирующаяся на старом шасси времен Digital (такое же использовалось в Digital Celebris GL). Свернуто было производство материнских плат для сторонних сборщиков. Более того, в поколении 21264 не было даже упрощенных версий для AlphaPC. Compaq упустила значительный кусок рынка, но это была лишь одна из многих ошибок, приведших компанию к поглощению Hewlett-Packard.

Здорово подкосил позиции Alpha отказ Compaq от участия в разработке Windows NT для Alpha в 1999 году, на этапе, когда Windows 2000 была уже на стадии Release Candidate. Пусть доля Windows NT на платформе была не так и велика, именно эта система кардинально влияла на проникновение Alpha в нижние (для нее) сегменты рынка. Windows 2000 для Alpha так и не была выпущена, оставшись на долгое время доступной только для платформ Intel — х86 и Itanium.

Но кроме Compaq, оставалась еще одна движущая сила — Samsung. Компания выпускала не только процессоры, но и разрабатывала и производила материнские платы для них. Более того, в 1999 году большая часть бизнеса, связанного с Alpha была выделена в созданную совместно с Compaq компанию Alpha Processor Inc., API. Samsung и API использовали как традиционные чипсеты Compaq (например, двухпроцессорная серверная плата UP2000), так и чипсеты AMD, подходящие для однопроцессорных плат. Таковы были UP1000 и UP1100.

Самой желанной для энтузиастов стала UP1500 — единственная, использовавшая северный мост AMD 761. Эта плата поддерживала память DDR SDRAM объемом до 4 Гбайт, и благодаря вдвое большей в сравнении обычной SDRAM производительности, подсистема памяти этой платы не становилась бутылочным горлышком (это касается исключительно плат на AMD 750 — платы на Typhoon/Tsunami использовали 128/256 бит интерфейс SDRAM, соответствующий потребностям процессора).

Еще одним приятным бонусом было наличие у этих плат слота AGP. Что интересно, в качестве южного моста использовались микросхемы ALi, а не обычно сопутствующие AMD 750/760 мосты VIA 686.

Сказал «А», скажи и «B»


Первые процессоры AMD Athlon использовали разъем Slot A. Такой форм-фактор имел определенную популярность в 1997-2000 годах, когда кэши выросли и переехали поближе к ядру процессора, но технологии были еще не готовы к тому, чтобы разместить кэш достаточного объема на том же кристалле. Общим для большинства процессоров в слотовом исполнении было расположение кэш-памяти в виде отдельных микросхем рядом с основной микросхемой процессора.

Исключением стали только поздние Pentium III «Coppermine» и Xeon «Cascades», которые получили кэш на кристалле, но продолжили использовать старый форм-фактор. Некоторые версии Xeon также несли на огромных размеров процессорной плате еще и модуль питания, VRM.

Итак, Slot A. Краткий опрос в среде энтузиастов ретрокомпьютинга показал, что большинство считает — в этом обозначении буква А отмечает принадлежность разъема компании AMD. И лишь немногие знают, что был также и Slot B. В исполнении Slot B выпускались процессорные модули для установки в платы UP1000 и UP2000.

Модуль сочетал в себе процессор 21264, установленный в плату без использования сокета (к сожалению, не удалось подробных фото, где было бы понятно была это BGA версия или просто припаянный к плате процессор с ножками), кэш память и VRM. Более того, согласно изначальным планам процессоры в таком исполнении должна была выпустить и AMD, вероятно это должен был быть некий ответ Intel Xeon, но и эти планы так и не были реализованы.

Лишь в 2001 году были объявлены процессоры Athlon MP и чипсет AMD 760MP с двумя шинами EV6. Плат на его основе для Alpha не последовало, а Athlon MP выпускался в том же Socket A (462), что и обычные Athlon тех лет.

Развитие или стагнация?


Как вы помните, Alpha всегда выделялась очень высокими для своего времени частотами. К концу двадцатого века, в результате гонки частот Intel и AMD и постепенного свертывания разработки архитектуры со стороны Compaq этот тренд прекратился. EV6 с частотой 466-600 МГц были не быстрее (речь только о частотах) предыдущего поколения.

Уже в 1999 году появились обновленные 21264А (EV67), выпускашиеся по 0.25 мкм технологии. Площадь кристалла сократилсь до 210 мм2, а частоты возросли до 600-750 МГц. Кроме die-shrink изменений это обновление не принесло. Что интересно, продававшийся как 600 МГц процессор на самом деле работал на 618 МГц. В том же 1999 Pentium III работал уже на 733 МГц, частоты практически сравнялись. А в 2000 году, Intel и AMD достигли частоты 1 ГГц.

В 2000 году появились 21264B (EV68) с частотами 800-833 МГц (0.18 мкм), но только в 2001 c появлением 21264С (также EV68) удалось достичь 1.25 ГГц, так и оставшихся финальными. Начиная с этой версии изменился сокет, вместо прежнего классического PGA с 587 контактами стал использоваться 675-контактный LGA. Для некоторых моделей серверов процессоры устанавливались на процессорные модули, но стандартизированы они не были, имя Slot C не появилось.

Упоминается также и 21264D, с частотами аналогичными предыдущей версии. Точные отличия этой версии от предыдущих неизвестны.

В 2001 году Compaq было очень плохо. Обвал рынка ценных бумаг интернет-компаний, более известный как крах доткомов и неэффективное управление привели компанию на грань банкротства. В 2002 году произошло объединение с HP, которое де-факто было поглощением. У большинства унаследованных от Compaq продуктов были аналоги в линейках HP. К чести последней, не весь модельный ряд Compaq был свернут, часть линеек была интегрирована в новый модельный ряд или даже заменила разработки HP.

Так ушли с рынка самобытные NetServer и Omnibook. Compaq’овские ProLiant и Evo были более мейнстримовыми, но и более совершенными — они и выжили в корпоративной борьбе. HP AlphaServer продолжили свое существование бок о бок с HP9000 и грядущими Integrity…

Очень милый сервер


Долгое время в коллекции Digital Vintage не было ни одной «Альфы». Поиски были долгими, а появление такой машины летом этого года — счастливой случайностью. Я хотел приобрести рабочую станцию IBM, но пока вел переговоры с продавцом меня опередили. Других объявлений у продавца не было, но я на удачу поинтересовался, есть ли еще что-то интересное. И получил ответ — «Альфа». Раздумывать долго не пришлось!

Представитель третьего поколения Alpha, попавший мне в руки — сервер. Сервер, выглядящий очень миловидно и до конца не определившийся кто же он такой — в зависимости от установленных плат расширения, он может быть как сервером, так и рабочей станцией. Его имя — AlphaServer DS10, но также он известен как AlphaStation XP900 и AlphaStation DS10. Наш экземпляр маркирован именно как сервер, но в нем установлена младшая из доступных для него видеокарт — 3DLabs Permedia 2 с 4 Мбайт видеопамяти.


Компанию ей составляет звуковая карта Ensoniq AudioPCI, согласно каталогу Compaq именно такая и положена. При этом на борту присутствует два сетевых интерфейса (10/100 мбит/сек), а последовательный порт может использоваться для подключения консоли.

Для сервера у DS10 очень непривычный форм-фактор. Это… десктоп. Красивый темно-синий десктоп форм-фактора NLX — в материнскую плату устанавливается плата-«елка» и в нее уже вставляются платы расширения. Боковые стенки и верхняя крышка снимаются отдельно и выполнены из шершавого, очень приятного на ощупь прочного пластика, с внутренней стороны к ним прикреплены экранирующие пластины. Ширина корпуса соответствует 19” стойке, высота — 3U, тонкие серверы в 1999 были еще в новинку.

Такая машина может стоять на столе у разработчика — она, кстати, довольно тихая, а может и в стойке — как на полке, так и, в специальном исполнении, на привычных сегодня направляющих-рельсах. Кодовое имя модели, WebBrick, очень хорошо указывает на основное применение этих машин. Кстати, существовала и 1U версия — DS10L с меньшими возможностями расширения.

По ширине корпус также соответствует классическом десктопу Inwin H500, что навевает мысли о том, что полка в стойке будет уютным домом и для него. Вот только Inwin’у потребуется на один юнит больше. DS10 при меньшей высоте также имеет два отсека для 5.25” устройств (а вот внешний отсек для 3.5” девайсов один, и его более чем достаточно) — в нашем случае в нем расположены CD-ROM (эти машины комплектовались IDE приводом) и «сказевый» стример формата DDS-4 (20/40 Гбайт).

Компанию им составляет обыкновенный 3.5” дисковод. Опционально могла устанавливаться занимающая оба отсека корзина для двух дисков SCSI SCA, поддерживающая горячую замену. В оставшемся узком пространстве над ними помещался тонкий «ноутбучный» CD-ROM.

Серверы в подобных корпусах — великая редкость. Мне известны лишь ранние модели HP NetServer с 486 процессором и AlphaServer DS10/DS15. Возможно, небольшие компании могли собирать серверы и в корпусах типа H500, но вряд ли это было сколько-нибудь распространенной практикой ввиду скромных возможностей по размещению дисковых подсистем.

Внутри корпуса скрывается фирменная материнская плата с одним разъемом Socket 587, в который в данном экземпляре установлен процессор EV67 с частотой 618 МГц (маркетинговое обозначение 600 МГц). Плата построена на чипсете Tsunami с южным мостом ALi. Оперативная память устанавливается в 4 слота SDRAM, максимальный ее объем 2 Гбайт — здесь он и достигнут. Требуется память стандарта не менее PC100, но фактически она работает на частоте 83 МГц. Интерфейс памяти — 128-битный, модули устанавливаются парами.

На плате не установлен контроллер SCSI — базовые версии DS10 обходились IDE дисками. В нашем случае SCSI реализован отдельным двухканальным контроллером Adaptec 39160 (установлена оригинальная плата с маркировкой HP — наша машина выпущена уже после слияния, в конце 2002 года). К первому каналу подключен основной жесткий диск — максимальный, согласно каталогу, 73 Гбайтный с интерфейсом Ultra160 SCSI и скоростью вращения шпинделя 10000 RPM. Диск быстрый и на удивление весьма тихий.

У контроллера есть и внешние разъемы, так что на второй канал можно повесить стример, ленточную библиотеку или дисковую полку. Из перечисленного в комплекте с машиной мне досталась оригинальная полка для SCSI дисков с несколькими 9 и 18 Гбайт накопителями. Она выполнена в том же цвете, что и сервер и отлично дополняет его. Полка довольно старой модели и выпускалась еще во времена Digital, о чем говорит тот факт, что один из блоков питания несет лого старой компании, а два — уже новой.


Блок питания очень похож на АТХ, но фактически плата не поддерживает управлением питанием. При завершении работы ОС отключение питания не происходит, вместо этого управление системой передается SRM. Аналогичное действие выполняет кнопка Halt, заменяющая Reset. Причем ее функцию можно изменить на Reset установкой джампера — это сделано для работы под управлением Windows NT.

Большинство Alpha-машин требовали перепрошивки для использования ARCBIOS и установки Windows NT. Лишь некоторые имели две прошивки сразу. В DS10 достаточно набрать в консоли SRM команду «arc» (или переключить режим работы в «NT») и можно работать ОС, требующими ARC прошивку.


Первичная загрузка также выполняется SRM, причем возможно настроить систему как на автоматический запуск ОС с устройства по умолчанию, так и на ручной старт из консоли SRM. Таким образом можно реализовать мультизагрузку, установив на каждый подключенный жесткий диск свою ОС.

ТруЪ ЮниксЪ


Среди прочего, Compaq унаследовала от Digital и разработанные ею операционные системы — OpenVMS и Digital Unix. Обе были весьма популярны — Digital Unix устанавливалась на 65% выпускаемых на тот момент Alpha-систем, а OpenVMS хоть и занимала около 30%, но считалась незаменимой в целом ряде применений. Обеим повезло — Compaq был заинтересован в их развитии, вот только имя бывшего конкурента мозолило глаза руководителям компании. Так Digital Unix начиная с версии 4.0F стала Tru64 Unix, что отражало нативно 64-битную природу системы.

Согласно идентификатору моего DS10, он поставлялся именно с Tru64 Unix версии 5.1, так что именно эту систему было решено выбрать для установки (а еще я пока не разобрался с OpenVMS). Установка довольно проста — загружаемся с CD-ROM, выбираем требуемый набор компонентов, разбивку диска, устанавливаем базовые настройки. При установленной видеокарту все это происходит в графическом режиме. Установка длится 40 минут и система сразу готова к работе.

Первым делом, нас встречает классическая оболочка CDE. Бывшая прорывом в середине девяностых, в начале XXI века, она смотрится все еще приятно, но устаревание уже чувствуется. Набор ПО в комплекте небольшой, только самое необходимое — утилиты и браузер. По умолчанию установлен Netscape 4 и Netscape 6. Возможно установить Mozilla Firefox 1.5.

На втором диске комплекта идут важные дополнения — мультимедийные службы, драйверы звуковых карт и 3D-ускорителей PowerStorm. На дополнительных дисках — утилиты с открытым исходным кодом, что крайне важно, пакетный менеджер RPM и окружение для работы Linux-программ. Пакетов в комплекте немного, еще некоторое количество доступно в интернете. Так я получил несколько простых игр, Xpaint, VNC и самое полезное — OpenOffice.

В целом, с софтом и поддержкой современных форматов файлов довольно грустно. Фон рабочего стола — XPM. Музыка — WAV. Большинство настроек оболочки (к консольному ПО претензий нет) выполняется через редактирование файлов конфигурации, даже настройки разрешения и частоты обновления экрана. Главной болью для меня лично стало отсутствие аналога Midnight Commander и проигрывателя MP3. Так я задался целью обеспечить себя этими необходимыми для комфортной жизни удобствами.


К счастью, в комплект системы входит компилятор, плюс среди GNU-утилит есть и gcc. С коммандером проблем не возникло — он собрался с первого же раза (я брал относительно старую версию 2017 года) и разве что упорно не хотел работать в цветном режиме. Пришлось сделать скрипт-обертку, который добавляет ключ принудительного цветного режима и передает остальные параметры при необходимости.

В качестве плеера был выбран весьма старый XMMS. Причина тому проста — он умеет выводить звук с помощью EsounD, Enlightened Sound Daemon. Это единственный доступный вариант для Tru64 из относительно распространенных. Другой вариант — штатная подсистема мультимедиа (в нее по факту и перенаправляется звук), но для нее плеер пришлось бы писать с нуля самостоятельно.


Сборка стала испытанием для моего терпения — в обычной жизни мне не приходится этим заниматься вообще, а тут потребовалось удовлетворить множество зависимостей из обоих миров — Unix и Linux, а потом еще и внести немного правок в скрипт сборки. Так или иначе — спустя полночи у меня уже играл в наушниках старый добрый Nightwish. XMMS не разочаровал.

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

Итак, теперь система вполне подходит для жизни при тяжелых приступах ностальгии. Загрузка занимает не больше пары минут, после загрузки работает субъективно очень быстро. Большинство программ запускаются мгновенно, за исключением браузера, офисного пакеты и плеера. А уровень погружения в период — кажется улетает далеко за 100%. Можно слушать музыку, работать с документами и даже ходить в интернет.

В основном, конечно, на сайты ретротематики — функционала браузера и производительности на современные сайты хватает с трудом. При этом по ощущениям, работать в интернете на Альфе комфортнее, чем на более свежих Pentium 4 с частотой 2.4 — 3 ГГц. Но это снова субъективное ощущение. Тестов производительности я не выполнял.


Моим главным опасением было разочарование, к счастью этого не случилось. Эта машина действительно великолепно сконструирована и в сравнении с ПК довольно необычно. Одна только консоль SRM вместо BIOS стоит многого. Я довольно плотно работал с этой машиной в течении месяца и получил массу удовольствия. Сейчас она установлена на стенде с моими любимыми сборками из мира х86 и подключена к KVM, чтобы можно было в любой момент получить требующуюся дозу ностальгии. Ее соседями стали уже знакомые моим читателями двухпроцессорные сборки с Pentium Pro и Pentium III Xeon и пара более скромных ностальжи-машин.

Заключение


Третье поколение архитектуры стало вершиной развития Alpha и началом конца. Постепенный отказ от создания рабочих станций и полное сворачивание программы AlphaPC сначала ограничили архитектуру развитием исключительно на серверном рынке, а потом столкнув во внутренней конкуренции сначала с Itanium, на который Compaq возлагала большие надежды, а потом еще и с PA-RISC — родным детищем HP, на замену которому и готовился совместными силами Itanium. Кто уйдет первым — вы узнаете из следующей части статьи. Подготовлю сразу, happy end не грозит никому из упомянутых.

До новых встреч!

Adblock test (Why?)

СМИ сообщили, что Уильям Шетнер полетит в космос на втором туристическом рейсе New Shepard

TMZ и Independent сообщили, что Уильям Шетнер полетит в космос на втором туристическом рейсе New Shepard. Старт запланирован на октябрь этого года, имена других пассажиров пока не названы.
Основатель Amazon Джефф Безос является любителем научной фантастики и большим поклонником сериала «Звездный путь», который он смотрел с детства. Вероятно, именно поэтому Безос выбрал исполнителя культовой роли капитана Кирка во второй гражданский экипаж New Shepard.

Сейчас знаменитый канадский актер, режиссер, продюсер и сценарист продолжает свою актерскую карьеру и исполняет роль ведущего в различных научно-популярных передачах, занимается озвучиванием учебных видеороликов. Совсем недавно он выпустил автобиографический альбом "Билл". В 2020 году актер просил НАСА и SpaceX взять его пассажиром в космос, чтобы исполнить свою мечту там побывать.

Если полет состоится, то 90-литний Шетнер станет самым пожилым космическим туристом в истории. Пока что это место в статистике пассажирских полетов занимает первая женщина-инспектор Федерального авиационного управления США и участница программы «Меркурий 13» 82-летняя Уолли Фанк, лично летавшая с Безосом этим летом.

В настоящее время Шетнер и Blue Origin не предоставили представителям СМИ комментарии по этой ситуации.

Первый туристический полет New Shepard состоялся 20 июля 2021 года. В течение 15 минут капсула корабля поднялась на высоту 105 км, экипаж провел примерно 3-4 минуты в условиях невесомости, наблюдая в иллюминаторы Землю и космос.

Adblock test (Why?)

Робот-газонокосилка, часть 2. Определение высоты травы

В первой части мы переделали бензиновую газонокосилку в самоходную электрическую с помощью деталей от б/у гироскутера: двух мотор-колес, основной платы и аккумулятора. И добавили возможность управлять газонокосилкой с телефона через Wi-Fi.

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


Часть 1. Механика и радиоуправление
Часть 2. Определение высоты травы
Часть 3. Сегментация травы нейросетью
Часть 4. Карта газона на визуальных маркерах

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

У этого способа есть большое преимущество - не требуется подготовка карты местности. Также это очень простой способ, ему не нужна большая вычислительная мощность. Поэтому с ним справится тот же микроконтроллер ESP8266, который управляет моторами газонокосилки и отвечает за радиоуправление с телефона.

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

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

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

Датчики расстояния

Существуют два основных популярных датчика расстояния, знакомых каждому ардуинщику. Это ультразвуковой HC-SR04 (цена 50 рублей) и относительно недавно появившиеся лазерные дальномеры VL53L0X (цена 120 рублей).

Слева HC-SR04, справа VL53L0X. Масштаб примерно соответствует реальному
Слева HC-SR04, справа VL53L0X. Масштаб примерно соответствует реальному

Они оба обладают сравнимыми характеристиками: измеряемое расстояние около 2 метров, частота измерений 10-20 раз в секунду. Даже угол зрения у них похож, примерно 30 градусов. Другими словами, они оба измеряют не расстояние до точки впереди, а до всего что попадет в конус с углом 30 градусов.

Лазерный VL53L0X работает по протоколу I2C и намного меньше по размеру. Смотрите масштаб на фото выше. К сожалению, не смотря на использование шины I2C, нельзя несколько VL53L0X повесить на общие четыре провода (два для шины I2C и два для питания). Потому что они с завода имеют одинаковый адрес. А для смены адреса к каждому датчику VL53L0X нужно тянуть отдельный провод.

А ультразвуковой HC-SR04 для точной работы требует поддержки микроконтроллером прерываний. Так как его принцип работы состоит в том, что надо подать сигнал на пин TRIGGER, после чего датчик испускает серию ультразвуковых волн, а после получения отраженного сигнала, он изменяет состояние своего пина ECHO. Поэтому приходится на ECHO вешать прерывание, чтобы измерять точные временные интервалы.

Из недостатков этих датчиков нужно отметить, что на VL53L0X может влиять яркий солнечный свет, а у HC-SR04 трава довольно сильно глушит звуки. Но на практике они оба прекрасно работают днем. И даже точность при работе по траве у них примерно одинаковая.

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

Алгоритм работы

В минимальной конфигурации для такого автопилота нужен только один датчик HC-SR04 или VL53L0X.

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

Если в этом месте расстояние от датчика до травы будет меньше некоторого порога, то это означает, что в этом месте трава высокая, а значит нужно поворачивать влево. В сторону скошенной полосы. А если датчик покажет расстояние больше порога, то значит там трава низкая, то есть уже скошенная. Это расстояние до голой земли. И значит надо повернуть вправо, в сторону еще не скошенной высокой травы.

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

Эта задача известна как "следование по линии" и является базовой на кружках робототехники. Машинка едет по нарисованной черной линии на полу, стараясь не съезжать с нее.

Обычно там используется ряд из 2-8 фотодиодов, которые позволяют определить текущий угол отклонения от линии. Этот угол используется в PID контроллере, чтобы при больших углах поворачивать резче, а при маленьких более плавно. Интегральный и дифференциальный компонент в формулах PID помогают ехать ровно, без колебаний относительно линии.

К счастью, так как мы не просто фиксируем черное пятно под датчиком, а измеряем именно расстояние, которое показывает высоту травы. Которая однозначно определяет в какую сторону нам нужно повернуть. Поэтому в минимальной конфигурации нам достаточно только одного датчика. Хотя можно использовать и несколько, конечно.

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

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

Мы будем использовать именно такой продвинутый вариант.

Программа

Как и в прошлый раз, программировать ESP8266 будем на языке javascript с помощью Espruino. Установка и настройка описаны в предыдущей части.

Воспользуемся по максимуму предыдущей программой, сохранив возможность управлять газонокосилкой с телефона по Wi-Fi. Просто добавим еще одну кнопку в интерфейс с названием Auto, при нажатии на которую будет включаться автопилот.

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

Технически, мы все еще будем слать на газонокосилку команды каждые 20-40 миллисекунд, чтобы отслеживать со стороны ESP8266 возможный обрыв связи. Это тоже увеличит безопасность, при пропадании связи дольше 300 миллисекунд газонокосилка автоматически остановится.

Но в режиме автопилота вместо команд /M, мы будем слать команды /MA, обозначающие автоматический режим.

Чтобы не мучаться с обработкой и хранением настроек на самой ESP8266, мы будем каждый раз в строке /MA слать полный набор параметров, нужных для автопилота. При скоростях Wi-Fi несколько лишних символов в строке запроса на скорости никак не сказываются, а это позволит нам динамически менять параметры автопилота из HTML интерфейса. И так отлаживать настройки для конкретной газонокосилки.

И параметры эти следующие:

/MAdist,speed,rotate,rotate2,rotate_timeout,turn,turn_timeout

Здесь dist - это расстояние в сантиметрах от датчика до травы. Расстояния меньше этого значения будут означать, что мы находится над высокой травой. А расстояния меньше - что над плоской землей, т.е. над уже прокошенным участком.

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

rotate и rotate2, - это степень поворота при подруливании, тоже -1000...1000. Причем степень подруливания линейно увеличивается от rotate до rotate2 в течение времени rotate_timeout в миллисекундах. Это позволит нам увеличивать угол поворота, если мы долго находится над высокой травой (или над скошенной). Аналог угла отклонения от линии у машинок.

turn - остановка и поворот с такой скоростью на месте, если за предыдущее время rotate_timeout так и не смогли выйти на скошенную (или на высокую) траву. Это аналог второго режима у машинок для слишком большого угла отклонения.

Если же за время turn_timeout в миллисекундах мы так и не сможем найти границу травы, то полностью останавливаемся и ждем команды оператора. Потому что дальше неизвестно что делать, мы потеряли слежение. Газонокосилка при этом начнет издавать по три коротких звука для сигнализации, что она застряла в этом жестоком непредсказуемом мире.

Итоговая строка отправляемых на газонокосилку команд для автоматического режима может выглядеть так:

/MA25,100,80,100,3000,200,5000

Здесь порог расстояния до травы 25 см, двигаться вперед с базовой скоростью 100 (из диапазона 1000, то есть на 10% газа), подруливать начиная от уровня 80, плавно увеличивая до 100 в течении 3000 миллисекунд (3 секунд). Если же за 3 секунды косилка не сможет найти границу травы, то остановиться и поворачивать с одинаковой скоростью 200 в течение 5000 миллисекунд (5 секунд). Если же и после этого не удастся найти, то полностью остановиться.

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

auto <input id='i_auto' type=text value='25,100,80,100,3000,200,5000'>

Также добавим отдельную кнопку для включения и выключения датчика расстояния. По умолчанию он будет выключен и включаться только при авто режиме. Эта кнопка просто шлет специальную команду /D в ESP8266

<button onclick="send('D')">dist</button>

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

Автопилот включен
Автопилот включен

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

И текущий уровень газа на моторы, который выдает ESP8266. В виде speed,steer (каждое значение в диапазоне -1000....1000).

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

В данном случае газонокосилка едет вперед со скоростью 100 (10% полного газа) и поворачивает вправо с уровнем поворота 93 (9.3% от максимума). Факт наличия поступательной скорости 100 единиц говорит о том, что автопилот находится в первом режиме: движение вперед с постоянным подруливанием. Если бы он перешел на второй режим с поворотами на месте, то там первое значение стояло бы 0, а второе 200 (как задано в настройках отправляемой строки /MA): 26 cm 0,200

Такая обратная связь в коде реализуется очень просто: в конце каждого GET запроса вместо ОК мы теперь возвращаем готовую строку:

res.end(A.status+" "+speed+","+steer);

Здесь в A.status сохранено текущее расстояние "26 cm".

А в HTML интерфейсе на телефоне, если ответ сервера в функции fetch() отличается от "ОК", то выводим на экран все что он прислал:

if (data!='OK') info.innerText = data;

Настройки автопилота в коде для удобства хранятся в одном объекте А

A = {
        sensor_type: 2, // 0 - без дальномера, 1 - лазерный VL53L0X, 2 - ультразвуковой HC-SR04

        dist_grass: 30, // cm
        speed: 300,             // move base, 0..1000
        rotate: 400,
        rotate2: 600,
        rotate_timeout: 3000, // ms
        turn: 300,              // rotate in place, 0..1000
        turn_timeout: 5000,// ms

        is_auto: false,
        is_dist: false,
        sensor: null,           // HC-SR04 или VL53L0X
        dist: 0.0,                      // текущее расстояние, cm
        time_rotate: 0,
        time_turn: 0,
        mode: 0,                        // -2,-1,0,1,2, 5 (-2 - turn, -1 - rotate, 0 - stop, 5 - begin auto)
        status: "",
}

Здесь обратите внимание на A.sensor_type, с помощью которого можно выбрать используемый датчик расстояния: ультразвуковой HC-SR04 или лазерный VL53L0X (сейчас выбран HC-SR04).

Можно также отключить оба датчика при sensor_type: 0, тогда телефон будет просто пультом радиоуправления газонокосилкой, как было в первой части.

Дальше идут текущие настройки автопилота, такие же как в строке /MA, а ниже еще несколько служебных переменных, необходимых для работы автопилота.

При каждом получении команды /MA со списком параметром, мы ее парсим и сохраняем настройки автопилота в объект A:

     } else if (msg[1]=="M" && msg[2]=="A") {
                // /MAdist,speed,rotate,rotate2,rotate_timeout,turn,turn_timeout
                
                var arr = msg.split(",");
                A.dist_grass = arr[0].substring(3)*1;
                A.speed = arr[1]*1; 
                A.rotate = arr[2]*1;
                A.rotate2 = arr[3]*1;
                A.rotate_timeout = arr[4]*1;
                A.turn = arr[5]*1;
                A.turn_timeout = arr[6]*1; 

                if (!A.is_auto) A.mode = 5; // begin auto
                A.is_auto = true;
                A.is_dist = true;
        }

Получение команды /MA включает и датчик (A.is_dist = true), и режим автопилота (A.is_auto = true). А каждое получение команды /M отключает автопилот:

       } else if (msg[1]=="M") {
                // /M-1000,1000

                A.is_auto = false;
    
    ....

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

И последнее отличие от предыдущей версии программы для ESP8266, это собственно функция автопилота auto(). Она запускается по таймеру в onInit() каждые 100 мс, то есть по 10 раз в секунду.

Функция автопилота auto()

function auto(){

        if (A.sensor && (A.is_dist || A.is_auto)) {

                A.status = A.dist.toFixed(0)+" cm";

                if (A.sensor_type == 1) {
                        try{
                        A.dist = A.sensor.performSingleMeasurement().distance / 10;     // VL53L0X, mm -> cm
                        }catch(e){A.status='error';}
                } else {
                        A.sensor.trigger(); // HC-SR04, send pulse, result in A.dist
                        }
                
        }

        if (!A.is_auto || A.dist < 5 || A.dist > 100 || A.mode == 0) return;  // 5..100 cm

        var time = Date.now();  // ms

        if (A.dist <= A.dist_grass) {
                // grass, rotate left
                if (A.mode == -2) {
                        // turn left
                        if (time - A.time_turn > A.turn_timeout) {
                                // stop
                                speed = 0;
                                steer = 0;
                                A.mode = 0;     // stop
                        } else {
                                // turn
                                speed = 0;              // in place
                                steer = -A.turn;        // left
                        }

                } else {
                        // rotate left
                        if (A.mode != -1) {A.mode = -1; A.time_rotate = time;} // begin rotate
                        if (time - A.time_rotate > A.rotate_timeout) {
                                // timeout rotate
                                A.mode = -2;
                                A.time_turn = time; // begin turn
                        } else {
                                // PID
                                speed = A.speed;        // base move
                                steer = -(A.rotate + Math.floor((A.rotate2-A.rotate)*(time - A.time_rotate)/A.rotate_timeout)); // rotate...rotate2, left
                        }

                }


        //---
        } else {
                // no grass, rotate right

                if (A.mode == 2) {
                        // turn right
                        if (time - A.time_turn > A.turn_timeout) {
                                // stop
                                speed = 0;
                                steer = 0;
                                A.mode = 0;     // stop
                        } else {
                                // turn
                                speed = 0;              // in place
                                steer = A.turn; // right
                        }

                } else {
                        // rotate right
                        if (A.mode != 1) {A.mode = 1; A.time_rotate = time;} // begin rotate
                        if (time - A.time_rotate > A.rotate_timeout) {
                                // timeout rotate
                                A.mode = 2;
                                A.time_turn = time; // begin turn
                        } else {
                                // PID
                                speed = A.speed;        // base move
                                steer = A.rotate + Math.floor((A.rotate2-A.rotate)*(time - A.time_rotate)/A.rotate_timeout); // rotate...rotate2, right
                        }
                }
        }

        send_motors();
}

Она запутанная по структуре, но очень простая по логике.

Сначала получаем расстояние до травы от датчика (это делается с частотой вызова функции auto(), то есть 10 раз в секунду). Лазерный VL53L0X сразу возвращает значение, только его нужно разделить на 10, чтобы перевести миллиметры в сантиметры. Но VL53L0X может выдавать ошибки в I2C шине, поэтому эту функцию нужно заключить в блок try/catch

A.dist = A.sensor.performSingleMeasurement().distance / 10;

А у ультразвукового HC-SR04 нужно только вызвать начало измерения. Результат запишется в переменную A.dist в обратном вызове.

A.sensor.trigger();

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

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

Выше я упоминал, что в случае полной остановки газонокосилка будет издавать по три звуковых сигнала. Это делается тем, что просто перестаем слать команды по UART, так как из-за A.mode = 0 до последней строчки с send_motors(); скрипт в этом случае не дойдет. Немного грязный хак, но полезный. Чем все время смотреть в экран телефона, чтобы отследить момент когда автопилот сдался.

Инициализация самих датчиков делается в onInit().

VL53L0X

VL53L0X инициализируется довольно просто:

              try{
                        I2C1.setup({ scl : pin_TRIG, sda: pin_ECHO , bitrate: 100000});         // bitrate: 15000 - 400000, по умолчанию 100000 (100кГц)
                        A.sensor = require("VL53L0X").connect(I2C1);
                }catch(e){A.status='error init VL53L0X';}

Модуль VL53L0X.js для работы с этим датчиком Espruino IDE скачивает автоматически (но можно скачать вручную и положить в папку modules, если в настройках IDE указана папка с проектом).

Этот код надо заключать в блок try/catch, так как он может выдавать ошибку, если не удалось инициализировать VL53L0X. Но благодаря A.status, об этом будет сообщено на экране телефона.

Подключается VL53L0X как пин SDA к пину D5 на ESP8266, а пин SCL к D6.

Питание у VL53L0X +3.3V, поэтому подсоединяется напрямую к ESP8266.

ВНИМАНИЕ! У меня VL53L0X по неизвестным причинам иногда начинает выдавать сплошные ошибки в шине I2C (No ASK). Причем сброс микроконтроллера не помогает, только полное отсоединение VL53L0X от питания. Возможно, это что-то с моими модулями или с прошивкой Espruino, а возможно на длинных провода I2C сама по себе работает нестабильно. Можно попробовать подтянуть SDA и SCL к +3.3V внешними подтягивающими резисторами. В шине I2C на обоих этих проводах здесь всегда должно быть напряжение +3.3V, а устройства при передаче данных замыкают их на 0.

Как подключить несколько датчиков VL53L0X?

Есть два способа. Либо использовать внешнюю плату типа TCA9548, которая позволяет переключаться между несколькими I2C датчиками с одинаковым адресом. Либо к каждому VL53L0X подвести по дополнительному проводу к пину XSHUT. Замыкая его на землю с помощью (OUTPUT, LOW), можно на время отключить датчик, а переведя его в (INPUT), включить обратно.

Тогда алгоритм такой: с помощью пина XSHUT выключаем все VL53L0X, потом включаем по одному и с помощью I2C команды меняем его адрес на какой-то другой. После этого у всех датчиков будут разные адреса и они прекрасно будут работать на одной I2C шине.

Ниже под спойлером пример кода для инициализации двух VL53L0X внутри функции onInit(). С большим числом датчиков это делается аналогично.

function onInit() {
        // эта функция запускается при старте

        // выключаем оба (OUTPUT, LOW)
        digitalWrite(pin_X1, 0); 
        digitalWrite(pin_X2, 0);

        // set up I2C
        I2C1.setup({ scl : pin_SCL, sda: pin_SDA , bitrate: 100000});           // bitrate: 15000 - 400000, по умолчанию 100000 (100кГц)
        
  // включаем первый
        pinMode(pin_X1, 'input');
        laser1 = require("VL53L0X").connect(I2C1, {address:0x54 });

        // включаем второй
        pinMode(pin_X2, 'input');
        laser2 = require("VL53L0X").connect(I2C1, {address:0x56 });

        // создаем HTTP сервер
        server = require("http").createServer(onPageRequest).listen(PORT);

}

HC-SR04

А с HC-SR04 еще проще. Его инициализация сразу включает callback функцию, куда передается расстояние в сантиметрах, когда оно появляется в датчике. Поэтому мы его просто копируем в переменную A.dist

               A.sensor = HC_SR04(pin_TRIG,pin_ECHO,function(d) {
                        A.dist = d; // cm
                });

Для начала нового измерения, по-прежнему надо вызвать A.sensor.trigger(), что делается в функции auto() по 10 раз в секунду.

ВНИМАНИЕ! Модуль HC-SR04.js в Espruino для работы с датчиком HC-SR04... Не работает с ним! Точнее, ответ от HC-SR04 приходит через полторы секунды. Проблема во времени с триггером.

Поэтому я просто вставил код исправленного модуля (он небольшой) в саму программу. Вот так это выглядит:

Исходный код
// HC-SR04
HC_SR04 = function(/*=PIN*/trig, /*=PIN*/echo, callback) {
        var riseTime = 0;
        trig.reset(); // lower the trigger, as it would have been floating
        setWatch(function(e) { // check for rising edge
          riseTime=e.time;
        }, echo, { repeat:true, edge:'rising'  });
        setWatch(function(e) { // check for falling edge
          callback(((e.time-riseTime)*1000000)/57.0);
        },  echo, { repeat:true, edge:'falling' });
        return {
          trigger : function() {
                digitalPulse(trig, 1, 0.1);  // FIX: было 0.01 /*10uS*/, из-за чего время ответа было 1600 мс
          }
        };
  };

Вся остальная работа с HC-SR04 остается без изменений.

ВНИМАНИЕ! Большинство датчиков HC-SR04 с алиэкспресс работают только с напряжением +5V. Которое нужно подавать на их пин TRIGGER для начала измерения. Хотя иногда встречаются модели, способные работать в том числе и на +3.3V, но это большая редкость.

Поэтому при подключении HC-SR04 к ESP8266 придется делать это через конвертор уровней из +3.3V в +5V. К счастью, на NodeMCU V3 есть пин VU, на котором есть +5V. Его можно использовать для запитывания конвертора уровней. Но +5V на пине VU есть только при питании самой ESP8266 от USB, то есть от внешнего повербанка. Как всегда, работа с микроконтроллерами сплошная попаболь.

Подключите пин ECHO к D5 на ESP8266, а пин TRIG к D6. И +5V к VIN у HC-SR04. Ну и GND, конечно.

Итоговый скрипт для ESP8266

Под спойлером ниже полный финальный код для ESP8266.

Финальный код для ESP8266

pin_ECHO = NodeMCU.D5;  // ECHO у HC-SR04 или SDA у VL53L0X
pin_TRIG = NodeMCU.D6;  // TRIG у HC-SR04 или SCL у VL53L0X

wheel_4 = false;                // 2 платы?
pin_4 = NodeMCU.D2;     // пин для UART второй платы
TIMEOUT = 300;                  // таймаут связи, мс

speed = 0;  // газ
steer = 0;  // повороты

var server;
serial2 = null;
time_last = 0;  // время последней команды

// для бинарных данных по UART
buffer = new ArrayBuffer(8);    // 8 байт в одной UART команде
view = new DataView(buffer);    // нужно для записи uint16_t и int16_t в buffer


// режим auto
A = {
        sensor_type: 1, // 0 - без дальномера, 1 - лазерный VL53L0X, 2 - ультразвуковой HC-SR04

        dist_grass: 30, // cm
        speed: 300,             // move base, 0..1000
        rotate: 400,
        rotate2: 600,
        rotate_timeout: 3000, // ms
        turn: 300,              // rotate in place, 0..1000
        turn_timeout: 5000,// ms

        is_auto: false,
        is_dist: false,
        sensor: null,           // HC-SR04 или VL53L0X
        dist: 0.0,                      // текущее расстояние, cm
        time_rotate: 0,
        time_turn: 0,
        mode: 0,                        // -2,-1,0,1,2, 5 (-2 - turn, -1 - rotate, 0 - stop, 5 - begin auto)
        status: "",
}

// HC-SR04
HC_SR04 = function(/*=PIN*/trig, /*=PIN*/echo, callback) {
        var riseTime = 0;
        trig.reset(); // lower the trigger, as it would have been floating
        setWatch(function(e) { // check for rising edge
          riseTime=e.time;
        }, echo, { repeat:true, edge:'rising'  });
        setWatch(function(e) { // check for falling edge
          callback(((e.time-riseTime)*1000000)/57.0);
        },  echo, { repeat:true, edge:'falling' });
        return {
          trigger : function() {
                digitalPulse(trig, 1, 0.1);  // FIX: было 0.01 /*10uS*/, из-за чего время ответа было 1600 мс
          }
        };
  };


function onInit() {
        // эта функция запускается при старте

        // UART на D4 (аппаратный Tx)
        Serial2.setup(9600, {tx:NodeMCU.D4});

        // софтверный UART для второй платы
        if (wheel_4) {
                serial2 = new Serial();
                serial2.setup(9600,{tx:pin_4}); 
                }

        send_motors();

        // timeout wifi
        setInterval(check_timeout,TIMEOUT);

        // создаем HTTP сервер
        server = require("http").createServer(onPageRequest).listen(80);

        if (A.sensor_type == 1) {
                // VL53L0X over I2C
                try{
                I2C1.setup({ scl : pin_TRIG, sda: pin_ECHO , bitrate: 100000});         // bitrate: 15000 - 400000, по умолчанию 100000 (100кГц)
                A.sensor = require("VL53L0X").connect(I2C1);
                }catch(e){A.status='error init VL53L0X';}
        } else if (A.sensor_type == 2) {
                // HC-SR04
                A.sensor = HC_SR04(pin_TRIG,pin_ECHO,function(d) {
                        A.dist = d; // cm
                });
        }

        // auto mode (для HC-SR04 минимум 60 мс между измерениями, для VL53L0X минимум 20 мс)
        if (A.sensor) setInterval(auto,100);

        }

function check_timeout(){
        if (Date.now() - time_last > TIMEOUT) {
                // стоп
                
                A.is_auto = false;

                speed = 0;
                steer = 0;      
                send_motors();
                }
        }


function onPageRequest(req, res) {
        var msg = req.url;
        res.writeHead(200, {'Content-Type': 'text/html', 'Access-Control-Allow-Origin': '*'});
        
        // время прихода последней команды
        time_last = Date.now(); 

        // парсим строку

        if (msg =="/") {
                res.end(WEB);
                return;

        } else if (msg[1]=="D") {
                // /D
                A.is_dist = !A.is_dist;
                if (!A.is_dist) A.dist = 0;

        } else if (msg[1]=="M" && msg[2]=="A") {
                // /MAdist,speed,rotate,rotate2,rotate_timeout,turn,turn_timeout
                
                var arr = msg.split(",");
                A.dist_grass = arr[0].substring(3)*1;
                A.speed = arr[1]*1; 
                A.rotate = arr[2]*1;
                A.rotate2 = arr[3]*1;
                A.rotate_timeout = arr[4]*1;
                A.turn = arr[5]*1;
                A.turn_timeout = arr[6]*1; 

                if (!A.is_auto) A.mode = 5; // begin auto
                A.is_auto = true;
                A.is_dist = true;

        } else if (msg[1]=="M") {
                // /M-1000,1000

                A.is_auto = false;

                var ind = msg.indexOf(',',2);
                var sp = parseInt(msg.substring(2,ind));
                var st = parseInt(msg.substring(ind+1, msg.length));

                // газ моторов (шлем в UART всегда)
                if (sp >= -1000 && sp <= 1000 && st >= -1000 && st <= 1000) {
                        speed = sp;
                        steer = st;
                        send_motors();
                        }
                } 
        res.end(A.status+" "+speed+","+steer);
        }


function send_motors() {
        // отправка текущего газа на моторы

        view.setUint16(0, 0xABCD, true); // uint16_t start = 0xABCD, стартовые 2 байта сообщения, true - все little endian
        view.setInt16(2, steer, true);   // int16_t steer=-1000..1000
        view.setInt16(4, speed, true);   // int16_t speed=-1000..1000
        view.setUint16(6, 0xABCD ^ steer ^ speed, true);  // uint16_t checksum = start ^ steer ^ speed

        Serial2.write(buffer);  // write, чтобы отправить бинарные данные
        if (wheel_4) serial2.write(buffer);             // вторая плата
        }



function auto(){

        if (A.sensor && (A.is_dist || A.is_auto)) {

                A.status = A.dist.toFixed(0)+" cm";

                if (A.sensor_type == 1) {
                        try{
                        A.dist = A.sensor.performSingleMeasurement().distance / 10;     // VL53L0X, mm -> cm
                        }catch(e){A.status='error';}
                } else {
                        A.sensor.trigger(); // HC-SR04, send pulse, result in A.dist
                        }
                
        }

        if (!A.is_auto || A.dist < 5 || A.dist > 100 || A.mode == 0) return;  // 5..100 cm

        var time = Date.now();  // ms

        if (A.dist <= A.dist_grass) {
                // grass, rotate left
                if (A.mode == -2) {
                        // turn left
                        if (time - A.time_turn > A.turn_timeout) {
                                // stop
                                speed = 0;
                                steer = 0;
                                A.mode = 0;     // stop
                        } else {
                                // turn
                                speed = 0;              // in place
                                steer = -A.turn;        // left
                        }

                } else {
                        // rotate left
                        if (A.mode != -1) {A.mode = -1; A.time_rotate = time;} // begin rotate
                        if (time - A.time_rotate > A.rotate_timeout) {
                                // timeout rotate
                                A.mode = -2;
                                A.time_turn = time; // begin turn
                        } else {
                                // PID
                                speed = A.speed;        // base move
                                steer = -(A.rotate + Math.floor((A.rotate2-A.rotate)*(time - A.time_rotate)/A.rotate_timeout)); // rotate...rotate2, left
                        }

                }


        //---
        } else {
                // no grass, rotate right

                if (A.mode == 2) {
                        // turn right
                        if (time - A.time_turn > A.turn_timeout) {
                                // stop
                                speed = 0;
                                steer = 0;
                                A.mode = 0;     // stop
                        } else {
                                // turn
                                speed = 0;              // in place
                                steer = A.turn; // right
                        }

                } else {
                        // rotate right
                        if (A.mode != 1) {A.mode = 1; A.time_rotate = time;} // begin rotate
                        if (time - A.time_rotate > A.rotate_timeout) {
                                // timeout rotate
                                A.mode = 2;
                                A.time_turn = time; // begin turn
                        } else {
                                // PID
                                speed = A.speed;        // base move
                                steer = A.rotate + Math.floor((A.rotate2-A.rotate)*(time - A.time_rotate)/A.rotate_timeout); // rotate...rotate2, right
                        }
                }
        }

        send_motors();
}



//WEB = `Server start...`;
WEB = `
<html>
<meta charset="UTF-8" />
<meta name="viewport" content="width=200, initial-scale=1">
<style>
.slider {-webkit-appearance: none; background: #82E0AA; outline: none; position: absolute; height:30%;}
</style>
<span id="info" style="color:red;">&nbsp;⬤</span>
<button onclick="div_opt.style.display=='none'?div_opt.style.display='block':div_opt.style.display='none';">☰</button>
<div id='div_opt' style="display:none">
<input id='speed_m' type="range" min="0" max="1000" value ="500"> <input id='steer_m' type="range" min="0" max="1000" value ="400">
<br>move <input id='i_move' type=text size=1 value=220> <button onclick="send('D')">dist</button>
<br>auto <input id='i_auto' type=text value='25,100,80,100,3000,200,5000'>
</div>
<div style="height:calc(100vmin - 32px);touch-action:none; position:relative;">
<input type="range" id="speed_s" min="-1000" max="1000" value ="0" class="slider" style="transform: translateX(-32%) rotate(-90deg); top:32%; width:min(90%, 80vmin);" oninput="update(this)" onmouseup="reset(this)" ontouchend="reset(this)">
<input type="range" id="steer_s" min="-1000" max="1000" value ="0" class="slider" style="top:25%; left:40%; width: 55%;" oninput="update(this)" onmouseup="reset(this)" ontouchend="reset(this)">
<button style="top:75%;left:min(35%, 35vmin);height:15%;width:20%; position:absolute; user-select:none;" onmousedown="move(true)" onmouseup="move(false)" ontouchstart="move(true)" ontouchend="move(false)" ontouchcancel="move(false)">Move</button>
<button id='b_auto' style="top:75%;left:75%;height:15%;width:20%; position:absolute;" onclick="auto(!is_auto)">Auto</button>
</div>
<script>

send_interval = 15; // ms

speed = 0; 
steer = 0;

is_move = false;  
is_auto = false;     

setTimeout(send_motors,1000);

async function send(msg) {
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => controller.abort(), 2000);

try {
  const response = await fetch("http://192.168.4.1/"+msg, {signal});
  if (!response.ok) throw new Error('error');
  const data = await response.text();
  if (data!='OK') info.innerText = data;
  if (info.style.color != "green") info.style.color = "green";
} catch (error) {
  info.style.color = "red";
}
if (msg[0] == 'M') setTimeout(send_motors, send_interval);
}

function send_motors() {
if (is_move) send('M'+i_move.value+","+steer); 
else if (is_auto) send('MA'+i_auto.value); 
else send('M'+speed+","+steer); 
}

function reset(el) {
el.value = 0;
update(); 
}

function update(){
auto(false);
speed = Math.round((speed_s.value*1 +1000)*(speed_m.value*2)/2000 - speed_m.value);
steer = Math.round((steer_s.value*1 +1000)*(steer_m.value*2)/2000 - steer_m.value);
}

function move(v){
auto(false);
is_move=v;
}

function auto(v){
if (v) is_move = false;
is_auto = v;
if (is_auto) b_auto.style.background='red'; else b_auto.style.background='';
}

</script>
`;

Укажите в нем в переменной sensor_type тип используемого датчика расстояния (1 - лазерный VL53L0X, 2 - ультразвуковой HC-SR04, 0 - никакой). Залейте в ESP8266 через Espruino IDE и введите в левой консоли

save()

Чтобы сохранить программу в памяти ESP8266.

После подключения к газонокосилке (пин D4 подключается к ближнему к черному проводу в шлейфе, как и в прошлый раз, а GND к черному проводу) и подачи питания, появится новая Wi-Fi сеть с названием "ESP8266".

Подключитесь к ней и откройте в браузере адрес http://192.168.4.1

С веб сервера на ESP8266 загрузится HTML интерфейс пульта управления.

Результат

Для удобства отладки, я использовал только шасси от газонокосилки.

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

Как видите, в принципе это работает. Но не очень надежно. Газонокосилка часто теряет слежение и уезжает вдаль в траву. Хотя иногда потом восстанавливается сама. Я позднее пытался (но недолго) проверить на более высокой траве. Было получше, но полностью проблему не решило.

В этих условиях с не очень высокой травой нужно было детектировать разницу в высоте около 4 см. Как показали наблюдения, показания датчиков как раз прыгают в этом диапазоне. Думаю, это из-за того что сигнал иногда попадает между травинками и поэтому длина пролета луча получается разной, вплоть до земли. Разницы между VL53L0X и HC-SR04 по точности я не заметил. Разве что VL53L0X время от времени зависал и требовал переподключения питания.

Можно попробовать сглаживать показания. Или поставить несколько датчиков расстояния в ряд, это тоже должно помочь.

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

В следующей части мы научим газонокосилку отличать скошенную траву от нескошенной с помощью нейросети.

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

Adblock test (Why?)