Month: October 2021

  • Changing Pulse Wave Frequency and Duty Cycle Using PWM Output [Arduino UNO]

    Changing Pulse Wave Frequency and Duty Cycle Using PWM Output [Arduino UNO]

    What is PWM output?

    PWM stands for pulse width modulation. It is a method of modulating a signal by changing the duty cycle of the waveform.

    For details, see my previous post.

    PWM output on Arduino

    The Arduino UNO uses a Microchip microcontroller called the ATmega328 as its main chip.
    Once you start digging deep into Arduino programming, you inevitably end up having to read the microcontroller’s datasheet, so it is worth taking a look at least once. (Which is exactly the situation I’m in now.)

    The Arduino has three timers (Timer/Counter).
    These timers govern timing in Arduino programs.
    Functions such as delay() and tone() rely on them for their measurements.

    Timer/CounterPin numberBit widthRolePWM frequency
    Timer05, 68 bitManages Arduino timing
    delay(), millis(), micros(), etc.
    977 Hz
    Timer19, 1016 bitServo library, etc.490 Hz
    TImer23, 118 bittone(), etc.490 Hz

    This time we will change the PWM output frequency by manipulating these timers.
    Incidentally, since this alters the timers at their core, you might also be able to tweak functions like delay() in useful ways. (Though it seems more likely that they would simply be thrown off and behave erratically.)

    Because TImer0 generally affects the system as a whole, I recommend using TImer1.

    Useful references
    https://playground.arduino.cc/Main/TimerPWMCheatsheet/
    https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
    https://atooshi-note.com/arduino-1hz-pwm/
    http://blog.kts.jp.net/arduino-pwm-change-freq/
    http://garretlab.web.fc2.com/arduino/inside/hardware/arduino/avr/cores/arduino/wiring_analog.c/analogWrite.html

    Overview of the program

     The overall approach is to change the Arduino timer’s register settings so that the PWM output frequency can be set freely.

    The goal is to be able to output low frequencies, so the program is written to produce 10 Hz.

    Here I connect an LED to pin 10 and write a program that lets you freely change the frequency and duty cycle of its blinking.
    Since we are using pin 10, we work with TImer1.

    Program code

    //レジスタの設定を変えるためのもの
    #include <avr/io.h>
    int PWMPin = 10;
    
    //関数の定義
    //frq:周波数 (1Hz~指定できる)
    //duty:指定したいduty比
    void HzWrite(int frq, float duty) { 
    
        // モード指定
      TCCR1A = 0b00100001;
      TCCR1B = 0b00010100; //分周比256を用いる
    
      // TOP値指定
      OCR1A = (unsigned int)(31250 / frq);
    
      // Duty比指定
      OCR1B = (unsigned int)(31250 / frq * duty);
    }
    
    
    void setup() {
      pinMode(PWMPin, OUTPUT);
    }
    
    void loop() {
      HzWrite(10, 0.5);
      delay(5000);
      digitalWrite(PWMPin, LOW);
      delay(5000);
    
    }

    Explanation of the program

    First, include <avr/io.h> in order to change the register settings.

    #include <avr/io.h>

    Next, to build a function that works together with delay() to repeat a 10 Hz output every five seconds, we define a function called HzWrite. Its arguments allow you to specify the frequency and duty cycle.

    void HzWrite(int frq, float duty) { 
    
    }

    Next comes setting the mode.
    The registers used here are TCCR1A/TCCR1B. (TCCR: Timer/Counter Control Register)
    The “1” indicates TImer1; if you want to use Timer2, use TCCR2A/TCCR2B instead.

    To set the PWM frequency to a specific value in Hz, you need to specify the TOP value yourself.
    The larger the TOP value, the lower the output frequency.
    Here I use 10 Hz as an example. Since this is very slow compared with the 16 MHz system clock, a large TOP value and a large prescaler are required. For this reason, we use Timer1, which offers the largest range.


    With the 8-bit Timer0 and Timer2, the maximum TOP value is 255 (2^8 – 1), while with the 16-bit Timer1 it is 65535 (2^16 – 1).
    (The reason for the -1 is that the range is 0–255 or 0–65535: the number of values is 2^x, but the maximum value must be one less.)

    In terms of how the system works, the counter increments up to the TOP value (counting 0, 1, 2, …), and when it matches OCRxA/OCRxB (where x is the timer number; each timer has two output pins, A and B, assigned to it), the pin output changes state (e.g., LOW→HIGH). Once the counter reaches the TOP value, it then decrements back down to 0 (counting down 65535, 65534, 65533, …), and just as during the increment phase, the pin output changes state when the count matches OCRxA/OCRxB.

    On the Arduino UNO, the speed at which this counter increments can be changed to some extent by changing the prescaler setting. (“To some extent” means you can choose from 1/8/64/256/1024.)
    The prescaler is the ratio (n) used when dividing the frequency (multiplying the frequency by 1/n).
    In other words, dividing 1000 Hz by a prescaler of 10 gives 100 Hz.

    Incidentally, with a prescaler of 1 the timer runs at 16 MHz, the system clock of the Arduino UNO (ATmega328).

    In short, by changing the TOP value, the OCRxA/OCRxB values, and the prescaler, you can freely set the points at which the output switches.

    Since we want 10 Hz here, we use a prescaler of 256 to leave plenty of margin.
    On the Uno, the clock is 16 MHz, so one count takes 1 / 16 MHz = 62.5 ns (prescaler 1).
    With a prescaler of 256, counting all the way to TOP takes 62.5 ns x 256 x 65535 = 1.04856 s, so frequencies as low as 1 Hz can be specified.

    This program can generate frequencies from 1 Hz up to 31250 Hz.
    However, as you approach 31250 Hz it becomes impossible to set the duty cycle precisely.
    If you want fine control over the duty cycle, you can only go up to about 300 Hz.

    By changing the prescaler setting in this program, you can build a version that produces the frequency range suited to your own application.

    Next, we write what to set in TCCR1A/TCCR1B.
    The fine details here are rather complicated, so let’s just work through the datasheet and set them roughly.

    Here the values are given in binary, so they begin with 0b. In TCCR1A you set COM1A1, COM1A0, COM1B, unused, unused, WGM11, WGM10 to 1 or 0.
    In TCCR1B you set unused (ICNC1), unused (ICES1), unused, WGM13, WGM12, CS12, CS11, CS10, respectively.

    TCCR1Aの指定(ATmega328データシートより)
    TCCR1Bの指定(ATmega328データシートより)

    First, here we select Mode 9, whose PWM mode is Phase and Frequency Correct.
    In this case the TOP value is set in OCR1A.

    モードの指定(ATmega328データシートより)

    Therefore, WGM13 / WGM12 / WGM11 / WGM10 are 1, 0, 0, 1, respectively.

    出力の指定(ATmega328データシートより)

    For COM1B1 / COM1B0: 0, 0 means no output; 0, 1 means toggle operation (the output is inverted on a compare match);
    1, 0 outputs LOW while the counter is between OCR1A/B and TOP, and HIGH while it is between 0 and OCR1A/B;
    1, 1 is the inverse of 1, 0.

    Here, since we want to switch the output LED between LOW and HIGH to produce the frequency, we set COM1B1 / COM1B0 to 1, 0.

    We choose 1, 0 because it makes the sketch easier to follow.

    分周比の指定(ATmega328データシートより)

    Since we are using a prescaler of 256 here, CS12/CS11/CS10 are set to 1, 0, 0.

    To summarize, we get the following.

    TCCR1A = 0b00100001;
    TCCR1B = 0b00010010;

    Next we set OCR1A and OCR1B so that the output is generated with the specified frequency and duty cycle.

      // TOP値指定
      OCR1A = (unsigned int)(31250 / frq);
    
      // Duty比指定
      OCR1B = (unsigned int)(31250 / frq * duty);

    When using Phase and Frequency Correct PWM, the counter both increments and decrements, so the output frequency can be expressed as follows.

    Frequency frq = IC clock frequency / (prescaler * TOP value * 2)

    Conversely, to obtain the TOP value:

    TOP value = IC clock frequency / (prescaler x frq x 2)

    For the Arduino UNO with a prescaler of 256:

    TOP value = OCR1A = 16,000,000 / (256 x frq x 2) = 31250 / frq

    Since we want the timing at which LOW and HIGH switch to correspond to OCR1A/OCR1B = duty cycle,

    OCR1B = 31250 / frq x duty

    An unsigned int is used to prevent overflow.

    Here is the main part of the output code.

    void setup() {
      pinMode(PWMPin, OUTPUT);
    }
    
    void loop() {
      HzWrite(10, 0.5);
      delay(5000);
      digitalWrite(PWMPin, LOW);
      delay(5000);
    
    }

    PWMPin, i.e. pin 10, is set as OUTPUT, and the frequency and duty cycle are specified with HzWrite().
    After waiting with delay(), the output is turned off with digitalWrite(PWMPin, LOW), followed by another delay().

    That covers the full program and its explanation.

    Afterword

    When looking for blog posts on how to change the PWM output frequency, I found many more results by searching for AVR, ATmega328, or 328P than by searching for Arduino.

    This post was only a rough overview, so if you want to dig deeper, I encourage you to look into it yourself.

  • How to generate continuous pulse waves with Arduino

    How to generate continuous pulse waves with Arduino

    Introduction

    There are times when you want to output a continuous pulse wave with an Arduino: blinking an LED, generating a sound, using it as a timer, and so on.

    It comes up often and seems simple at first glance, but once you dig into it you find it is surprisingly deep.

    In this post, I introduce several ways to output a continuous pulse wave with an Arduino.

    Changing the timing with delay

    The simplest and easiest approach is to switch the output ON and OFF using the delay function.

    //pinはピン番号
    void loop(){
        digitalWrite(pin, HIGH);
        delay(1000);
        digitalWrite(pin, LOW);
        delay(1000);
    }

    In the program above, the output is toggled between HIGH and LOW.
    Since delay is specified in milliseconds, delay(1000) waits for one second.

    In other words, this program turns the output on and off at 1 Hz.

    However, using the delay() function to set the frequency has a number of drawbacks.
    With this approach, changing the output duration—for example, outputting a 60 Hz signal for five seconds—requires a for loop, which is inconvenient.

    That said, because it is so simple, it is a good choice when you just want to try something out.

    Using tone()

    The tone() function is commonly used to generate buzzer sounds and the like.
    Official Arduino reference

    This function lets you specify the frequency and the duration.
    So, unlike the delay approach, you can specify the frequency directly without calculating it.

    //pinはピン番号
    void loop() {
         tone(pin,60);
    }

    You can write it as tone(pin, frequency) or tone(pin, frequency, duration).

    The duration is given in milliseconds, so it is written the same way as delay.

    The limitation of this function is that you cannot specify frequencies of 31 Hz or below.
    In other words, you cannot generate an output such as 1 Hz.

    For frequencies above 31 Hz, such as audio tones, it makes specifying the frequency extremely easy, and the code is far shorter and more accurate than using the delay function.

    Using PWM output and changing its frequency

    Using PWM output offers the greatest flexibility—and it is also why this topic gets so deep.

    PWM stands for pulse width modulation.
    For details, see Wikipedia.

    The term alone does not tell you much, but simply put, PWM is a way of modulating an output by changing the duty ratio.
    The official Arduino explanation is here.

    Normally, you would set the brightness of an LED by changing the current. But if the current is fixed and you still want to change the brightness, you can blink the LED at a very high frequency (30–60 Hz is said to be the point where people can no longer perceive the flicker).

    Normally the ON and OFF periods are 1:1 (a duty ratio of 50%), but what happens if you make it 4:1 (80% duty) or 1:4 (20% duty)?
    The former will look bright, and the latter will look dim.

    Modulating the output by changing the pulse width in this way is what PWM output is all about.

    On the Arduino you can not only generate this output but also change the frequency of the PWM output.
    The idea here is that by tweaking the register settings—essentially the low-level guts of the Arduino—you can change the PWM output frequency.
    Incidentally, the default output frequency is 490 Hz, or 980 Hz on some pins.

    I will explain how to do this in detail in a future post.
    Searching for “PWM Arduino frequency change” turns up plenty of explanations.

    After reading them about four times, it starts to make sense.

    Basically, I suggest looking through these methods to find the one that best fits your own goal.

  • How to Install Python Video Annotator

    How to Install Python Video Annotator

    What is Python Video Annotator?

    Python Video Annotator is an application that lets you analyze recorded videos and annotate events within them along a timeline.

    Researchers in neuroscience and ethology can use it to record videos of animals and then analyze and quantify their behavior.
    For example, suppose you are recording mouse behavior and want to score actions such as sticking out the tongue, wagging the tail, or moving the ears.
    When in the video does each action occur, and how long does it last?
    Watching the video and logging everything in Excel each time becomes overwhelming once you have defined many behaviors.
    With a tool like this, you can record annotations directly on the video and export the timing and event information.

    There used to be an open-source application called VCode for recording animal behavior.
    The problem, however, was that it no longer runs on current computer operating systems.

    Python Video Annotator works on modern PCs and retains the essential features, while also allowing you to combine it with external sensor data (such as pressure gauges) and behavior-quantification tools like DeepLabCut, making it an extremely useful tool for researchers.

    How to install

    The official website describes the installation procedure in detail, but I could not get it to install properly on my computer. (Installing it directly may have caused conflicts with packages that were already installed.)
    So instead I followed the approach described on the GitHub page, building a virtual environment with Anaconda and installing it there.

    It sounds complicated when described in words, but the steps are very simple.
    As of now (October 20, 2021) it does not appear to support the latest macOS (Big Sur 11.6), though this will probably be fixed soon.
    For that reason, I will use Windows as the example here.

    That said, on macOS the steps are basically the same once you have installed Anaconda and can use the conda command, so please refer to this guide once support is available. (For details, see my previous post.)

    Install Anaconda and open the Anaconda prompt.
    Then create a virtual environment and activate it.

    conda create -n videoannotator python=3.6
    conda activate videoannotator

    Next, install the required packages.

    pip install opencv-python-headless pyqt5==5.14.1 pyqtwebengine==5.14.0

    Then install Python Video Annotator.

    pip install python-video-annotator

    Once all the processing finishes, the installation is complete.

    To launch it, activate the virtual environment first and then run it.

    conda activate videoannotator
    start-video-annotator

    If the software starts up, you are all set.

  • Using Conda Commands on macOS

    Using Conda Commands on macOS

    Here I’ll walk through installing Anaconda on macOS and setting up the terminal environment.

    Installing Anaconda

    Go to the Anaconda homepage and scroll down to find the downloads.

    Choose the installer that matches your environment.
    Since this guide covers macOS, select the 64-bit Graphical Installer.

    Launch the installer and follow the instructions to complete the installation.

    There are two installers for Mac. The 64-bit Graphical Installer installs Anaconda through a GUI, which is the more familiar approach, and unless you have a specific reason otherwise, this is the one to use.

    Downloading the 64-bit Command Line Installer gives you a *.sh file.
    This is a shell-script installation, used when you want to install from the terminal.

    Since installing software on Linux is normally done from the terminal, people used to Linux may find this option easier. (Probably.)

    Configuring the command line environment

    After installing on macOS, all you get is Anaconda-Navigator in your applications list — as is, you can’t use Anaconda or Python from the terminal.

    If you want to use the conda command to install packages and so on, you need to activate Anaconda.
    To activate Anaconda (i.e., to make the conda command available):

    conda activate

    Run the above.
    The conda command should now work.

    If activating the conda environment every time is a hassle, you can have it activate automatically.
    To do so, run the following in the terminal:

    ~/opt/anaconda3/bin/conda init シェル名

    Run the above.
    Use the name of the shell you actually use. If you have no idea what that means and have never changed it, you’re probably on the default shell (zsh on macOS), so substitute that for the shell name.

    ~/opt/anaconda3/bin/conda init zsh

    Now, when you restart the terminal, the conda environment will be activated automatically and you won’t need to type conda activate.

    To turn off automatic activation,

    conda config --set auto_activate_base false

    run the above in the terminal.