FreeRTOS Code Reading (Arduino編, #2)

xTaskCreate() 関数を読む前に予定を変えてWindows環境でAruduino IDEでのビルドについて確認します。

Arduino IDEのメニューから、ファイル->環境設定->より詳細な情報を表示する->コンパイル にチェックを入れると、 下記にようにビルド時の詳細情報が表示されるようになります。

"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10809 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\standard" "-IC:\Users\hogehoge\Documents\Arduino\libraries\FreeRTOS\src" "C:\Users\hogehoge\AppData\Local\Temp\arduino_build_353041\sketch\arduino_freertos_sample.ino.cpp" -o "C:\Users\hogehoge\AppData\Local\Temp\arduino_build_353041\sketch\arduino_freertos_sample.ino.cpp.o"

上の例では、下記フォルダでビルドが実行され、ファイルが生成されています

"C:\Users\hogehoge\AppData\Local\Temp\arduino_build_353041

arduino_build_folder

上記フォルダで、avr-objdump.exe を実行することで、生成されたアセンブリ言語を見ることもできます

objdump

必要に応じて利用していきたいと思います。

次回こそxTaskCreate() 関数を読み進めます。

FreeRTOS Code Reading (Arduino編, #1)

興味があるのでFreeRTOSのソースコードを読んでみる。 あとで修正するかもしれませんが、しばらくは体裁が整っていない自分用のメモです。

なぜ読むか?

RTOSの実装に興味があり、Arduino版ならコード量の少なく読みやすそうだったので。

ソースコードはここ。github.com MPU(atmega328p)のdatasheetはここ。https://avr.jp/user/DS/PDF/mega328P.pdf

もしくはここ。http://akizukidenshi.com/download/ds/microchip/atmega328.pdf

読み方、ソースコード引用の方針

どこから読み始めるか

161204_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf に variantHook.cpp から読めと書いてあるのでそこから始める。 (↑は昔書いたメモだけど、見当たらないorz)

読む

  • Arduino_FreeRTOS_Library\src\variantHooks.cpp
extern void setup(void);
extern void loop(void);

/*-----------------------------------------------------------*/

void initVariant(void) __attribute__ ((OS_main));
void initVariant(void)
{
#if defined(USBCON)
    USBDevice.attach();
#endif

    setup();        // the normal Arduino setup() function is run here.
    vTaskStartScheduler(); // initialise and run the freeRTOS scheduler. Execution should never return here.
}

setup(), loop()はexternされていて、実体は Arduinoのsketchが参照される。

  • task.c
void vTaskStartScheduler( void )
{
BaseType_t xReturn;

    /* Add the idle task at the lowest priority. */
    #if( configSUPPORT_STATIC_ALLOCATION == 1 )
    {
        ...
    }
    #else
    {
        /* The Idle task is being created using dynamically allocated RAM. */
        xReturn = xTaskCreate(  prvIdleTask,
                                configIDLE_TASK_NAME,
                                configMINIMAL_STACK_SIZE,
                                ( void * ) NULL,
                                portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
    }
    #endif /* configSUPPORT_STATIC_ALLOCATION */

configSUPPORT_STATIC_ALLOCATION は, config次第だが多分0(要確認)。

#ifndef configSUPPORT_STATIC_ALLOCATION
    /* Defaults to 0 for backward compatibility. */
    #define configSUPPORT_STATIC_ALLOCATION 0
#endi

スケジューラをタスクの1つとして登録する。

        /* The Idle task is being created using dynamically allocated RAM. */
        xReturn = xTaskCreate(  prvIdleTask,
                                configIDLE_TASK_NAME,
                                configMINIMAL_STACK_SIZE,
                                ( void * ) NULL,
                                portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
    if( xReturn == pdPASS )
    {
        ...

        /* Interrupts are turned off here, to ensure a tick does not occur
        before or during the call to xPortStartScheduler().  The stacks of
        the created tasks contain a status word with interrupts switched on
        so interrupts will automatically get re-enabled when the first task
        starts to run. */
        portDISABLE_INTERRUPTS();

        #if ( configUSE_NEWLIB_REENTRANT == 1 )
        {
            /* Switch Newlib's _impure_ptr variable to point to the _reent
            structure specific to the task that will run first. */
            _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
        }
        #endif /* configUSE_NEWLIB_REENTRANT */

        xNextTaskUnblockTime = portMAX_DELAY;
        xSchedulerRunning = pdTRUE;
        xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;

        /* If configGENERATE_RUN_TIME_STATS is defined then the following
        macro must be defined to configure the timer/counter used to generate
        the run time counter time base.   NOTE:  If configGENERATE_RUN_TIME_STATS
        is set to 0 and the following line fails to build then ensure you do not
        have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your
        FreeRTOSConfig.h file. */
        portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();

        traceTASK_SWITCHED_IN();

        /* Setting up the timer tick is hardware specific and thus in the
        portable interface. */
        if( xPortStartScheduler() != pdFALSE )
        {
            /* Should not reach here as if the scheduler is running the
            function will not return. */
        }
        else
        {
            /* Should only reach here if a task calls xTaskEndScheduler(). */
        }
    }
    else
    {
        ...
    }
  1. スケジューラのタスクの生成に成功したか(xReturn == pdPASS)を確認する
  2. xPortStartScheduler() を呼ぶまで割り込み禁止にする
        xNextTaskUnblockTime = portMAX_DELAY;
        xSchedulerRunning = pdTRUE;
        xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
  • xNextTaskUnblockTime は、...
  • xSchedulerRunning は、スケジューラが動作中はpdTRUEvoid vTaskEndScheduler( void ) が呼ばれると pdFALSE に設定される
  • xTickCount は、次のスケジュールのタスクの割り込みまでの時間。
        portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();

        traceTASK_SWITCHED_IN();

この2つのマクロはdefaultはカラ。

        if( xPortStartScheduler() != pdFALSE )
  • port.c
BaseType_t xPortStartScheduler( void )
{
    /* Setup the relevant timer hardware to generate the tick. */
    prvSetupTimerInterrupt();

    /* Restore the context of the first task that is going to run. */
    portRESTORE_CONTEXT();

    /* Simulate a function call end as generated by the compiler.  We will now
   jump to the start of the task the context of which we have just restored. */
    __asm__ __volatile__ ( "ret" );

    /* Should not get here. */
    return pdTRUE;
}
//initialize watchdog
void prvSetupTimerInterrupt( void )
{
    //reset watchdog
    wdt_reset();

    //set up WDT Interrupt (rather than the WDT Reset).
    wdt_interrupt_enable( portUSE_WDTO );
}
  • prvSetupTimerInterrupt() は、WDT(Watch Dog Timer)をリセットし、WDT割り込みを有効にしている。 ** `wdt_rest(), wdt_interrupt_enable()' は要確認
  • portRESTORE_CONTEXT() は、CPUレジスタを戻して(pop)、xPortStartScheduler() が呼ばれる前の状態(context)に戻している。
  • ret を発行して関数から戻る。

ここまででスケジューラタスクの登録し、実行した状態になった。

次回は、少し戻ってスケジューラタスクの生成処理を読み解いてみる。

        /* The Idle task is being created using dynamically allocated RAM. */
        xReturn = xTaskCreate(  prvIdleTask,
                                configIDLE_TASK_NAME,
                                configMINIMAL_STACK_SIZE,
                                ( void * ) NULL,
                                portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */

Googleカレンダーをスマホと同期させる

改めていうことじゃないですが、Googleカレンダー便利ですね。 スマホとも同期できるので一元管理できていいですね。

でも、自分の環境では問題が・・・

用途毎に複数のカレンダーを作ったり、公開されているカレンダーを登録したりして、 複数のカレンダがーが場合にブラウザでは全てのカレンダーが見れるけど、 同期設定しているつもりのスマホのカレンダーアプリでは見れるカレンダーと見れないカレンダーがありました。 以前に軽く調べたときはよくわからなかったけど、 もう一度調べ直しても見たら解決したのでφ(..)

そのような内容なので、スマホのカレンダーアプリでGoogleカレンダーと"全く"同期できない場合は 他の記事を検索した方がよいです。

iPhone/iPad

iPhone/iPadはこの記事で紹介されている同期設定のページが ビンゴでした。 weekly.ascii.jp

…ただ、自分でGoogleカレンダーのヘルプからたどろうとすると スマートフォンまたはタブレットでのカレンダーの同期 - カレンダー ヘルプApple カレンダーとの同期→他のカレンダーの同期→カレンダーの同期 となかなかたどり着けないページにある。

Android

Androidスマホではカレンダーアプリとして ジョルテを使っていますが、 このアプリからでは設定できないようだ。 Googleカレンダーでないと同期するカレンダーを選択できないようだ。Googleカレンダー"アプリ"は全く使ってなかったので気づかなかったけど… 具体的にはGoogleカレンダーアプリを開いて以下の手順を実行すれば、ジョルテでも同期されるようになりました。 メニュー → 設定 → 同期させたいカレンダーを選択 → 同期をONに変更

f:id:zinziroge:20160220111720p:plain:w300 f:id:zinziroge:20160220111714p:plain:w300 f:id:zinziroge:20160220111652p:plain:w300 f:id:zinziroge:20160220111647p:plain:w300

Structure From Motion

SfMを勉強しようと思って、この本のChapter 4のソースコードを入手してビルドしようとしてはまったことのメモ。 動作ししてから思い出しながら書いているので抜けがあるかも。

Mastering OpenCV With Practical Computer Vision Projects: Step-by-step Tutorials to Solve Common Real-world Computer Vision Problems for Desktop or Mobile, from Augmented Reality and Number Plate Recognition

Mastering OpenCV With Practical Computer Vision Projects: Step-by-step Tutorials to Solve Common Real-world Computer Vision Problems for Desktop or Mobile, from Augmented Reality and Number Plate Recognition

  • 作者: Daniel Lelis Baggio,Shervin Emami,David Millan Escriva,Khvedchenia Ievgen,Naureen Mahmood
  • 出版社/メーカー: Packt Publishing
  • 発売日: 2012/12/03
  • メディア: ペーパーバック
  • この商品を含むブログ (2件) を見る

テキストに対応したソースコードはここから取得。 MasteringOpenCV/code · GitHub

PCLのビルド(実際にはびるどはしてないけど)

PCLの公式Siteでもall in one packageを用意しているが、 今回使用したVisual Studio 2013用がなかった。 1つ1つコンパイルするの嫌だなぁと思っていたら、VS2013用にall in one packageを作っている方が居たので、 Building Point Cloud Library with Visual Studio 2012/2013/2015 | Summary?Blog

SSBAのビルド

SSBAもビルド。下記を入手し、3rdparty\SSBA-3.0だけビルドして、 Chapter4_StructureFromMotion\3rdparty\SSBA-3.0 としてコピー。 royshil/SfM-Toy-Library · GitHub

SfMのcmake

cmakeで Chapter4_StructureFromMotion のVS2013用ソリューションファイルを作ろうとすると VTK_DIRがないと怒られる。エラーメッセージを見るとPCLのcmakeに書いてあるようなので、 インストールされているフォルダ構成に合わせて下記に修正。 "C:\Program Files (x86)\PCL 1.7.2\cmake\PCLConfig.cmake"

macro(find_VTK)
  if(PCL_ALL_IN_ONE_INSTALLER AND NOT ANDROID)
#    set(VTK_DIR "${PCL_ROOT}/3rdParty/VTK/lib/vtk-5.8")
    set(VTK_DIR "${PCL_ROOT}/3rdParty/VTK/lib/cmake/vtk-6.2")

SfMのビルド

やっと、VS2013用ソリューションファイルができたのでChapter4_StructureFromMotionのビルド。

  • SURFを使っているいくつかのファイルでエラーが出るので下記を追加。場所が移動しているらしい。
#include <opencv2/nonfree/gpu.hpp>
  • ↑と合わせて下記も追加。([ExploringSfMExec]->[プロパティ]->[構成プロパティ]->[リンカー]->[入力]->[追加の依存ファイル])  C:\opencv_2.4.11\opencv\build\x86\vc12\lib\opencv_nonfree2411.lib も追加()。

  • WIN32の手順でファイルを取得するらしいのだが、エラーが出るので下記を追加。 Common.cpp:

#include <windows.h>
  • 最後に異なるバージョンのopencvの混在でもはまった。  自分の環境には2.4.1をインストールしてたんだけど、opencv2.4.2~2.4.11を使うように指示されていたので、2.4.11をインストールした。 そうしたら、cv::imread()で落ちる。理由は、環境変数PATHに2.4.11へのパスより先に2.4.1のパスが書かれていたから。

DLT(Direct Linear Transformation:直接線形変換)

幾つか記事を見たり、文献を観たいしたけどいまいちわからなかったので整理。

特異値分解(SVD)を用いて最小二乗法によりHomographyを求める。

{\displaystyle x'_i=Hx_i}
明らかに
{\displaystyle x'_i \times Hx_i=0}
(これは |a| \times |a|=0 より明らか)
{\displaystyle
  H = 
  \left(
    \begin{array}{ccc}
      h_{11} & h_{12} & h_{13} \\
      h_{21} & h_{22} & h_{23} \\
      h_{31} & h_{32} & h_{33}
    \end{array}
  \right) = 
  \left(
    \begin{array}{ccc}
      h_1^{\mathrm{T}} \\
      h_2^{\mathrm{T}} \\
      h_3^{\mathrm{T}}
    \end{array}
  \right)
}
と置くと
{\displaystyle
  Hx_i = \left(
    \begin{array}{c}
      h_1^{\mathrm{T}} x_i\\
      h_2^{\mathrm{T}} x_i\\
      h_3^{\mathrm{T}} x_i
    \end{array}
  \right),
  x'_i = \left(
    \begin{array}{c}
      x'_i\\
      y'_i\\
      w'_i
    \end{array}
  \right)
}
よって、クロス積の定義より
{\displaystyle
x'_i \times Hx_i = \left(
    \begin{array}{cc}
      y'_i h_3^{\mathrm{T}} - w_i' h_2^{\mathrm{T}} x_i\\
      w'_i h_1^{\mathrm{T}} - x_i' h_3^{\mathrm{T}} x_i\\
      x'_i h_2^{\mathrm{T}} - y_i' h_1^{\mathrm{T}} x_i
    \end{array}
  \right) = 0
}
これを書き換えると
{\displaystyle
x'_i \times Hx_i = \left(
    \begin{array}{ccc}
      0^{\mathrm{T}}         & -w'_i x_i^{\mathrm{T}} &  y'_i x_i^{\mathrm{T}} \\
      w'_i x_i^{\mathrm{T}}  & 0^{\mathrm{T}}         & -x'_i x_i^{\mathrm{T}} \\
      -y'_i x_i^{\mathrm{T}} & x'_i x_i^{\mathrm{T}}  & 0^{\mathrm{T}}
    \end{array}
  \right) 
  \left(
    \begin{array}{c}
      h_1 \\
      h_2 \\
      h_3
    \end{array}
  \right) = 0
}
H はn倍しても等価なので最後の行は削除できる。
{\displaystyle x'_i} は同次座標系なので {\displaystyle w'_i=1}ととると
{\displaystyle
  \left(
    \begin{array}{ccccccccc}
      0   & 0   & 0   & -x_i & -y_i & -w_i &  y'_i x_i &  y'_i y_i &  y'_i w_i \\
      x_i & y_i & w_i & 0    & 0    & 0    & -x'_i x_i & -x'_i y_i & -x'_i w_i \\
    \end{array}
  \right) 
  \left(
    \begin{array}{c}
      h_1 \\
      h_2 \\
      h_3
    \end{array}
  \right) = 0
}
{\displaystyle w_i=1}と置く。また、各要素がゼロになるので符号をそろえて見やすくすると
{\displaystyle
  \left(
    \begin{array}{ccccccccc}
       0   &  0   &  0   & -x_i & -y_i & -1   &  y'_i x_i &  y'_i y_i &  y'_i w_i \\
      -x_i & -y_i & -1   & 0    & 0    & 0    &  x'_i x_i &  x'_i y_i &  x'_i w_i \\
    \end{array}
  \right) 
  \left(
    \begin{array}{c}
      h_{11} \\
      h_{12} \\
      h_{13} \\
      h_{21} \\
      h_{22} \\
      h_{23} \\
      h_{31} \\
      h_{32} \\
      h_{33} \\
    \end{array}
  \right) = 0
}
n個の座標を対象にすると下記のようにかける。
{\displaystyle
  \left(
    \begin{array}{ccccccccc}
       0   &  0   &  0   & -x_1 & -y_1 & -1   &  y'_1 x_1 &  y'_1 y_i &  y'_1 w_1 \\
      -x_1 & -y_1 & -1   & 0    & 0    & 0    &  x'_1 x_1 &  x'_1 y_i &  x'_1 w_1 \\
       0   &  0   &  0   & -x_2 & -y_2 & -2   &  y'_2 x_2 &  y'_2 y_2 &  y'_2 w_2 \\
      -x_2 & -y_2 & -1   & 0    & 0    & 0    &  x'_2 x_2 &  x'_2 y_2 &  x'_2 w_2 \\
           &      &      &      & \vdots
    \end{array}
  \right) 
  \left(
    \begin{array}{c}
      h_{11} \\
      h_{12} \\
      h_{13} \\
      h_{21} \\
      h_{22} \\
      h_{23} \\
      h_{31} \\
      h_{32} \\
      h_{33} \\
    \end{array}
  \right) = 0
}
{\displaystyle
Mx=0
}
これを特異値分解(SVD)を使って説く。
つづく。

参考:

Direct Linear Transform アルゴリズムを使って、投影変換の行列Hを計算する。 - ぱたヘネ
(ほぼこの記事に自分が読んでわからなかったところを書き足した感じ)

これなら分かる応用数学教室―最小二乗法からウェーブレットまで

これなら分かる応用数学教室―最小二乗法からウェーブレットまで

実践 コンピュータビジョン

実践 コンピュータビジョン

類似画像検索アルゴリズムの調査

類似画像検索というか下記要件を満たす検索をやりたい。

  • 画像は線画
  • 画像の中に特定の図形を探しだす
  • スケール、回転に不変(強い)
  • 探す先の画像は探し元の画像に対して非常に大きい

一から考えるのは無理があるので、適当なアルゴリズムを探している。

類似画像検索として一般的な分類としては

  • 特徴点ベース
  • テンプレートマッチング
  • ハフ変換とか

なんかがありそうなんだけどどういうのがいいことやら。

もう少し調べてみたらHuモーメントを使うのがよさそう。
Image moment - Wikipedia, the free encyclopedia
構造解析と形状ディスクリプタ — opencv 2.2 documentation

この路線で調べてみよう