У наші дні можна стверджувати, що телефон перестав бути пристроєм тільки для дзвінків. Він дозволяє нам оплачувати покупки, знаходити правильну дорогу, викликати таксі. Ситуація, в якій у вас сідає батарейка, стає однією з найбільш стресових. Залишитися вночі на незнайомій вулиці без телефону досить неприємно. При цьому витрата батарейки зростає багато в чому як наслідок розширення можливостей.
Виробники як заліза, так і софту, намагаються вирішити цю проблему. Для Яндекса вона теж актуальна, тому що наші сервіси - це те, що повинно бути під рукою у людини в будь-який момент. Ми по-різному над цим працюємо і в рамках експерименту створили пристрій для вимірювання струму, який споживається телефоном з батарейки. Тепер ми вміємо міряти миттєві значення струму з батарейки телефону (Nexus, iPhone і ін.) В міліампер 500 раз в секунду, зберігати цю метрику на диск і вважати за нею середнє споживання.

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

Кілька місяців тому, коли ми починали прикручувати тестування навантаження телефонів до Яндекс.Танку (Це наш opensource інструмент для тестування продуктивності), ми зіткнулися з тим, що одну з найважливіших метрик - споживання струму з батарейки - ми не можемо заміряти достовірно, а на деяких телефонах не можемо заміряти взагалі. Наприклад, ось як виглядає графік споживання струму на iPhone, отриманий стандартними засобами від Apple:

Всі три запуски тесту значення споживання взагалі не змінювалося і дорівнювало 1/20. Дивує використана одиниця виміру - 1/20 означає, що якщо телефон далі буде працювати з тим же енергоспоживанням, то сяде він за 20 годин. Тобто, метрика виходить дуже неточна і не дуже интерпретируемая. Крім того, цифри в сирому вигляді отримати не можна, тільки хіба що скріншот зробити і прикласти його до тікету.
З Android девайсами ситуація виглядає краще, але все одно далека від ідеалу. Струм заміряти можна, читаючи з / proc / ... циферку, але краще не робити це занадто часто - опитуванням значення можна просадити продуктивність телефону і зіпсувати тести. На різних девайсах циферка знаходиться в різних місцях файлової системи. На частині Android телефонів взагалі відсутня залізяка, що вимірює струм, тому на них не вийде програмними засобами знімати споживання. На Nexus, які ми взяли як reference, значення в / proc змінюється раз в 20 секунд.

Загалом, ми вирішили спробувати вимірювати споживання хардверних і таким чином вбити всіх зайців разом: так можна міряти взагалі на всіх девайсах, включаючи ноутбуки і холодильники. Ми знали про існування Power Monitor , Але ціна пристрою (приблизно $ 800 за штуку, а на кожен телефон буде потрібно свій девайс), і його несумісність з Linux (а значить, і складності з автоматизацією), змусили задуматися про своєму велосипеді. Аналогічна ситуація спостерігається з осцилографами і іншими вимірювальними пристроями загального призначення на ринку - купувати дорого, автоматизувати складно.
Існує ще проект BattOr , За описом це приблизно те, що ми хочемо. Сам я не пробував зв'язатися з авторами, але колеги кажуть, що команду купив Google і з тих пір від них нічого не чути і на пошту вони не відповідають. Збіг? =)
Для початку, як proof-of-concept, ми зібрали схему з шунтом, аналогічну представленої в цієї статті. Струм ми вимірювали в розриві дроту USB. Оскільки значення сили струму очікувалося невелике, до 500 мА, довелося посилювати напругу за допомогою інструментального підсилювача, а не знімати його безпосередньо з шунта ардуінкой.

Після ще деяких танців з бубном нам вдалося отримати на екрані ноутбука графік споживання телефоном струму з USB. Тут ми зрозуміли, що таких вимірювань нам не вистачає - ми міряємо не ток з батарейки, а струм з USB, телефон запасає енергію в батарейці, і ми не можемо порівняти графік споживання струму з тим, що відбувається на телефоні. Вирішили, що потрібно витягувати батарейку з телефону і використовувати замість неї зовнішнє живлення, а USB під час тестів взагалі не встромляти.

