Контроллер Arduino с датчиком температуры и Python интерфейсом для динамической идентификации объектов управления

    Введение


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

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

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

    Контур измерения температуры


    Контур измерения температуры состоит из первичного цифрового измерительного преобразователя – DS18B20 (Maxim Integrated), управление которым, по интерфейсу 1-wire, осуществляет микропроцессорный контроллер – Atmega328 (5V 16MHz (Microchip) на платформе Arduino Pro Mini.

    Выходной сигнал измерительной информации с DS18B20 по интерфейсу 1-wire поступает на дискретный вход микроконтроллера, обрабатывается, преобразуется в строку ASCII символов измеренных значений температуры в диапазоне от -55 до +125 °C и, по стандартному последовательному интерфейсу, через TTL-USB преобразователь, поступает в компьютер для дальнейшей программной обработки:



    Измерительная подсистема


    Измерительная подсистема построена на базе платформы Arduino Nano V3:



    Программное обеспечение составлено на базе примера, представленного на сайте [1], с использованием библиотеки OneWire, которую можно подключить через менеджера библиотек в интегрированной среде разработки Arduino Software:

    #include <OneWire.h>
    // OneWire DS18B20 Temperature Example
    // http://www.pjrc.com/teensy/td_libs_OneWire.html
    // The DallasTemperature library can do all this work for you!
    // http://milesburton.com/Dallas_Temperature_Control_Library
    //Вывод Data преобразователя DS18B20 подключаем к 7-му выводу //платформы Arduino
    OneWire  ds(7);  
    void setup(void) {
      Serial.begin(9600);
    }
    void loop(void) {
      byte i;
      byte present = 0;
      byte type_s = 0;
      byte data[12];
      byte addr[8];
      float celsius;
      ds.search(addr);  
      ds.reset();
      ds.select(addr);
      ds.write(0x44, 1);  
      delay(800);    
      present = ds.reset();
      ds.select(addr);
      ds.write(0xBE);   // Read Scratchpad
      for ( i = 0; i < 9; i++) {  
        data[i] = ds.read();
       }
      int16_t raw = (data[1] << 8) | data[0];
      celsius = (float)raw / 16.0;
      Serial.println(celsius);
    }

    После отладки и тестирования приведенной программы прошивки контролера, приступаем к монтажу компонентов и элементов измерительной подсистемы, и к сборке в корпус:



    В условиях требований к минимизации корпуса, используем платформу Arduino Pro Mini. Аппаратное обеспечение подсистемы обработки и представления измерительной информации осуществляется через USB порт компьютера.

    Python интерфейс для обработки “кривой разгона” и её графической реализации


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

    1. Управление и опрос виртуального COM порта через USB порт; здесь использованы функции библиотеки pySerial.
    2. Интерактивное взаимодействие с оператором; здесь вводим необходимое количество измерений и номер последовательного порта (смотрим в Диспетчере Устройств ОС MS Windows). Если номер порта введен верно и не занят другими программами, на консоль и в графическое окно выводятся текущие измеряемые значения технологического параметра. По окончании измерений, на консоли выводится продолжительность времени измерений, период опроса датчика и указание – в каком файле txt находится таблица с результатами измерений, а в графическое окно выводится график измерений, дата, время, номер эксперимента, период опроса датчика.
    3. Автоматическая регистрация результатов измерений; здесь на диске в папке со скриптом необходимо наличие файла count.txt, в котором записано целое без знаковое число, используемое как счётчик экспериментов; каждый последующий эксперимент увеличивает счётчик на единицу и добавляет значение счётчика к имени файла с таблицей результатов эксперимента.

    Листинг программы:

    import numpy as np
    import matplotlib.pyplot as plt
    import serial
    from drawnow import drawnow
    import datetime, time
    #вывод выборки в графическое окно
    def cur_graf():
        plt.title("DS18B20")
        plt.ylim( 20, 40 )
        plt.plot(nw, lw1, "r.-")
        plt.ylabel(r'$температура, \degree С$')
        plt.xlabel(r'$номер \ измерения$')
        plt.grid(True)
    #вывод всех списков в графическое окно
    def all_graf():
        plt.close()
        plt.figure()
        plt.title("DS18B20\n" +
                  str(count_v) + "-й эксперимент " +
                  "(" + now.strftime("%d-%m-%Y %H:%M") + ")")
        plt.plot( n, l1,  "r-")
        plt.ylabel(r'$температура, \degree С$')
        plt.xlabel(r'$номер \ измерения$' +
                   '; (период опроса датчика: {:.6f}, c)'.format(Ts))
        plt.grid(True)
        plt.show()
    #определяем количество измерений
    # общее количество измерений
    str_m   = input("введите количество измерений: ") 
    m = eval(str_m)
    # количество элементов выборки
    mw  = 16
    #настроить параметры последовательного порта
    ser = serial.Serial()
    ser.baudrate = 9600
    port_num = input("введите номер последовательного порта: ")
    ser.port = 'COM' + port_num
    ser
    #открыть последовательный порт
    try:
        ser.open()
        ser.is_open
        print("соединились с: " + ser.portstr)
    except serial.SerialException:
        print("нет соединения с портом: " + ser.portstr)
        raise SystemExit(1)
    #определяем списки
    l1  = [] # для значений температуры
    t1  = []
    lw1 = [] # для значений выборки температуры
    n   = [] # для значений моментов времени
    nw  = [] # для значений выборки моментов времени
    #подготовить файлы на диске для записи
    filename = 'count.txt'
    in_file = open(filename,"r")
    count = in_file.read()
    count_v = eval(count) + 1
    in_file.close()
    in_file = open(filename,"w")
    count = str(count_v)
    in_file.write(count)
    in_file.close()
    filename = count + '_' + filename
    out_file = open(filename,"w")
    #вывод информации для оператора на консоль
    print("\n параметры:\n")
    print("n - номер измерения;")
    print("T - температура, град. С;")
    print("\n измеряемые значения величины температуры\n")
    print('{0}{1}\n'.format('n'.rjust(4),'T'.rjust(10)))
    #считывание данных из последовательного порта
    #накопление списков
    #формирование текущей выборки
    #вывод значений текущей выборки в графическое окно
    i = 0
    while i < m:
        n.append(i) 
        nw.append(n[i])
        if i >= mw:
            nw.pop(0)
        line1 = ser.readline().decode('utf-8')[:-2]
        t1.append(time.time())
        if line1:
            l1.append(eval(line1))
            lw1.append(l1[i])
            if i >= mw:
                lw1.pop(0) 
        print('{0:4d} {1:10.2f}'.format(n[i],l1[i]))
        drawnow(cur_graf)
        i += 1
    #закрыть последовательный порт
    ser.close()
    ser.is_open
    #time_tm -= time_t0
    time_tm = t1[m - 1] - t1[0]
    print("\n продолжительность времени измерений: {0:.3f}, c".format(time_tm))
    Ts = time_tm / (m - 1)
    print("\n период опроса датчика: {0:.6f}, c".format(Ts))
    #запись таблицы в файл
    print("\n таблица находится в файле {}\n".format(filename))
    for i in np.arange(0,len(n),1):
        count = str(n[i]) + "\t" + str(l1[i]) + "\n"
        out_file.write(count)
    #закрыть файл с таблицей
    out_file.close()
    out_file.closed
    #получить дату и время
    now = datetime.datetime.now()
    #вывести график в графическое окно
    all_graf()
    end = input("\n нажмите Ctrl-C, чтобы выйти ")

    Получим:

    введите количество измерений: 256
    введите номер последовательного порта: 3
    соединились с: COM3
    параметры:
    n — номер измерения;
    T — температура, град. С;
    измеряемые значения величины температуры
    n T
    0 24.75
    1 24.75
    2 24.75
    3 24.75
    4 24.75
    5 24.75
    6 24.75
    …………….



    Python интерфейс для получения передаточной функции и оценки адекватности модели


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

    Определение передаточной функции объекта по каналу регулирования температуры
    # -*- coding: utf8 -*-
    import matplotlib.pyplot as plt
    import time
    start = time.time()
    from scipy.interpolate import splev, splrep
    import scipy.integrate as spint
    import numpy as np
    from scipy.integrate import quad
    xx =np.array(np.arange(0,230,1))
    yy1 =np.array([
     24.87, 25.06, 25.31, 25.5, 25.81, 26.06, 26.37, 26.62, 26.87, 27.12, 27.44, 27.69, 27.87, 28.12, 28.31, 28.56, 28.75, 28.94, 29.12, 29.31, 29.5, 29.69, 29.81, 30.0, 30.12, 30.25, 30.37, 30.56, 30.69, 30.81, 30.87, 31.0, 31.12, 31.25, 31.31, 31.44, 31.5, 31.62, 31.69, 31.81, 31.87, 31.94, 32.06, 32.13, 32.19, 32.25, 32.31, 32.38, 32.44, 32.5, 32.56, 32.63, 32.69, 32.75, 32.75, 32.81, 32.88, 32.94, 32.94, 33.0, 33.06, 33.13, 33.13, 33.19, 33.25, 33.25, 33.31, 33.31, 33.38, 33.38, 33.44, 33.44, 33.5, 33.5, 33.56, 33.56, 33.56, 33.63, 33.63, 33.69, 33.69, 33.69, 33.75, 33.75, 33.81, 33.81, 33.81, 33.88, 33.88, 33.88, 33.88, 33.94, 33.94, 33.94, 34.0, 34.0, 34.0, 34.0, 34.06, 34.06, 34.06, 34.06, 34.06, 34.13, 34.13, 34.13, 34.13, 34.13, 34.19, 34.19, 34.19, 34.19, 34.19, 34.25, 34.25, 34.25, 34.25, 34.25, 34.25, 34.31, 34.31, 34.31, 34.31, 34.31, 34.31, 34.31, 34.38, 34.38, 34.38, 34.38, 34.38, 34.38, 34.38, 34.38, 34.38, 34.44, 34.44, 34.44, 34.44, 34.44, 34.44, 34.44, 34.44, 34.44, 34.5, 34.5, 34.5, 34.5, 34.5, 34.5, 34.5, 34.5, 34.5, 34.5, 34.5, 34.5, 34.5, 34.56, 34.56, 34.56, 34.56, 34.56, 34.56, 34.56, 34.56, 34.56, 34.56, 34.56, 34.56, 34.56, 34.56, 34.56, 34.56, 34.63, 34.56, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.63, 34.69, 34.63, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.69, 34.75, 34.69, 34.75, 34.69, 34.69, 34.75, 34.75, 34.75, 34.75, 34.75])
    yy2=yy1-24.87#компенсация смещения нуля
    yy=yy2/max(yy2)#нормирование
    """ Интерполяция переходной характеристики при помощи сплайнов"""
    def h(x):         
             spl = splrep(xx , yy )
             return splev(x, spl)
    """ Численное интегрирование без смены координаты времени в соответствии с (6)"""
    S1=(spint.quad(lambda x:1-h(x),xx[0],xx[len(xx)-1])[0])
    S2=(spint.quad(lambda x:(1-h(x))*(S1-x),xx[0],xx[len(xx)-1])[0])
    S3=(spint.quad(lambda x:(1-h(x))*(S2-S1*x+(1/2)*x**2),xx[0],xx[len(xx)-1])[0])
    S4=(spint.quad(lambda x:(1-h(x))*(S3-S2*x+S1*(1/2)*x**2-(1/6)*x**3),xx[0],xx[len(xx)-1])[0])
    """ Определение коэффициентов передаточной функции"""
    b1=-S4/S3
    a1=b1+S1
    a2=b1*S1+S2
    a3=b1*S2+S3
    """ Возврат во временную область"""
    def ff(x,t):
            j=(-1)**0.5
            return (2/np.pi)*( ((b1*x*j+1)*np.e**(-25*x)/(a3*(x*j)**3+a2*(x*j)**2+a1*x*j+1)).real)*(np.sin(x*t)/x)
    y=np.array([round(quad(lambda x: ff(x,t),0, 0.6)[0],2) for t in xx])
    """ Определение критерия адекватности модели """
    k=round(1-sum([(yy[i]-y[i])**2 for i in np.arange(0,len(yy)-1,1)])/sum([(yy[i])**2 for i in np.arange(0,len(yy)-1,1)]),5)
    stop = time.time()
    print ("Время работы программы :",round(stop-start,3))
    plt.title('Идентификация модифицированным методом площадей.\n Адекватность модели: %s'%k)
    plt.plot(xx, yy,label='W=(%s*p+1)/(%s*p**3+%s*p**2+%s*p+1)'%(round(b1,1),round(a3,1),round(a2,1),round(a1,1)))
    plt.legend(loc='best')
    plt.grid(True)
    plt.show()


    Получим:

    Время работы программы: 1.144



    Получена передаточная функция объекта (ёмкость с нагревателем) при адекватности к “кривой разгона”- 0,97.

    Выводы


    Разработан и испытан контроллер Arduino с датчиком температуры и Python интерфейсом для динамической идентификации объектов управления по каналу регулирования температуры.

    Ссылка:

    1. OneWire Library
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 29

      +1

      Курсовик?

        +1
        «Разработчик учебных программ»

        Ну.

        Непонятно только, под какими пытками и с какой целью его научили говорить фразами типа «динамической идентификации объектов управления по каналу регулирования температуры».
          –2
          Исключительно используя терминологию ТАУ. Пытки не применялись.
            +4
            Это называется не «терминология ТАУ», а «канцелярит».

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

                Если я начну такими словами говорить, какими вы статьи пишете, другая сторона решит, что я на встречу упоротый пришёл.
                  +2
                  Но вы же не обсуждаете эти задачи в узком кругу, а публикуете статью для широкой аудитории на Хабре. Вряд ли специалистам интересна эта поделка на Arduino, у них есть железки покруче. А широкой аудитории это потенциально интересно, ТАУ штука крутая и незаслуженно обойденная тут вниманием (мне по крайней мере точно интересно). Но гуглить термины и через строчку лезть в поисковик — это усложняет чтение и понимание. Хочется объяснений «на пальцах».
                    0
                    Согласен с Вами, учту.
                    Спасибо за профессиональный комментарий и интерес к публикации.
          –4
          Такого курсового проекта ещё нет. Разработка имеет более широкую область применения. Но если Вы хотите использовать как курсовой проект то пожалуйста пользуйтесь. Можете использовать для распространения научного softa.
          Спасибо за содержательный комментарий!
            +2

            Посмотрел в профиль. Не курсовик, извините. Статья для журнала "Вестник Зажопинского Университета".

              –3
              Там не публиковал не знаю. Поделитесь своим опытом.
                +3

                Ну раз просите, пожалуйста
                https://scholar.google.com/citations?user=cMmcXOEAAAAJ

                  –3
                  Тогда не понятно откуда такая реакция на практическую работу направленную на обучение и не претендующую на особую научность. Для самоутверждения?
                  Спасибо за комментарий!!!
                    +1

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

                      –2
                      В статье решена практическая задача, и хабр тем и ценен, что рассчитан на широкую аудиторию, и понятие серьёзности у каждого разное. Но, несерьёзное отношение к обучению никого не красит.
                        +3

                        Академический стиль и широкая аудитория — вещи взаимоисключающие.

                          –2
                          Вас раздражает академический стиль, и Вы приватизировали понятие на широкую аудиторию, что дальше ?!..
                            0

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

                            0
                            Попробуйте «загуглить» непонятные для Вас термины (это займёт не много времени) и просмотрите статью заново. Если есть сомнения, повторите приведенные в статье решения, используя метод «копи-паст». Если Вас не интересуют темы ТАУ, АСУТП и т.п. сделайте проект по первой части статьи — уверен, Вы точнее оцените содержание статьи и, возможно, будете в восторге. Удачи!
                              0

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

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

                              И то автора на всё не хватает, поэтому вдруг опа — и «USB-порт» вместо «интерфейсный разъём ПЭВМ, реализующий универсальную последовательную шину USB».
                0

                Передергиваете.

                  +2
                  Ну не плохо, но стиль изложения отталкивает местами. Я правда принял DS18B20 за IR приёмник. Уже был готов глянуть на кодировку сигнала и прерывание, но видимо не в этот раз. =)
                    +1

                    Попробуйте на этот объект подать другое входное воздействие (например превдослучайную бинарную последовательность) для проверки адекватности модели.

                      0
                      Для изучения в ВУЗе очень даже классно. Студенты и так ничего не учат а то. Тут хотя бы какая никакая практика с железом есть.
                        0
                        а внутре у ней неонка?
                          0

                          DS18B20 можно без ардуины напрямую с com порту цеплять через пару резисторов с диодами. Зачем весь этот огород?

                            0
                            А с показанным на картинке usb2ttl переходником можно совсем напрямую подключить. Зачем тут огород описано выше, в заминусованных комментах автора.
                              0
                              Можно, конечно, а потом пилить свой софт для работы непосредственно с ножками?
                              Или поставить Ардуинку как преобразователь из 1Wire в COM-Port и использовать все что угодно, начиная от терминала — выбор за Вами.

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

                            Самое читаемое