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

В первую очередь необходимо припаять к штекеру питания два резистора по 1 к? вот этой схеме делителя напряжения:

image

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

Теперь необходимо подключить выход делителя к любому аналоговому входу на Arduino. В моем случае это ножка А5. Затем попробуем считать напряжение с батареек:

void setup() {
  Serial.begin(9600);
  pinMode(A5, INPUT);
}

void loop() {
  float k = 2;
  float voltage = k*analogRead(A5);
}

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

void loop() {
  float k = 2/1024;
  float voltage = k*analogRead(A5);
}

Теперь подбираем при помощи вольтметра коэффициент, при котором voltage будет примерно равно реальному напряжению:

  float k = 2*1.12;
  float voltage = k*4.5f/1024*analogRead(A5);

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


void loop() {
  float k = 2*1.12;
  float voltage = k*4.5f/1024*analogRead(A5);
  float chargeLevel_procents;
  float chargeLevel;
  float y;
  int z;

  //Сглаживание значения заряда батареи

  float A_v = voltage; //Значение
  float A_K = 0.3; //Коэффициент сглаживания
  static float A_y; //Выходное значение
  
  A_y = A_y - A_K * (A_y - A_v);
}

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

После этого необходимо найти заряд аккумулятора в процентах:

  y = A_y / 8.4 * 100;
  
  chargeLevel_procents = y;
  chargeLevel = z;

Нам осталось только перевести это в значок батарейки (или в квадратики, как у меня) и вывести в консоль:


if(chargeLevel_procents >= 0 && chargeLevel_procents < 33) {
    z = 1; // 1/3 заряда
  }
  
  else if(chargeLevel_procents >= 33 && chargeLevel_procents < 66) {
    z = 2; // 2/3 заряда
  }

  
  else if(chargeLevel_procents >= 66 && chargeLevel_procents <= 100) {
    z = 3; // Полный заряд
  }

Serial.print("\t Voltage: ");
    Serial.print(A_y);
    Serial.print(" V ");
    Serial.print("\t Charge: ");
    if(z == 1) {
      Serial.print("¦");
    }
    else if(z == 2) {
      Serial.print("¦¦");
    }
    else if(z == 3) {
      Serial.print("¦¦¦");
    }
    else {
      Serial.print("ERROR");
    }
    Serial.print("\r\n");  

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