Як відомо, все, чого нас вчили на уроках фізики і електротехніки, - брехня, ніяких електронів не існує, а пристрої працюють на білому димі. І якщо цей білий дим виходить, то пристрій працювати перестає. У черговому експерименті білий дим вийшов з Arduino і ми її втратили. Виявилося, що між "0" на вході нашого блоку живлення і "-" на його виході - 88 вольт змінного напруги. Після ще кількох експериментів з різними БП ми зрозуміли, що не всі вони однаково хороші, але є такі, які нам підходять. І ми стали використовувати ці відповідні. Також ми вирішили більше не використовувати схему з шунтом і інструментальним підсилювачем і замість цього взяти готовий модуль вимірювання струму до Arduino на базі MAX471, яка по суті те ж саме, тільки у вигляді мікросхеми. Ще ми розглядали варіант на базі датчика Холла (ACS712), але, вивчивши документацію на цей чіп, побачили, що він сильно шумить і вирішили навіть не пробувати.

Для того, щоб живити сучасний телефон немає від вбудованої батареї, а від зовнішнього джерела, мало його розібрати і витягнути батарею - аж надто розумні сучасні батареї. Тому ми витягуємо з батареї контролер і підключаємося вже до нього.

Щоб повернути модифікований таким чином iPhone (або інший пристрій) в зібране стан, ми свердлимо корпус і виводимо два проводка.

Ось така коробочка у нас вийшла в результаті. Правда, в метро її краще не возити, телефон, проводи, ось це все ... можуть не зрозуміти =)

Ми вже почали впроваджувати тестування наших додатків на енергоспоживання, так що чекайте поліпшень в цій області. Процитую колег, які користуються нашою коробочкою.
Для отримання релевантного результату тесту при прямих вимірах батарейки цим пристроєм досить п'яти хвилин. Якщо ж заміряти «як раніше», тобто дивитися на швидкість зменшення% заряду батареї - то потрібно 6-8 годин, плюс не забувайте про людський фактор. Тобто, час тесту скоротили з 8 години до 5 хвилин: майже в 100 разів.
Поточний розкид результатів виміру ± 15%. Це не ідеал і треба похибка зменшувати. Однак, тепер довіру до результату підвищилося за рахунок виключення людського фактора і істотно меншого часу на 1 завмер. Досить виконати за півдня багато-багато вимірів і відсікти результати, які постраждали від раптових сплесків незрозумілою активності на телефоні.
Стало можливим крос-платформенне, і крос-девайсное порівняння значень. Одиниця виміру - mA, а не «швидкість зменшення відсотків заряду», яка залежить від платформи, обсягу батареї, «свіжості» батареї, не кажучи вже про запущені процеси ... Порівняти тільки mA при одному і тому ж занедбаному Я.Сервісе на Andoird і на iOS - не можна. Треба додати поправочний коефіцієнт - скільки жере кожна платформа, без Я.Сервіса. Але, це знову-таки питання на пів дня вимірів (і це з кавою-поговорити).
Щоб збирати дані від Arduino (а вона просто 500 раз в секунду шле їх по USB), ми написали простеньку читалку. На Python виникли проблеми з повторним відкриттям пристрою на читання - вдруге дані вже не читалися. Ми не стали розбиратися і просто переписали те ж саме на Golang - після цього все запрацювало.
Тут нас чекали ще невеликі граблі: в буфері пристрою з попереднього запуску залишаються старі дані. Тому зараз ми просто відкидаємо перші 500 вимірювань (1 секунда). Потім зібрані в .csv дані обробляємо скриптом на Python (в якому використовуються Pandas і Seaborn) і отримуємо графіки, які ви бачили на початку статті.
Якщо вам цікаві вихідні читалки, прошивка і код для обробки даних - можу поділитися, пишіть в личку.
Збіг?