...

суббота, 7 марта 2020 г.

Управление Tion S3 и его подключение к умному дому

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

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

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

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

В спецификации на сайте сказано, что нужен телефон с Bluetooth 4.0 и выше. Приложений два: Magic air и Tion remote. Разбиралось второе, поскольку оно проще и в нем нет специфики работы с базовой станцией.

После декомпиляции быстро нашлись классы, отвечающие за взаимодействие (кстати, разные для версии S3 и S3 lite): приложение и бризер обмениваются пакетам по 20 байт, в начале и конце которого фиксированные символы (= и Z соответственно), второй байт в пакете — передаваемая команда (из enum).

Доступных действий три: pair, decode и encode. Ими и займемся.

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

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

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

command_PAIR = 5
command_REQUEST_PARAMS = 1
command_SET_PARAMS = 2
command_prefix = 61
command_suffix = 90

def create_command(self, command: int) -> bytearray:
    command_special = 1 if command == self.command_PAIR else 0
    return bytearray([self.command_prefix, command, command_special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, self.command_suffix])

и после передачи пакета с command_PAIR, к устройству можно подключаться в любой момент.

Большой проблемой для меня стало разобраться куда же этот пакет нужно передать: устройство танслирует несколько characteristic и из декомпилированного приложения я так и не понял что куда нужно писать. Но нашелся класс с описанием uuid и человеческими названиями этих uuid

public class BreezerUuids {
    public static String getDeviceUuid(@NonNull BreezerType breezerType) {
        return breezerType == BreezerType.BR_LITE ? "98f00001-3788-83ea-453e-f52244709ddb" : "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
    }

    public static String getWriteUuid(@NonNull BreezerType breezerType) {
        return breezerType == BreezerType.BR_LITE ? "98f00002-3788-83ea-453e-f52244709ddb" : "6e400002-b5a3-f393-e0a9-e50e24dcca9e";
    }

    public static String getNotifyUuid(@NonNull BreezerType breezerType) {
        return breezerType == BreezerType.BR_LITE ? "98f00003-3788-83ea-453e-f52244709ddb" : "6e400003-b5a3-f393-e0a9-e50e24dcca9e";
    }

    public static String getNotifyDescriptorUuid(@NonNull BreezerType breezerType) {
        BreezerType breezerType2 = BreezerType.BR_LITE;
        return "00002902-0000-1000-8000-00805f9b34fb";
    }
}

Как вскоре выяснилось, pair-пакет нужно писать в DeviceUUID. В итоге pair делается так:

uuid = "6e400001-b5a3-f393-e0a9-e50e24dcca9e"
def _get_pair_command(self) -> bytearray:
    return self.create_command(self.command_PAIR)
def pair(self, mac: str):
    self._btle.connect(mac, btle.ADDR_TYPE_RANDOM)
    characteristic = self._btle.getServiceByUUID(self.uuid).getCharacteristics()[0]
    characteristic.write(bytes(self._get_pair_command()))
    self._btle.disconnect()

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

response =  self._btle.getServiceByUUID(self.uuid).getCharacteristics()[0].read()

А на параметры 20 байт ответа разбираются вот так:

statuses = [ 'off', 'on' ]
modes = [ 'recirculation', 'mixed' ]

def _process_mode(self, mode_code: int) -> str:
    try:
      result = self.modes[mode_code]
    except IndexError:
      result = 'outside'
    return result

def _process_status(self, code: int) -> str:
    try:
      result = self.statuses[code]
    except IndexError:
      result = 'unknown'
    return result

def _decode_response(self, response: bytearray) -> dict:
    return {
      "heater": self._process_status(response[4] & 1),
      "status": self._process_status(response[4] >> 1 & 1),
      "sound": self._process_status(response[4] >> 3 & 1),
      "mode": self._process_mode(int(list("{:02x}".format(response[2]))[0])),
      "fan_speed": int(list("{:02x}".format(response[2]))[1]),
      "heater_temp": response[3],
      "in_temp": response[8],
      "filter_remain": response[10]*256 + response[9],
      "time": "{}:{}".format(response[11],response[12]),
      "request_error_code": response[13],
      "fw_version": "{:02x}{:02x}".format(response[16],response[17])
    }

Но тут выяснилось, что при последовательных чтениях данные не обновляются. Чтобы их обновить нужно прочитать данные из notify характеристики и послать команду command_REQUEST_PARAMS в write характеристику. После этого функция для получения актуальных данных с бризера начинает выглядеть примерно так:

uuid_write = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"
uuid_notify = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"

def _connect(self, mac: str,  new_connection = True):
    if new_connection:
      self._btle.connect(mac, btle.ADDR_TYPE_RANDOM)
      for tc in self._btle.getCharacteristics():
        if tc.uuid == self.uuid_notify:
          self.notify = tc
        if tc.uuid == self.uuid_write:
          self.write = tc
...
def get(self) -> dict:
    response = ""

    self.notify.read()
    self.write.write(self._get_status_command())
    response =  self._btle.getServiceByUUID(self.uuid).getCharacteristics()[0].read()

    return self._decode_response(response)

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

Получение данных с бризера — хорошо, но цель в том, чтобы ночью уменьшать мощность вентилятора (сильно шумит, зараза), управлять оборотами на основании данных mhz19 итд.

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

def _encode_mode(self, mode: str) -> int:
  return self.modes.index(mode) if mode in self.modes else 2

def _encode_status(self, status: str) -> int:
  return self.statuses.index(status) if status in self.statuses else 0

def _encode_request(self, request: dict) -> bytearray:
  settings = {**self.get(), **request}
  new_settings = self.create_command(self.command_SET_PARAMS)
  new_settings[2] = settings["fan_speed"]
  new_settings[3] = settings["heater_temp"]
  new_settings[4] = self._encode_mode(settings["mode"])
  new_settings[5] = self._encode_status(settings["heater"]) | (self._encode_status(settings["status"])<<1) | (self._encode_status(settings["sound"])<<3)
  return new_settings

Пишем это все в характеристику uuid == uuid_write.
Неясной осталась судьба еще пары байт пакета, работа с которыми в оригинальном приложении выглядит так:

public class Breezer3sSetParamsCommand extends BaseBreezerCommand {
...
    public void createCommandData() {
...
this.commandDataArr[i2 + 1] = (byte) 0;
        if (this.f) {
            byte[] bArr = this.commandDataArr;
            bArr[7] = (byte) (bArr[7] | 2);
        }
        this.commandDataArr[10] = (byte) this.e;

Результаты изысканий выше собраны в модуль для python3.
На коленке написан простой API сервер, который транслирует json-запросы, через модуль управления, в бризер и выдает json ответы.

В Home assistant сказано, что есть: rest сенсор, rest команды управления и компонент fan, управление которым делается через rest команды.

И все это добро запущено на малине.

Дальше в планах — отдельный компонент для Home assistant, чтобы обойтись без промежуточного API сервера, который очень нужен поскольку обещаниями интеграции бризеров в умный дом Тион кормит публику с 2016 года (если я правильно помню историю общения с пользователями в официальной группе ВК(https://vk.com/tion_ru)), платформ управления великое множество, а с rest API могут взаимодействовать все.

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

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

P.S.: Issue, PR и вопросы в коментах приветствуются: если возникнут вопросы — постараюсь помочь с интеграцией, в меру своих знаний и возможностей.

Let's block ads! (Why?)

Стас Афанасьев. Juno. Pipelines на базе io.Reader/io.Writer. Часть 1

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

Станислав Афанасьев (далее – СА): – Добрый день! Меня зовут Стас. Я приехал из Минска, из компании Juno. Спасибо, что в этот дождливый день пришли, нашли в себе силы выйти из дома.

Сегодня я с вами хочу поговорить на такую тему как построение пайплайнов (pipelines) Go на базе интерфейсов io.Reader/io.Writer. То, о чём я сегодня буду говорить, это, в общем-то, концепция интерфейсов io.Reader/io.Writer, для чего они нужны, как их правильно использовать и, самое главное, как их правильно реализовывать.

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

Прежде чем мы начнём, следует ответить на вопрос, зачем эти интерфейсы вообще нужны? Поднимите руки, кто с Go работает плотно (каждый день, через день)…

Отлично! У нас всё-таки Go-комьюнити. Думаю, многие из вас работали с этими интерфейсами, слышали о них, по крайней мере. Может, вы даже о них не знаете, но вы точно что-то должны были о них слышать.

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

io.Reader


Это очень простой интерфейс. Он состоит всего из одного метода – метода Read. Концептуально реализацией интерфейса io.Reader может быть сетевое соединение – например, там, где данных ещё нет, но они могут там появиться:

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

Концептуальная реализация интерфейса io.Reader – это доступ к каким-то данным. Все кейсы, которые я писал, поддерживаются методом Read. Он имеет всего один аргумент – это slice byte.
Здесь надо сделать одно замечание. Тех, кто пришёл в Go недавно или пришёл из каких-то других технологий, где не было похожего API (я один из таких), эта сигнатура немного путает. Кажется, что метод Read каким-то образом вычитывает этот slice. На самом деле всё наоборот: реализация интерфейса Reader вычитывает данные внутри себя и заполняет этот слайс (slice) теми данными, которые у этой реализации есть.

Максимальное количество данных, которое может быть вычитано по запросу методу Read, равно длине этого слайса. Обычная реализация возвращает столько данных, сколько она может вернуть на момент запроса, либо максимальное количество, влезающее в этот slice. Это говорит о то, что Reader можно вычитывать кусочками: хоть по байту, хоть по десять – как угодно. А клиент, который вызывает Reader, по возвращаемым значениям из метода Read, думает, как ему дальше жить.

Метод Read возвращает два значения:

  • количество вычитанных байт;
  • ошибку, если она произошла.

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

Io.Reader – How to?


Есть ровно два способа, чтобы ваши данные удовлетворяли интерфейсу Reader.

Первый – самый простой. Если у вас есть какой-то slice byte, и вы хотите сделать так, чтобы он удовлетворял интерфейсу Reader, можно взять реализацию какой-то стандартной библиотеки, которая уже удовлетворяет этому интерфейсу. Например, Reader из пакета bytes. На слайде выше видна сигнатура, как создаётся этот Reader.

Есть способ посложнее – реализовать самостоятельно интерфейс Reader. В документации есть примерно 30 строк с хитрыми правилами, ограничениями, которые необходимо соблюдать. Прежде чем мы обо всех поговорить, мне стало интересно: «А в каких случаях недостаточно стандартных реализаций (стандартной библиотеки)? Когда наступает тот момент, когда нам необходимо реализовывать интерфейс Reader самостоятельно»?

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

  • Самая популярная категория – connections. Это реализация как собственных протоколов, так и обёртки для уже существующих типов. Так, у Брэда Фитцпатрика есть проект Camlistore – там есть пример в виде statTrackingConn, который, в общем-то, является обычным Wrapper над типом con из пакета net (добавляет метрик к этому типу).
  • Вторая категория по популярности – это кастомные буферы. Здесь мне понравился один-единственный пример: dataBuffer из пакета x/net. Его особенность в том, что он хранит данные, порезанные на чанки (chunks), и при вычитывании проходится по этим чанкам. Если в чанке данные закончились – он переходит к следующему чанку. При этом он учитывает ту длину, то место, которое он может заполнить в переданном слайсе.
  • Ещё одна категория – это всевозможные progress-bars, подсчёты количества вычитанных байт с отправкой в метрики…

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

Правила документации


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

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

Так как это довольно строгий контракт, клиент может довериться тому количеству, которое приходит из реализации. В стандартной библиотеке существуют Wrapper’ы (например, bytes.Buffer и bufio). В стандартной библиотеке есть такой момент: некоторые реализации доверяют обёрнутым Reader’ам, некоторые не доверяют (об это мы ещё поговорим).

Bufio вообще ничему не доверяет – проверяет абсолютно всё. Bytes.Buffer доверяет абсолютно всему, что ему прилёт. Сейчас я продемонстрирую, что происходит в связи с этим…

Мы сейчас рассмотрим три возможных кейса – это три реализованных Reader’а. Они достаточно синтетические, полезны для понимания. Все эти Reader’ы мы будем вычитывать при помощи хелпера ReadAll. Его сигнатура представлена наверху слайда:

io.Reader#1. Пример 1


ReadAll – это хелпер, который принимает какую-то реализацию интерфейса Reader, вычитывает её всю и возвращает те данные, которые он вычитал, а также ошибку.

Первый наш пример – это Reader, который всегда будет возвращать -1 и nil в качестве ошибки, то есть такой NegativeReader. Давайте его запустим и посмотрим, что же будет:

Как известно, паника без причины – признак дурачины. Но кто в этом случае дурачина – я или byte.Buffer – зависит от точки зрения. У тех, кто пишет этот пакет и кто за ним следит, имеют разные точки зрения.

Что здесь произошло? Bytes.Buffer принял отрицательное количество байт, не проверил, что оно отрицательное, и внутренний буфер попытался отрезать по верхней границе, которую он получил – и мы получили выходит за границы slice.

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

Второй «пойнт» – в том, что по stack trace не понятно, что вообще произошло. Понятно, что мы вышли за границы слайса – ну и что? Когда у вас столь многослойный pipe и происходит такая ошибка, не с ходу понятно, что произошло. Так вот bufio стандартной библиотеки тоже «паникует» в этой ситуации, но делает более красиво. Он сразу пишет: «Я вычитал отрицательное количество байт. Делать больше ничего не буду – не знаю, что с этим делать».

А bytes.Buffer паникует как может. Я отправил issue в Golang с предложением добавить человеческую ошибку. Дня три мы обсуждали перспективы этого решения. Причина такова: исторически так сложилось, что разными людьми в разное время были приняты разные несогласованные решения. И сейчас мы имеем следующее: в одном случае мы не доверяем реализации вообще (проверяем всё), а в другом – доверяем полностью, нам по барабану, что оттуда придёт. Это не решённый вопрос, и мы об этом ещё поговорим.

io.Reader#1. Пример 2


Следующая ситуация: наш Reader будет возвращать всегда 0 и nil в качестве результатов. С точки зрения контрактов здесь всё законно – никаких проблем нет. Единственный нюанс: в документации написано, что реализации не рекомендуется возвращать значения 0 и nil, кроме того кейса, когда длина присланного slice равна нулю.

В реальной жизни такой Reader может доставить массу неприятностей. Так, мы возвращаемся к вопросу, должны ли мы доверять Reader’у? Например, в bufio встроена проверка: он последовательно читает Reader ровно 100 раз – если 100 раз возвращается такая пара значений, он просто возвращает NoProgress.

В bytes.Buffer ничего подобного нет. Если мы запустим этот пример, мы получим просто бесконечный цикл (ReadAll под капотом использует bytes.Buffer, а не сам вычитывает Reader):

io.Reader#1. Пример 2


Ещё один пример. Он тоже довольно синтетический, но полезен для понимания:

Здесь мы возвращаем всегда 1 и nil. Казалось бы, здесь тоже никаких проблем нет – всё законно с точки зрения контракта. Есть нюанс: если я запущу этот пример на своём компьютере, то он зависнет секунд через 30…

Связано это с тем, что клиент, который вычитывает этот Reader (т. е. bytes.Buffer), никогда не получает признака конца данных – вычитывает, вычитывает… Плюс к этому, он каждый раз получает один вычитанный байт. Для него это значит, что в какой-то момент заканчивается прелоцированный буфер, он элоцирует ещё – ситуация повторяет, и он элоцирует до бесконечности, пока не лопнет.

io.Reader#2. Возврат ошибки


Мы подходим ко второму важному правилу реализации интерфейса Reader – это возвращение ошибки. В документации оговорены три ошибки, которые реализация должна возвращать. Самая главная из них – это EOF.

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

Есть ещё одна ошибка, которая называется UnexpectedEOF. Если вдруг во время чтения Reader не может больше вычитывать данные, задумывалось, что он будет возвращать UnexpectedEOF. Но по факту эта ошибка используется только в одном месте стандартной библиотеки – в функции ReadAtLeast.

Ещё одна ошибка – NoProgress, о которой мы уже говорили. В документации так и написано: это – признак того, что интерфейс реализован фигово.

Io.Reader#3


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

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

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

io.Reader. Mistakes


В общем-то, по Reader’у это были основные важные правила. Есть ещё набор мелких, но они не такие важные и не приводят к такой ситуации:

Прежде чем мы пройдём всё, что касается Reader’а, надо ответить на вопрос: важно ли это, часто ли случаются ошибки в кастомных реализациях? Чтобы ответить на этот вопрос, я обратился к своей шпуле (spool) на 1000 репозиториев (а там получилось порядка 550 кастомных реализаций). Я глазами первую сотню посмотрел. Конечно, это не суперанализ, но какой есть…

Определил две самые популярные ошибки:

  • никогда не возвращается EOF;
  • слишком большое доверие к обёрнутому Reader’у.

Опять-таки, это проблема с моей точки зрения. А со стороны тех, кто смотрит за пакетом io, это не проблема. Мы об это ещё поговорим.

К одному нюансу я хотел бы вернуться. Смотрите:

Клиент ни в коем случае не должен интерпретировать пару 0 и nil как EOF. Это ошибка! Для Reader’а это значение – всего лишь возможность отпустить клиента. Так вот две ошибки, о которых я сказал, кажутся несущественными, но достаточно представить, что у вас в проде многослойный pipeline и в середину закралась маленькая, хитрая «багуля», то «подземный стук» не заставит себя ждать долго – гарантированно!

По Reader’у в принципе всё. Это были основные правила реализации.

io.Writer


На другом конце пайплайнов у нас есть io.Writer – то, куда мы данные, как правило, пишем. Очень похожий интерфейс: он тоже состоит из одного метода (Write), сигнатура у них сходная. С точки зрения семантики интерфейс Writer является более понятным: я бы сказал, что как слышится, так и пишется.

Метод Write принимает slice byte и записывает его, в общем-то, целиком. У него тоже есть набор правил, которым необходимо следовать.

  1. Первое из них касается возвращаемого количества записываемых байт. Я бы сказал, что оно не такое строгое, потому что я не нашёл ни одного примера, когда это приводило бы к каким-то критическим последствиями – например, к panic’ам. Это не очень строго, потому что есть следующее правило…
  2. Реализация Writer обязана возвращать ошибку всякий раз, когда количество записанных данных меньше, чем было прислано. То есть частичная запись не поддерживается. Это значит, что не очень-то и важно то, сколько байт было записано.
  3. Ещё одно правило: Writer ни в коем случае не должен модифицировать присланный slice, потому что клиент с этим слайсом ещё будет работать.
  4. Writer не должен удерживать этот slice (такое же правило есть и у Reader’а). Если вам нужны данные в своей реализации для каких-то операций, вы должны просто скопировать этот слай, и всё.

По Reader и Writer всё.

Дендрограмма


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

На этой дендрограмме есть все реализации всех интерфейсов пакета io. Эта дендрограмма нужна для того, чтобы просто понять: что и с чем можно склеиваться в пайплайнах, откуда и что можно вычитывать, куда можно записывать. Я на неё ещё буду ссылаться по ходу своего доклада, поэтому обращайтесь к QR-коду.

Пайплайны (pipelines)


Мы поговорили о том, что такое Reader, io.Writer. Теперь поговорим о том API, который существует в стандартной библиотеке для построения пайплайнов. Начнём с самых основ. Может, это кому-то даже будет неинтересно. Тем не менее это очень важно.

Мы будем вычитывать данные стандартного потока ввода (из Stdin’а):

Stdin представлен в Go глобальной переменной типа file из пакета os. Если вы бросите взгляд на дендрограмму, то заметите, что тип file реализует в том числе интерфейсы Reader и Writer.

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

Один нюанс относительно этого хелпера стоит заметить: ReadAll вычитывает Reader до конца, но окончание он определяет именно по EOF’у, по тому признаку окончания, о котором мы говорили.
Мы будем сейчас лимитировать количество данных, которые мы вычитываем из Stdin. Для этого в стандартной библиотеке существует реализация LimitedReader:

Я бы хотел, чтобы вы обратили внимание на то, как LimitedReader ограничивает вычитываемое количество байт. Можно было бы подумать, что эта реализация, этот Wrapper вычитает всё, что есть в Reader’е, который он оборачивает, а потом отдаст столько, сколько мы хотим. Но всё работает немного по-другому…

LimitedReader обрезает по верхней границе тот slice, который ему подают в качестве аргумента. И этот обрезанный слайс он передаёт в Reader, который оборачивает. Это наглядная демонстрация того, как регулируется длина вычитываемых данных в реализациях интерфейса io.Reader.

Возврат ошибки end of file


Ещё один интересный момент: обратите внимание, как эта реализация возвращает ошибку EOF! Здесь используются возвращаемые именованные значения, и они присваиваются теми значениями, которые мы получаем из обёрнутого Reader’а.

И если так происходит, что в обёрнутом Reader’е данных больше, чем нам нужно, мы присваиваем значения завёрнутого Reader’а – допустим, 10 байт и nil – потому что в обёрнутом Reader’е ещё есть данные. Но переменная n, которая уменьшается (в предпоследней строке), говорит, о том, что мы достигли «дна» – конца того, что нам нужно.

В следующей итерации клиент должен прийти ещё раз – на первом условии он получит EOF. Этот самый кейс, о котором я упоминал.

Продолжение будет совсем скоро…


Немного рекламы :)


Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас, оформив заказ или порекомендовав знакомым, облачные VPS для разработчиков от $4.99, уникальный аналог entry-level серверов, который был придуман нами для Вас:Вся правда о VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps от $19 или как правильно делить сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).

Dell R730xd в 2 раза дешевле в дата-центре Equinix Tier IV в Амстердаме? Только у нас 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ от $199 в Нидерландах! Dell R420 — 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — от $99! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки?

Let's block ads! (Why?)

Чтение на выходные: 12 материалов о подкастах, закате эпохи FM-радиостанций и приложениях для медитации

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


Фото Zoltan Fekeshazi / Unsplash

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

  • «Доброе утро, Вьетнам!»: строим своё интернет-радио. Этот материал поможет всем, кто хочет общаться со слушателями в режиме онлайн. Рассказываем, что нужно сделать, чтобы открыть свою интернет-радиостанцию с прямыми эфирами и круглосуточным вещанием. Проект мы рассматриваем в качестве хобби, поэтому бизнес-модель оставляем за скобками. Поможем разобраться с целями и задачами — ведь от этого напрямую зависит и то, какие надо покупать железки, и то, какой контент пойдет в эфир. Еще рассказываем о способах вещания и разнице между ретрансляцией и автодиджеем.

  • Что ненавидят радиослушатели и радиоведущие. Максимальной боли и ярости пост — откровения ведущего радиоэфира о том, что бесит его и коллег, а что на дух не переносит аудитория. Сообщения с SMS-порталов, плейлисты, вещание в регионах и роль ведущих в этом вопросе — все это в первой части материала. А во второй — переходим к болям самих работников пульта и микрофона — о слишком внимательных слушателях, о постоянных фанатах, которые вовсе не так милы, и о передаче приветов и поздравлений.


Фото david de la vega / Unsplash
  • Шесть мифов о радиоведущих. Эта профессия долгое время была окутана романтическим флёром, а фильмы «Рок волна» и «День радио» только его усилили. Конечно, оба фильма — скорее правда, нежели вымысел, но некоторые мифы хочется раз и навсегда развеять. В материале говорим о том, кто на самом деле читает по бумажке, сколько в действительности времени ведущие проводят на станции. Из других тем — кто сколько зарабатывает, можно ли прожить на радийную зарплату, так ли это легко — говорить в микрофон и как попасть в радиоэфир. Статья пригодится всем, кто мечтает попробовать себя в роли радиоведущего.

  • Радио — конец прекрасной эпохи. Лебединая песня радиовещания в FM-диапазоне. От падения объема аудитории до обслуживания и поддержания станции в рабочем виде. Почему всё это перестаёт работать также хорошо, как раньше. В конце материала говорим о том, что медленно убивает FM-вещание и сколько может продлиться эта агония.

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


Фото Eric Nopanen / Unsplash
  • Что происходит на рынке аудиоподкастов. Вновь возвращаемся к этому сверхпопулярному формату. Обсуждаем то, как подкасты трансформируются в медиа, в чём их преимущество перед более традиционными моделями дистрибуции аудиоконтента. Здесь и про график выхода передач, и про влияние дедлайнов на качество, и про концептуальность.

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

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



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

10 тематических подкастов о звуке, аудиотехнике, саундтреках и виниле
10 научно-популярных подкастов о звуке и работе в сфере звукозаписи
Что послушать про аудиотехнику: 15 подкастов


Let's block ads! (Why?)

[Из песочницы] МЭМС акселерометры, магнитометры и углы ориентации

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

Чтобы понять, на какие точности углов мы можем рассчитывать, нужно приложить некоторое количество усилий.

TL;DR: Описан небольшой скрипт для Octave/MATLAB, позволяющий оценить ошибки расчёта углов ориентации по измерениям МЭМС акселерометров и магнитометров. На входе скрипта — параметры датчиков из даташитов (и/или погрешности калибровки). Статья может быть полезна тем, кто начинает использовать инерциальные датчики в своих устройствах. Небольшой ликбез по датчикам прилагается. Ссылка на гитхаб тоже.
Сходу примем такие условия:

  • Мы хотим оценить углы ориентации неподвижного устройства.
    Почему?

    Ориентацию подвижного устройства просто по формулам не посчитать, нужно использовать хитрые алгоритмы.

  • Для оценки углов мы будем использовать измерения МЭМС акселерометров и магнитометров.

1. Краткий ликбез


Углы ориентации


Будем понимать под углами ориентации объекта углы Эйлера — крен (roll), тангаж (pitch), рыскание (yaw), связывающие собственную систему координат XYZ объекта и локальную систему координат восток-север-верх (ENU — East North Up). Углы roll, pitch, yaw обозначают поворот, который нужно совершить осям XYZ чтобы перейти в оси ENU. Соответственно, нулевые углы означают, что ось X объекта смотрит на восток, ось Y объекта смотрит на север, ось Z — вверх.

Порядок поворота осей — начиная с последнего угла: сначала на yaw (вокруг оси Z), потом на pitch (вокруг оси Y), потом на roll (вокруг оси X).

Акселерометр


Это датчик, измеряющий проекцию кажущегося ускорения на ось чувствительности. Кажущегося — потому что измеряет и силу тяжести тоже, даже в то время как акселерометр неподвижен. Проще всего представить акселерометр как грузик на пружинке, его выдаваемые измерения пропорциональны степени растяжения пружины. Если акселерометр покоится — пружина растянута лишь силой тяжести. Если ускоряется — то будет сумма сил: инерции грузика $inline$\left (F=m\overrightarrow{a}\right )$inline$ и силы тяжести $inline$\left (F_{g}=m\overrightarrow{g}\right )$inline$

Примем следующую модель измерений триады ортогональных (взаимно перпендикулярных) акселерометров:

$$display$$a_{XYZ}= m_{a} \cdot A_{XYZ}+b_{a}+n_{a},$$display$$

где $inline$a_{XYZ}$inline$ – измеряемое ускорение в ССК (собственной системе координат) XYZ, $inline$m_{a}$inline$ – матрица перекоса осей и масштабных коэффициентов акселерометра, $inline$A_{XYZ}$inline$ – вектор истинного ускорения в ССК XYZ, $inline$b_{a}$inline$ – вектор смещения нуля акселерометра, $inline$n_{a}$inline$ – шум измерений.

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

$$display$$m_{a}=\begin{bmatrix}1+m_{a,1,1} & m_{a,1,2} & m_{a,1,3}\\ m_{a,2,1}& 1+m_{a,2,2} & m_{a,2,3}\\ m_{a,3,1} & m_{a,3,2} & 1+m_{a,3,3} \end{bmatrix},$$display$$

где элементы, расположенные по главной диагонали ($inline$ 1+m_{a,1,1}, 1+m_{a,2,2}, 1+m_{a,3,3}$inline$) — это масштабные коэффициенты и их погрешности по трём осям акселерометра, а остальные элементы матрицы — перекосы осей акселерометра.
Выбор параметров акселерометра из даташита

Акселерометр MPU-9250


  • Смещение нуля акселерометра — Zero-G Initial Calibration Tolerance ($inline$\pm60mg$inline$ для компонент $inline$X, Y$inline$, $inline$\pm80mg$inline$ для компоненты $inline$Z$inline$) — для расчётов переводим в единицы $inline$g$inline$ домножив на $inline$10^{-3};$inline$
  • Погрешность масштабного коэффициента — Initial Tolerance ($inline$\pm3\%$inline$) — выражается в процентах. Для расчётов надо перевести в разы, домножив на $inline$10^{-2};$inline$
  • Перекосы осей — Cross Axis Sensitivity ($inline$\pm2\%$inline$) — также умножаем на $inline$10^{-2};$inline$
  • Спектральная плотность мощности шума акселерометра — Noise Power Spectral Density $inline$\left (300\frac{\mu g}{\sqrt{Hz}} \right )$inline$ — переводим числитель в $inline$g$inline$ домножая все на $inline$10^{-6};$inline$
  • Полоса пропускания — Low Pass Filter Response $inline$\left (5-260 Hz\right )$inline$ — приведены границы, в пределах которых её можно изменять. Установим максимальную полосу. Все равно ошибки будут определяться не шумами;

Зная спектральную плотность мощности шума и полосу пропускания датчика можно рассчитать СКО шума на выходе датчика:

$$display$$\sigma _{noise}=G_{0}\cdot\sqrt{\Pi_{noise}};$$display$$


Акселерометр ADIS16488A:


  • Смещение нуля — Bias Repeatability ($inline$\pm 16mg$inline$) — переводим в $inline$g$inline$ домножая на $inline$10^{-3};$inline$
  • Погрешность масштабного коэффициента — (Sensitivity) Repeatability ($inline$\pm 0.5\%$inline$) — переводим из процентов в разы;
  • Перекосы осей — Misalignment Axis to frame ($inline$\pm1^{\circ}$inline$) — в градусах, переводим в разы (радианы, поскольку величины малые);
  • Спектральная плотность мощности шума — Noise Density $inline$\left ( 0.063\frac{mg}{\sqrt{Hz}}rms \right )$inline$ — переводим числитель в $inline$g;$inline$
  • Полоса пропускания — $inline$\left (3dB Bandwidth\right)$inline$ — выберем такой же, как у MPU-9250;


Магнитометр


Датчик, который измеряет проекцию индукции магнитного поля на ось чувствительности. Магнитометру свойственны искажения hard-iron и soft-iron. Hard-iron искажение — это аддитивный эффект, когда к измеряемому полю добавляется постоянная составляющая. Причиной может быть, например, действие постоянного магнита или собственное смещение нуля датчика. Искажение soft-iron — мультипликативный эффект, отражающий изменение направления и/или ослабление вектора магнитной индукции. Этот эффект может быть вызван наличием металлического предмета в непосредственной близости от магнитометра или же собственными искажениями датчика — погрешностью масштабного коэффициента или перекосом его оси чувствительности.
Примем модель измерений триады магнитометров:

$$display$$m_{XYZ}=S_{m}\cdot M_{XYZ}+b_{m}+n_{m},$$display$$

где $inline$m_{XYZ}$inline$ – измерения магнитометра в ССК XYZ, $inline$S_{m}$inline$ – диагональная матрица перекоса осей и масштабных коэффициентов (которая описывает эффект soft–iron), $inline$M_{XYZ}$inline$ – вектор истинной магнитной индукции в ССК, $inline$b_{m}$inline$ – смещение нулей магнитометра (описывает эффект hard–iron), $inline$n_{m}$inline$ – шум измерений.
Матрица перекоса осей и масштабных коэффициентов магнитометра:

$$display$$S_{m}=\begin{bmatrix}1+S_{m,1,1} & S_{m,1,2} &S_{m,1,3}\\ S_{m,2,1}& 1+S_{m,2,2} & S_{m,2,3}\\ S_{m,3,1} & S_{m,3,2}&1+ S_{m,3,3} \end{bmatrix},$$display$$

элементы, расположенные на главной диагонали ($inline$S_{m,1,1}, S_{m,2,2}, S_{m,3,3}$inline$) — масштабные коэффициенты и их погрешности по трём осям магнитометра, остальные элементы матрицы — перекосы осей магнитометра. Все элементы матрицы также учитывают эффект soft-iron.
Выбор параметров магнитометра из даташита

Магнитометр MPU-9250


В даташите нужных нам параметров нет, поэтому предположим, что магнитометр откалиброван и возьмем следующие числа:
  • смещение нуля — $inline$(1\mu T);$inline$
  • погрешность масштабных коэффициентов — $inline$(5\%);$inline$
  • перекосы осей — предположим, что они такие же, как у акселерометров — $inline$(\pm2\%);$inline$
  • шум на выходе — $inline$(0.6\mu T);$inline$

Магнитометр ADIS16488A


  • Смещение нуля — Initial Bias Error $inline$\left (\pm15 mgauss = 1.5 \mu T \right )$inline$ — будем считать, что мы его откалибровали до $inline$(0.5 \mu T)$inline$;
  • Погрешность масштабного коэффициента — Initial Sensitivity Tolerance $inline$\left (2\% \right );$inline$
  • Перекосы осей — Misalignment Axis to axis $inline$\left (0.35^{\circ} \right )$inline$ — в градусах, переводим в разы (радианы, так как величина маленькая);
  • Спектральная плотность мощности шума — Noise Density $inline$\left (0.042\frac{mgauss}{\sqrt{Hz}} \right )$inline$ — переводим в $inline$\left (\frac{Tesla}{\sqrt{Hz}} \right );$inline$
  • Полоса пропускания — возьмем для модели значение $inline$260 Hz;$inline$


Расчет углов ориентации


Благодаря наличию на Земле силы тяжести, акселерометры «чувствуют» направление вниз. Их измерения используются для расчета углов крена и тангажа. Формулы для расчёта можно найти тут. Третий — угол рыскания (а в данном случае — магнитного азимута), может быть определен благодаря наличию у Земли магнитного поля. Вектор индукции магнитного поля измеряется магнитометрами и их измерения участвуют в расчете угла рыскания. Нужно отметить, что в расчёте магнитного азимута используются измерения магнитометра, пересчитанные в плоскость. Здесь можно найти формулу для расчёта магнитного азимута.

$$display$$roll=atan\left ( \frac{a_{Y}}{a_{Z}} \right ),$$display$$

$$display$$pitch=atan\left ( \frac{-a_{X}}{\sqrt{a_{Y}^{2}+a_{Z}^{2}}} \right ),$$display$$

$$display$$yaw=atan2\left ( \frac{m_{E}}{m_{N}} \right ),$$display$$

где $inline$atan2$inline$ — функция полного арктангенса, $inline$a_{X}$inline$, $inline$a_{Y}$inline$, $inline$a_{Z}$inline$ — измерения акселерометра по трём осям в ССК, $inline$m_{E}$inline$, $inline$m_{N}$inline$ — измерения магнитометра по осям X', Y' (измерения магнитометров пересчитаны в плоскость).

2. Ошибки оценивания углов ориентации


Описание алгоритма


  • Сформируем массивы случайных углов Эйлера roll, pitch, yaw. Они будут задавать наборы вариантов истинной ориентации объекта в модели.
    Зачем много углов?

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

  • Из случайных углов roll, pitch, yaw формируется матрица преобразования из ССК XYZ в ЛСК ENU:

    $$display$$C_{XYZ}^{ENU}=\begin{vmatrix} cy\cdot cp &-cr\cdot sy+sr\cdot cy\cdot sp &sr\cdot sy+cr\cdot cy\cdot sp \\ sy\cdot cp &cr\cdot cy+sr\cdot sy\cdot sp & -sr\cdot cy+cr\cdot sy\cdot sp \\ -sp &sr\cdot cp &cr\cdot cp \end{vmatrix},$$display$$

    где $inline$cr=\cos (roll)$inline$, $inline$sr=\sin(roll)$inline$, $inline$cp=\cos(pitch)$inline$, $inline$sp=\sin(pitch)$inline$, $inline$cy=\cos(yaw)$inline$, $inline$sy=\sin(yaw)$inline$.
  • Используя данную матрицу можно получить выражение для истинных ускорений в ССК:

    $$display$$A_{XYZ}=\left ( C_{XYZ}^{ENU} \right )^{T}\cdot \begin{vmatrix} 0\\ 0\\ -1\\ \end{vmatrix},$$display$$


    $inline$\begin{vmatrix} 0\\ 0\\ -1\\ \end{vmatrix}$inline$ — вектор, определяющий направление гравитационного ускорения, выраженный в единицах g, $inline${(C_{XYZ}^{ENU} )}^{T}$inline$ — матрица преобразования координат из ЛСК в ССК (обратная матрице преобразования из ССК в ЛСК).
  • Применяем модель измерения акселерометра:

    $$display$$a_{XYZ}=\left ( I+m_{a} \right )\cdot A_{XYZ}+b_{a}+n_{a},$$display$$

  • По измерениям акселерометра рассчитываются новые углы крена и тангажа (оценки) по формулам:

    $$display$$roll'=atan \left ( \frac{a_{Y}}{a_{Z}} \right ),$$display$$

    $$display$$pitch'=atan\left ( \frac{-a_{X}}{\sqrt{a_{Y}^{2}+a_{Z}^{2}}} \right ).$$display$$

  • Также необходимо сформировать матрицу пересчета в «горизонт» из этих углов, для этого воспользуемся функцией rpy2mat:

    $$display$$C_{XYZ}^{XYZ'}=rpy2mat\left ( \begin{bmatrix} roll'\\ pitch'\\ 0 \end{bmatrix}^{T} \right ),$$display$$

    где углы roll' и pitch' — это углы, рассчитанные по измерениям акселерометра, а третий угол — нулевой.
  • Возьмем вектор истинных магнитных плотностей в ЛСК ENU и пересчитаем его в ССК XYZ:

    $$display$$M_{XYZ}= {(C_{XYZ}^{ENU} )}^{T}\cdot M_{ENU}.$$display$$

  • Применяем модель измерений магнитометра:

    $$display$$m_{XYZ}=S_{m}\cdot M_{XYZ}+b_{m}+n_{m}.$$display$$

  • Осталось пересчитать измерения магнитометра из ССК в «горизонт»:

    $$display$$m_{XYZ'}=C_{XYZ}^{XYZ'}\cdot m_{XYZ}.$$display$$

  • По «горизонтированным» измерениям магнитометра расcчитывается угол магнитного азимута:

    $$display$$yaw'=atan2\left ( \frac{m_{Y'}}{m_{X'}} \right ).$$display$$

  • Ошибки оценивания углов ориентации рассчитываются как разность между истинными углами roll, pitch, yaw и рассчитанными по измерениям датчиков — roll', pitch', yaw'.

3. Результаты — расчет погрешностей оценки углов


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

В таблице ниже — максимальные значения полученных ошибок:


Совместное влияние погрешностей акселерометра и магнитометра на ошибки оценивания углов ориентации:
  • Вот так выглядят ошибки оценивания крена в зависимости от значений крена и тангажа:

  • Ошибки оценивания тангажа в зависимости от значений крена и тангажа:

  • Ошибки оценивания магнитного азимута от углов крена и тангажа:

  • Ошибки оценивания магнитного азимута от углов крена и магнитного азимута:

  • Ошибки оценивания магнитного азимута от углов тангажа и магнитного азимута:


Как можно заметить - величина ошибок растёт с приближением к границе диапазонов измерений углов. Почему?
Это можно понять из рисунка ниже.

Допустим мы поворачиваем ось чувствительности Z ($inline$z1\rightarrow z2$inline$) акселерометра так, чтобы проекция силы тяжести на эту ось стала меньше ($inline$g'\rightarrow g"$inline$). Значение проекции силы тяжести плюс погрешность акселерометра дадут область возможных значений измерения (розовая область). Погрешность оценки угла при этом возрастает ($inline$\Delta _{1}\rightarrow \Delta _{2}$inline$). Таким образом, при уменьшении проекции вектора силы тяжести на ось чувствительности ошибка акселерометра начинает вносить бОльшую ошибку в оценку угла.


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

Итог


  • Разработана модель, позволяющая оценивать погрешности расчёта углов ориентации. Углы ориентации рассчитаны по измерениям акселерометров и магнитометров. В расчете погрешности углов учитываются модели погрешностей этих датчиков.
  • Ошибки оценивания углов ориентации являются функциями одновременно всех углов ориентации. При этом максимальные значения ошибок наблюдаются на границах диапазонов измерений углов.

Спойлер - дисклеймер:
  • Не рекламируем и не рекомендуем покупать эти датчики (они уже довольно старые).
  • Не учитываем влияние нелинейности измерений, влияние вибрации, нестабильности и т.д. — используем лишь первое приближение к модели ошибок датчиков.

Литература


Let's block ads! (Why?)

Как защитить свои активы во время коррекций на фондовом рынке?

Изображение: Unsplash

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

Что такое коррекция?


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

С другой точки зрения, коррекция возникает из-за большого количества стоп-ордеров, делающих выгодным движение цены в направлении их исполнения, после чего цена возвращается к основному тренду. Кроме того, коррекция определяется как снижение на 10% одного из основных фондовых индексов США (S&P 500 или Dow Jones Industrial Average).

Если говорить о значительных рыночных коррекций, то с 1980 по 2018 гг. на американском рынке произошло 36 коррекций. Из них лишь 5 перешли в «медвежьи рынки», то есть они долгое время снижались. Это принесло немало огорчений инвесторам, которые оказались в длинных позициях в те моменты. Выходит, что около 86% снижений являются обычными коррекциями, и рынок в дальнейшем успешно восстанавливается. А вот в оставшихся 14% случаев падение бывает более серьезным и длительным.

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

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

Но здесь одно “НО”. Это происходит только в том случае, если акция не попадет на медвежий рынок, опустившись на 20% от своего максимума. Если потери растягиваются до 20%, то впереди болезненные последствия и больше времени на восстановление.

Способы защиты от последствий коррекций на бирже


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

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

Модельный портфель


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

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

Индивидуальный инвестиционный счет (ИИС)


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

Аналитиками ITIcapital были разработаны стратегии разных уровней риска и размером потенциальной доходности. С ними ИИС может прибавлять на счет примерно 25% или 33% в год.
В течение одного календарного года на счет можно добавить не более 1 млн рублей. Получить налоговый вычет 13% от суммы на счёте можно не более, чем с 400 тыс. рублей в год.

Структурный продукт


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

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

Пример. Если коэффициент участия равен 70%, а цена базового актива изменилась на 10%, инвестор получит 7%. Это чуть меньше, чем при покупке базового актива, но так гарантируется сохранность капитала при неблагоприятном сценарии движения актива.

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

Заключение


Долгосрочный успех при биржевых инвестициях состоит в сохранении капитала. Одно из главных правил Уоррена Баффета – никогда не теряйте деньги.

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

Читайте обзоры, аналитику рынков и инвестидеи в Telegram-канале ITI Capital

Let's block ads! (Why?)

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

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

Официальный ответ представителя Альфа-банка, который был дан клиентам только через несколько часов, после начала блокировки карт:


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

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

«Сейчас мы убедились, что угрозы нет, карты разблокировали и перевыпустили для полной безопасности. Новые карты будут готовы на следующей неделе», — пояснили в Альфа-банке.

Буквально три дня назад, 4 марта 2020 года, Ашот Оганесян, основатель и технический директор компании DeviceLock, опубликовал на Хабре статью «Анализ утечки второго порядка: когда утекает у тех, кто ворует данные у банка», в которой была информация о том, что в сети некоторое время были доступны персональные данные более ста тысяч клиентов одного из банков, включая номера счета отправителя, номера банковской карты получателя и срок ее действия, валюту и тип счета, ФИО, пол, номер мобильного телефона, адрес электронной почты, место работы (название и ИНН), а также потенциально возможно присутствие и других данных (паспорт, данные по кредитам и зарплате, кодовое слово, наличие загранпаспорта и ДМС и т.п.).

В конце своей публикации Оганесян пояснил, что он «незамедлительно уведомил банк и ЦБ в лице ФинЦЕРТ (подразделении ЦБ, которое отслеживает и реагирует на атаки и утечки данных)». По словам Оганесяна, «банк, как ни странно, особого интереса к файлам не проявил и архив не запросил, а вот ФинЦЕРТ – наоборот, запросил и получил все необходимые для анализа инцидента файлы».

Ранее в начале ноября 2019 года в СМИ сообщалось о появлении в продаже в интернете данных примерно 3,5 тыс. клиентов Альфа-банка и около 3 тыс. клиентов «АльфаСтрахования». Представители Альфа-банка подтвердили утечку данных только пятнадцати своих клиентов.

Let's block ads! (Why?)

[Перевод] Складские роботы, использующие ИИ для сортировки предметов, готовы к работе

Стартап из Беркли Covariant вышел из тени и считает, что его роботы готовы к выходу в мир


Летом 2018 года небольшой стартап из Беркли, разрабатывающий роботов, столкнулся с трудным заданием. Компания Knapp, крупный поставщик технологий складской логистики, искала новую роботизированную руку, управляемую ИИ, способную захватывать как можно больше различных типов предметов. Каждую неделю, восемь недель подряд, компания отправляла стартапу список из всё более сложных предметов – непрозрачных коробок, прозрачных коробок, упаковок лекарств, носков – покрывавший диапазон продукции клиентов компании. Стартап покупал подобные предметы, а потом через неделю отправлял видео, на котором их роборука перекладывала предметы из одной серой корзины в другую.

К концу задания руководство Knapp было сражено. Они уже лет шесть-семь безуспешно давали подобные задания многим стартапам, и ожидали провала и на этот раз. Но вместо этого в каждом видео роборука стартапа перекладывала каждый предмет с идеальной точностью и подходящей скоростью.
«С каждым следующим продуктом мы ожидали неудачи, поскольку задача становилась всё более сложной», — говорит Питер Пачвейн, вице-президент по инновациям в Knapp, штаб-квартира которой находится в Австрии. «Однако оказалось, что они достигли успеха, и всё работало. Мы никогда ещё не видели такой качественной работы ИИ».

Сейчас Covariant вышел из тени и объявляет о совместной работе с Knapp. Его алгоритмы уже работают в роботах Knapp на складах двух клиентов компании. Один из них принадлежит немецкому производителю электротоваров Obeta, и роботы работают там с сентября. Сооснователи стартапа говорят, что Covariant уже близок к заключению ещё одной сделки с другим промышленным гигантом, производящим роботов.

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

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


Роботизированная рука в офисе Covariant

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

За последние несколько лет исследовательские лаборатории достигли невиданных успехов в комбинировании ИИ и робототехники, добиваясь подобной ловкости, однако перенести эти достижения в реальный мир – это совсем другая задача. В лабораториях допустима точность в 60-70%; на производстве этого недостаточно. И даже с точностью в 90% роботизированная рука будет «предложением с потерей ценности», говорит Питер Аббил, сооснователь и главный учёный Covariant.

Аббил и Чен оценивают, что для того, чтобы на самом деле отбить инвестиции, робот должен достигать точности в 99-99,5%. Только тогда он сможет работать без частого вмешательства человека и риска замедлить конвейер. Однако только недавний прогресс в глубоком обучении, и в частности, в обучении с подкреплением, позволил достичь подобного уровня точности.

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

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

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

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

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

Пачвейн из Knapp говорит, что с тех пор, как компания перешла на платформу Covariant, её роботы перешли от возможности поднимать 10-15% предметов из ассортимента Obeta до возможности поднимать порядка 95% предметов. Последние 5% — это такие особо хрупкие вещи, как стекло, с которыми всё ещё позволяют работать только людям. «И это не проблема, — добавляет Пачвейн. – В будущем типичным устройством склада будут 10 роботов и один человек. Таков план». Благодаря совместной работе Knapp распространит своих роботов с софтом от Covariant на склады своих клиентов в течение нескольких лет.

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

На сегодня Covariant получил уже $27 млн от инвесторов, среди которых такие светила ИИ, как обладатели премии Тьюринга Джоффри Хинтон и Ян Лекун. Стартап хочет заниматься не только поднятием объектов, но и всем спектром работы складов, от разгрузки грузовиков до упаковки коробок и сортировки на стеллажах. Также у стартапа есть идеи о выходе за пределы складов и входе в другие области промышленности.

Но конечная цель Аббила ещё выше: «Долгосрочная идея компании – решить все проблемы в области ИИ-роботизации».

Let's block ads! (Why?)

Pinebook Pro: личные впечатления от использования ноутбука

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


Что по срокам?

Устройства делают партиями, точнее даже парами партий: с ANSI и ISO клавиатурами. В начале отгружают ISO версию, а затем (примерно через неделю) партию с клавиатурами ANSI. Заказ я оформил 6-го декабря, из Китая ноутбук был отгружен 17 января. Как я уже говорил в предыдущей публикации, доставки в Россию именно этого ноутбука нет, поэтому пришлось оформлять доставку через посредника в США. 21 января посылка поступила на склад в США и была отправлена в Санкт-Петербург. 29 января посылка поступила в ПВЗ, но за полчаса до его закрытия, поэтому забрал я ноутбук уже утром 30-го января.


Что по стоимости?

За сам ноутбук и доставку его в США я заплатил 232.99$ (15`400,64 в рублях на тот момент). А за пересылку из США в Санкт-Петербург 42.84$ (2`878,18 в рублях на тот момент).

Насчет пересылки хочется отметить пару моментов:


  • После недолгого сравнения был выбран Pochtoycom (не реклама, вероятно, есть и более дешевые посредники).
  • При пополнении счета у посредника был начислен некоторый процент сверху (сейчас не помню точно сколько: не много, но неприятный привкус остался).
  • Мне не пришлось платить пошлину за ввоз устройства, потому что его цена умещается в лимит €200 беспошлинного ввоза.
  • В стоимость пересылки мною была включена дополнительная (что-то около 3$) услуга по заворачиванию посылки в дополнительный слой полиэтиленовой пленки. Это перестраховка оказалась по факту не нужной (поэтому я бы сказал, что такой ноутбук с доставкой обойдется в ~18 тысяч рублей), так как родная упаковка достаточно многослойная.

Внутри пакета DHL оказался пакет с пупырчатой пленкой, внутри которого уже была картонная коробка и адаптер питания. Внутри первой коробки была вторая картонная коробка. И уже внутри второй коробки лежит quick start guide (в виде распечатанного листа A4) и само устройство в тонком амортизирующем пакете.


Фото упаковки

Тачпад

Первое, что сильно портит впечатление об устройстве, это тачпад. Как справедливо заметил andreyons в комментариях к предыдущей публикации:


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

От себя я бы сказал, что у тачпада присутствует "дрифт". То есть в конце жеста курсор еще самостоятельно уезжает на несколько пикселей. Кроме обновления прошивки сильно улучшает ситуацию (но, к сожалению, не решает до конца) настройка параметра MinSpeed (в etc/X11/xorg.conf):

    Section "InputClass"
        Identifier "touchpad catchall"
        Driver "synaptics"
        MatchIsTouchpad "on"
        MatchDevicePath "/dev/input/event*"

        Option "MinSpeed" "0.25"
    EndSection

Или тоже самое с помощью команды:

synclient MinSpeed=0.25

Рекомендация по настройке уже перекочевала из ветки форума (Trackpad lack of fine movement and overrun ruining experience) в wiki-документацию.


Клавиатура

Клавиатура в целом мне понравилась. Но есть несколько моментов, которые являются скорее придирками с моей стороны:


  • Ход клавиш непривычно долгий (то есть клавиши высокие)
  • Нажатия шумные

Вариант ISO (UK) раскладки для меня слишком непривычен, поэтому для себя я заказал ANSI (US) раскладку. Ниже пойдет речь именно о ней:

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


  • Нет клавиши контекстного меню (ни отдельной, ни Fn +)
  • Нет отдельной клавиши Delete (есть сочетание клавиш Fn + Backspace)
  • Клавиша питания расположена в правом верхнем углу, справа от F12

Я понимаю, что тут дело привычки, но мое личное предпочтение: клавиша (лучше — кнопка) питания должна быть отдельно от клавиш клавиатуры. А на освободившимся месте я бы предпочел видеть отдельную клавишу Delete. Контекстное меню для меня удобно видеть на сочетании Fn + правый Ctrl.


Подключение внешнего экрана

До того, как ноутбук попал ко мне в руки я был убежден, что китайский адаптер с USB Type C на HDMI, купленный на aliexpress для Nintendo Switch (если что — про опасность таких устройств я знаю), будет работать с Pinebook Pro. Что-то вроде этого:

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


Here are some selection criteria for successfully using the USB C alternate mode for video:
  • The device must use USB C alternate mode DisplayPort. Not USB C alternate mode HDMI, or other.
  • The device can have a HDMI, DVI, or VGA connector, if it uses an active translater.

То есть нужен адаптер с USB Type C именно на DisplayPort, который может уже потом давать вывод на HDMI, DVI и тому подобное. Сообщество тестирует разные адаптеры, результаты можно найти в сводной таблице. В общем нужно быть готовым к тому, что произвольный USB Type C док не заработает или заработает не полностью.


Операционная система

С завода ноутбук приходит с Debian (MATE). Из коробки в лоб не заработало:


  • Перенос системной панели к левому краю экрана: после перезагрузки пропадает кнопка главного меню, на нажатие клавиши Super (Win) нет никакой реакции.
  • Для одного из Android-смартфонов не заработал протокол MTP. Установка других пакетов для работы с MTP проблемы не решило: телефон упорно не видится ноутбуком.
  • Для некоторых видео на youtube не работал звук в FireFox. Как оказалось проблема уже была обсуждена на форуме и решена.

Плюс достаточно странным для меня показалось то, что дефолтная ОС оказалась 32-х битной: armhf, а не arm64.

Поэтому недолго думая я перешел на использование 64-х битной Manjaro ARM с Xfce в качестве рабочего стола. Я несколько лет не имел дело с Xfce, да и до этого в основном пользовался Xfce в качестве среды рабочего стола для *BSD-систем. Если коротко — очень понравилось. Стабильно, отзывчиво, конфигурируемо.

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


Тесты питания

Сразу хочу сказать, что я подозреваю, что у меня что-то не в порядке с системой питания. Мой ноутбук в режиме ожидания разряжается (от 100% до 0) меньше чем за двое суток (часов за 40). Тестировал на Debian, потому что на Manjaro ARM suspend-режим пока не работает — Manjaro ARM 19.12 Official Release — PineBook Pro:


Known Issues:
  • Suspend does not work

Но по опыту использования могу заметить, что без подключенного адаптера питания в режиме неполной нагрузки я спокойно использую ноутбук в течении дня без подзарядки. В качестве нагрузочного теста питания я поставил потоковое видео с youtube (https://www.youtube.com/watch?v=5cZyLuRDK0g) по WiFi со стопроцентной яркостью экрана. Устройство проработало от батареи чуть менее трех часов. То есть на "посмотреть фильм" вполне хватит (хотя я все же ожидал немного лучших результатов). Греется при этом нижняя часть ноутбука весьма прилично.


Зарядка

К слову о зарядке. Адаптер питания выглядит так:

Длина провода питания чуть больше метра, что маловато при сравнении с типичными ноутбуками.

До того, как я получил устройство я почему-то считал, что ноутбук будет заряжаться от USB Type C. И вроде бы пока ноутбук включен зарядка через USB Type C должна работать — Charging via USB-C. Но у меня аккумулятор от USB Type C не заряжается (что подкрепляет мои опасения о том, что в системе питания моего экземпляра что-то не в порядке).


Звук

Звук плохой. Откровенно говоря, хуже качества звука (или даже такое же) я просто не видел. Даже у 10-дюймового планшета или просто современного смартфона качество звука, воспроизводимого через динамики устройства, намного лучше. Для меня это совсем не критично, но качество звука неприятно удивило.


Резюме

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

На момент появления у меня ноутбука я посмотрел в текущей рознице альтернативы. За те же деньги есть несколько моделей какого-нибудь условного Irbis, и по одной модели от Acer и Lenovo (с Windows 10 на борту). В моем случае я ни капли не жалею, что взял именно Pinebook Pro, но, например, для своих родителей (очень далеких от компьютерной среды и живущих географически далеко от меня) я бы взял что-то другое.

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

Текущая обстановка (COVID-19) к сожалению привела к тому, что график производства на текущий момент заморожен. На официальном форуме появились ветки о продаже Б/У моделей. Зачастую продавцы ставят цену, равную стоимости нового устройства и оплаченной доставки (220-240$). Но особо предприимчивые личности продают свои экземпляры на аукционе за 350$. Что говорит о наличии интереса к этим устройствам, а в случае с Pine64 комьюнити определяет многое. На мой взгляд жизненный цикл Pinebook Pro будет долгим и успешным (хотя бы для конечных пользователей).

Let's block ads! (Why?)

Подстава с NVMe на Линуксе

Доброго времени суток.

Хотел обратить внимание сообщества на характерную особенность Linux при работе с несколькими NVMe SSD в одной системе. Особенно актуально будет для тех кто любит делать из NVMe программные RAID массивы.
Надеюсь, что информация приведенная ниже поможет уберечь ваши данные и избавит от досадных ошибок.
Все мы привыкли к следующий логике Linux при работе с блочными устройствами:
Если устройство называется /dev/sda то разделы на нем будут /dev/sda1, /dev/sda2, и т.д.
Для просмотра SMART атрибутов мы используем что-то вроде smartctl -a /dev/sda, а форматируем, и в массивы добавляем уже разделы, вроде /dev/sda1.

Все мы привыкли к аксиоме, что /dev/sda1 располагается на /dev/sda. И, если в один день SMART покажет что /dev/sda почти сдох, — именно /dev/sda1 мы будем выкидывать из RAID массива на замену.

Оказывается, при работе с NVMe Namespaces это правило не работает. Пруф:

nvme list && ( smartctl -a /dev/nvme0 && smartctl -a /dev/nvme1 && smartctl -a /dev/nvme2 ) | grep Serial
Node SN Model Namespace Usage Format FW Rev
---------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1 S466NX0K72XX06M Samsung SSD 970 EVO 500GB 1 96.92 GB / 500.11 GB 512 B + 0 B 1B2QEXE7
/dev/nvme1n1 S466NX0K43XX48W Samsung SSD 970 EVO 500GB 1 91.00 GB / 500.11 GB 512 B + 0 B 1B2QEXE7
/dev/nvme2n1 S466NX0K72XX01A Samsung SSD 970 EVO 500GB 1 0.00 B / 500.11 GB 512 B + 0 B 1B2QEXE7
Serial Number: S466NX0K72XX06M
Serial Number: S466NX0K72XX01A
Serial Number: S466NX0K43XX48W

Внимательный читатель по сопоставлению серийных номеров заметит, что /dev/nvme1n1 на самом деле располагается на /dev/nvme2, и наоборот.

Р.S.

Желаю вам никогда не удалять из RAID массива последний живой NVMe SSD.

Let's block ads! (Why?)

«Мастерхост» урегулировал конфликт с бывшим владельцем дата-центра

Вечером 5 марта 2020 года хостинг-провайдер «Мастерхост» сообщил об урегулировании конфликта с экс-собственником компании, который фактически захватил дата-центр компании и не менее четырех дней саботировал работу провайдера. В результате инцидента большое количество клиентов «Мастерхоста» не смогли получить доступ к своим интернет-ресурсам. Среди пострадавших клиентов были как крупные государственные корпорации, включая «Роскосмос», а также ряд министерств и ведомств РФ, так и тысячи небольших компаний — не работали сайты ряда торговых центров, девелоперов и крупных риелторских агентств, разных интернет-магазинов,
Сообщение от ГК «Мастерхост»:

Уважаемые клиенты!

Рады сообщить, что ООО «Мастерхост» удалось достигнуть договорённости относительно права использования ресурсов дата-центра.

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

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

Это было тяжёлое время для всех нас, но мы полностью готовы открыть новый этап в своей работе.

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

  • невозможно подключиться к серверу MySQL;
  • три дня назад поменяли днс, до сих пор не обновились;
  • наш сайт по-прежнему лежит, доступа к базе, ftp нет. И код для переноса домена получить не можем;
  • у нас в МХ 10 единиц оборудования на колокейшене, свои Днс сервера, поэтому проблемы с днс самого МХ нас обошли стороной до вчерашнего дня. Вчера в 12:00 по питанию, НА ЖИВУЮ перезагрузили все наши сервера. В итоге один NAS начал испытывать проблемы с файловой системой (пол дня решали), часть ВМ в кластере к8 начали испытывать проблемы с подключенными шарами и дисками, один СХД подключенный по фибре вообще отключился и не доступен до сих пор, 3 критично важных ВМ сдохли из-за недоступности СХД. У нас весь ИТ отдел сутки пытается все исправить. Читаю новости о том что все вчера порешалось, смотрю на мониторинг заббикса где висит алерт недоступности СХД с убитыми ВМ и испытываю уныние. В почте все заявки на суппорт МХ пришли с отбивкой «доставка отложена»;
  • ничего не работает, ни сайт, ни почта, доступа к БД нет, поддержка не отвечает;
  • сделайте REPAIR TABLE нет доступа в phpadmin;
  • хинт: подключайтесь к БД, используя имеющиеся у Вас реквизиты доступа к серверу MySQL, другим способом, например, через приложение «Navicat for MySQL». У меня один сайт сразу же заработал, а вот на двух других пришлось БД ремонтировать;
  • почта не работает у всех сайтов, один сайт только что снова ушел в офф;
  • наш сайт как лег, так и не встаёт… в админку также не пускают;
  • некоторые таблицы находятся в состоянии crashed поэтому не пускают, походу где были изменения при отключении таблицы упали, пытаются восстановить;
  • почта работает частично. Те у кого переадресация на уровне мастерхоста была настроена, получают на свои личные ящики письма. То есть, их сервер письма принимает, пересылает куда нужно. Но аутентификация не работает, в сами ящики зайти не дает;
  • не работает изменение AAAA/A зон. 6 часов назад поменял, в ЛК все поменялось. Но домен по прежнему смотрит на хостинг masterhost;
  • с трудом зашел в лк. Домены от 04.03.20 и 03.03.20, так и не продлились. Ключ authinfo-кода, не дают. Тех поддержка второй день игнорит. Телефоны не работают, чат также молчит;
  • в понедельник 2го марта с утра выключился сайт и почта. В среду, 4го марта, ближе к вечеру, заработал сайт со всеми базами, почта недоступна, 5го марта в четверг с утра снова выключился сайт, 5го марта к вечеру заработал сайт и почта, но почта не принимает и не отправляет письма, так что почта, можно сказать, на данный момент не работает до сих пор.

Утром 2 марта 2020 года в работе хостинг-провайдера «Мастерхост» начались проблемы. Вечером 2 марта 2020 года в 20:36 компания сделала официальное заявление о захвате дата-центра бывшим собственником компании. Компания заявила, что её дата-центр «в настоящее время находится в физическом распоряжении бывшего собственника компании, который периодически инициирует проблемы в работе оборудования. Именно это обстоятельство является причиной сбоев».

Судя по упоминанию «огромного количества запросов бэкапов», клиентскую базу российских хостингов ждет определенное перераспределение по провайдерам услуг.

Вопрос: Как получить бэкап сайта?
Ответ: Сейчас нам поступает огромное число заявок на бэкап. Все они будут обработаны специалистами, как только появится техническая возможность. Просим Вас ожидать, когда с Вами свяжутся наши сотрудники, чтобы предоставить данные. Заявку можно оставить в Личном кабинете, либо направить письмом на support@masterhost.ru.

Вопрос: Новости о закрытии 5 марта и судебном процессе 18 марта. Правда ли?
Ответ: Наша компания не собирается закрываться, информация про 5 марта – фейк.
18 марта действительно состоится заседание арбитражного суда. Хотим отметить, что день судебного заседания и время восстановления работы сервисов никак не связан.

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

Вопрос: Будут ли компенсации?
Ответ: Да, вопрос по компенсациям будет решаться в индивидуальном порядке после включения всех сервисов.

Судебное заседание по иску «Мастерхоста» к «Информационному центру» состоится 18 марта 2020 года.

5 марта 2020 года уполномоченный при президенте РФ по защите прав предпринимателей Борис Титов предложил законодательно защитить клиентов хостингов от конфликтов компаний, предоставляющих им услуги. Владельцы сайтов пострадали от того, что суд не обеспечил хостеру доступ к оборудованию, что по его мнению неправильно. Титов считает, что этот прецедент является «поводом задуматься о том, насколько клиенты оказались не защищены».

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

Основанный в 1999 году «Мастерхост» — один из первых хостинг-провайдеров и регистраторов доменов в России. По данным самой компании, она обслуживает более одного миллиона клиентов по всем услугам и более 500 тыс. доменов. В компании работает 125 человек. Портал HostAdvice оценивал до начала марта 2020 года долю клиентов «Мастерхоста» на российском рынке хостинга в 2,96%, хостер занимал по этому показателю шестое место на рынке.

Let's block ads! (Why?)