Комментарии (33)


  1. Meklon
    24.02.2016 12:03

    Субъективно лучше использовать дифференциальный АЦП и измерять между его ножками. Например, ads1115 — 16 бит, 4 канала. Можно и дифференциально измерять и относительно опорного. Не очень быстрый, но китайцы готовый breakout за копейки продают.


    1. Delics
      24.02.2016 13:21

      Написано, максимальное входное напряжение — 5,5В. А если больше надо, то что посоветуете? Через делитель напряжения? Или есть подходящий АЦП для 24В?


      1. Meklon
        24.02.2016 13:37

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



        Симуляция

        Полная схема:


        Еще можно посмотреть библиотеки RunningAverage и RunningMedian для сглаживания.
        Хотя это и дикий перебор для обычного измерения батареи.


        1. Delics
          24.02.2016 13:42

          Спасибо!


        1. Meklon
          24.02.2016 13:44

          Извините за простынь, спойлер поломал при редактировании.


    1. Zolg
      24.02.2016 13:46
      +1

      А зачем? Все равно измерением только напряжения остаточную емкость можно определить с точностью плюс-минус пол слоновьей филейной части. Лишняя точность АЦП будет действительно лишней.
      Если уж ставить дополнительный корпус, то есть спец микросхемы для контроля (в том числе) заряда батареи.
      Google(«battery monitor IC»)


      1. anticyclope
        24.02.2016 15:00

        Беда в том, что почти нет fuel gauge в удобных для Arduino-поделок корпусах.


        1. vladimir_open-dev
          24.02.2016 15:08

          И правильно, что нет — там порог входа высокий.


          1. anticyclope
            26.02.2016 06:17

            Не прослеживаю связь :)


  1. Visphord
    24.02.2016 12:05

    Эх, жаль не универсально (ваш код будет работать только с вашим типом аккумуляторов).
    У меня в домашних поделках примерно такой-же код, строго завязанный на литий (3.0-4.2В).


  1. zirus
    24.02.2016 12:11
    +6

    Ваша схема будет выжирать из аккумулятора 120мА*ч каждые сутки. Номиналы резисторов можно легко сделать 100кОм без особого ущерба точности. Я в своих схемах устанавливал даже мегаомные резисторы на делитель, но тут уже надо учитывать входное сопротивление АЦП. На нижнее плечо можно поставить конденсатор номиналом 1 мкФ, шумы уменьшатся.

    Также, ваше предположение, что заряд(количество энергии в аккумуляторе в процентах) пропорционален напряжению, неверно. Для определения на глазок — сойдёт, а вообще точность будет, думаю, процентов 30. При использовании литий-ионных аккумуляторов уровень заряда у вас опустится до 50 процентов, зависнет на этом уровне некоторое время, и дальше резко уйдёт в ноль. См. google://"li-ion discharge graph".


    1. Meklon
      24.02.2016 12:18

      Можно еще буферный операционный усилитель поставить в теории. Чтобы точно не отъедать энергию при измерении и не влиять на напряжение.


    1. Zolg
      24.02.2016 12:40
      +2

      И сам делитель в данном случае имеет смысл делать 10:1 и использовать внутренний Vref атмеги (1.1v для 328'ой).


  1. FireWind
    24.02.2016 12:57

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


    1. IronHead
      24.02.2016 13:23
      +1

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


  1. Plone
    24.02.2016 13:57
    +2

    Еще замечу, что называть деление на 1024 «переводом в десятеричную систему» неверно («десятичную», кстати). По сути это перевод в проценты (вы делите полученное значение на максимально возможное). Далее нужно просто умножить на 10, т.к. в вашем случае 100% — это 10 вольт. Ну, а потом поправочные коэффициенты добавить. Желательно несколько (по всей длине рабочего диапазона), с учетом нелинейной зависимости емкости от напряжения, как уже заметили выше.


  1. vladimir_open-dev
    24.02.2016 14:01
    +1

    Таким методом об уровне заряда аккумулятора не узнать ничего… и, как правильно сказали выше этот делитель потребляет энергию постоянно(и в конце концов испортит батарею). Если хотите измерять уровень заряда, то ищите по словам GasGauge/FuelGauge ic. Пост полная чушь(не завидую тому, кто не подумав повторит).


    1. zirus
      24.02.2016 14:57

      FuelGauge ic — крутая тема. В ноутбучных аккумуляторах стоит. По каким только параметрам не считает ёмкость. Даже саморазряд учтён, температурные зависимости, падение ёмкости в зависимости от цикла заряда-разряда. И много чего ещё. Не один день надо сидеть, чтобы понять


    1. Delics
      24.02.2016 15:46

      > Таким методом об уровне заряда аккумулятора не узнать ничего

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

      Делителем легко это перевести в диапазон до 5В и дальше уже накапливать данные и анализировать.

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


      1. IronHead
        24.02.2016 15:56

        Посмотрите график разряда любого современного АКБ. Он выглядит примерно так http://img.fcenter.ru/imgmat/article/cases/Ni_MH_batteries/128780.png
        То есть просадка напряжения будет в самом конце, когда емкости уже не осталось. А до этого, емкость будет уменьшаться, а напряжение — нет.
        Это если совсем уж простым языком.


        1. Delics
          24.02.2016 16:15

          График монотонно убывающий.

          Значит для измерения заряда и разряда он должен однозначно подходить.

          Про красивый progressbar уровня зарядки, понятно, речи не идет.


      1. Zolg
        24.02.2016 16:01

        Ну не то, что бы совсем ничего, но точность будет невысока.
        1) Зависимость нелинейна.
        2) Ни у одного серьезного производителя я не встречал один «график зависимости напряжения от заряда». В даташитах присутствуют графикИ зависимости напряжения от заряда для различных температур/разрядных токов.


        1. Delics
          24.02.2016 16:23

          > Зависимость нелинейна.

          Линейно и не нужно. Важно, что монотонно убывающая.

          > я не встречал один «график зависимости напряжения от заряда»

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


          1. Zolg
            24.02.2016 16:29

            Линейно и не нужно. Важно, что монотонно убывающая.

            Точность «полностью заряжен»/«севший в ноль» обеспечить получится.
            устройство делается на один конкретный тип аккумуляторов

            у одного конкретного аккумулятора будут разные кривые в зависимости от условий эксплуатации.


      1. vladimir_open-dev
        24.02.2016 16:08

        Уже правильно ответили + еще можно добавить, что кривая в графике смещается от температуры и поэтому дома будет 70%, а на улице 0%...


  1. mrigi
    24.02.2016 16:33
    +1

    А есть тут практики, реализовавшие "battery monitor ic"? А то рассказы про великий гугл они конечно замечательные, но реальные проекты найти не так уж и легко. Хотелось бы технически обоснованное бюджетное решение ($0.5-2.5), вымученное чьим-то опытом. Желательно в виде готового модуля. Вполне достаточно индикации из 3-5 диодов. На алиэкспрессе ничего приличного найти не могу.


    1. Delics
      24.02.2016 16:38

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


    1. vladimir_open-dev
      24.02.2016 17:54

      Пожалуйста...bq34z100-G1
      4 диода + необходимость программирования и обучения(для одного типа АКБ можно делать единожды) + отсутствие балансировки и защиты + уже не 2,5 бакса. Но в этих задачах такой ценник это нормально(не стоит забывать цену датчика тока).


  1. Zolg
    24.02.2016 16:42

    для ардуинщиков:
    http://www.seeedstudio.com/wiki/Energy_Shield


  1. ofStatic
    27.02.2016 01:10

    Чтобы определить процент по напряжению, надо хотя-бы примерно учитывать далеко не линейную разрядную кривую и делать замеры при том токе нагрузки, для которого эта кривая задана (в идеале при нулевом). Потому что под заметной нагрузкой некоторому напряжению может соответствовать, например, уровень заряда в 70%, а без нагрузки — 30%. Можно, конечно, измерять еще и ток и делать поправку на внутреннее сопротивление аккумулятора, но оно плавает от температуры сильно, это костыли. И да, это справедливо для лития, для никеля по напряжению вообще почти нереально определить уровень заряда на участке от 20 до 80%, кривая очень плоская.

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


  1. ForTheHorde
    27.02.2016 01:17

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


  1. mappa
    27.02.2016 01:20

    Если необходимо измерить напряжение питания самого МК, можно поступить еще изящнее и обойтись без делителя совсем: за опорное напряжение принять напряжение питания (неизвестное), а измерить относительное напряжение на внутреннем опорном источнике (известное заранее, обычно 1.1, как указали выше). Затем не хитрыми математическими операциями получить напряжение питания контроллера AVR.


  1. EngineerArt
    27.02.2016 01:20

    Теперь подбираем при помощи вольтметра коэффициент, при котором voltage будет примерно равно реальному напряжению:
    Так делать нельзя!

    Реальное значение напряжения в Вольтах будет = (Полученное значение) * (Опорное Напряжение)/(дискретность АЦП)