M5stack unitV2 A.I cameraのmicroSDスロット

TFカードと呼んでますが、実態はmacroSDとほぼ同じだろう。本体にスロットがあり、取り出し簡単ではなかったけれども抜いてみたら、SunDiskの16GBのカードが入っていて中はカラっぽ。

すでにsshコマンドで確認済みですが。

https://isehara-3lv.sakura.ne.jp/blog/2022/03/07/unit-v2カメラにsshログオン/

A.Iカメラの基本機能でそれなりのことはできるけれども、何かやろうとするとA.Iカメラ側にコード書かなければいけないけれども、関連情報はこれからサーチ。まあ、Pythonも3.0系が入っているし、c/c++も使えばやりたいことはできるでしょう。

Groveインターフェース介して、電源供給とシリアル通信使うのが現実的なアプリケーションになると思う。

 

admin

M5stackでstepping motorを動かす

Arduinoのステッピングモーター駆動は挙動不審、どうも脱調しているかの如く、同じ動作の繰り返しでも段々位置ずれするから、M5stackでも動かしてみる。

ライブラリ使うとブラックボックスになるので、直接ソースで動作を指定しました。

#include <M5Stack.h>

// motor/driver 28BYJ-48/ULN2003
//
// original source https://blog.takumus.io/entry/2016/09/13/190510
//

const int IN1 = 2;
const int IN2 = 16;
const int IN3 = 5;
const int IN4 = 17;

const int d_hs[8] = {   // 1-2 drive, 4096 cycles/turn ; gear ration 64:1
  0B00001000, 
  0B00001100,
  0B00000100,
  0B00000110,
  0B00000010,
  0B00000011,
  0B00000001,
  0B00001001
};

int i = 0;

void step(int d);

void setup()
{
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
}

void loop()
{
  for(int i=0; i < 8*256; ++i)
  { 
    step(1);
    delayMicroseconds(2000);    // it does not work properly lower than 2 ms 
  }
  for(int i=0; i < 8*512; ++i)
  {
    step(-1);
    delayMicroseconds(2000);
  }
  for(int i=0; i < 8*256; ++i) 
  { step(1); delayMicroseconds(2000); 
  } 
}
 
void step(int d) // d = -1 : anticlockwise, d = 1 : clockwise { i += d; if(i > 7) i = 0;
  if(i < 0) i = 7;
  byte b = d_hs[i];
  digitalWrite(IN1, bitRead(b, 0));     // bit position 0 ; LSB
  digitalWrite(IN2, bitRead(b, 1));
  digitalWrite(IN3, bitRead(b, 2));
  digitalWrite(IN4, bitRead(b, 3));
}

M5stackは外部に出ているGPIOピンが少ないので、使用するピンは限定されます。

以下の画像で、3-R0, 18-SCKなどは同じピンがオスメスの違いで出力されているだけです。

最初、2/5/35/36使ったら動かない、35/36は入力専用だから。次に2/5/25/26使うと動いたけど、スピーカーと兼用らしくて五月蝿い。で最終的に2/5/16/17を使用。

 

<結論>

M5stackでは正確に角度を刻める、ただし時間待ちを1,500μsぐらいに小さくすると抜けが出るようです。値を大きく取って、連続して動かしていてもターンテーブルの位置は変わらないから、時間待ちがどうも問題の本質のようです。

あとArduinoIDEはイマイチだから、Arduinoの開発環境もVScodeにしたほうがいいかもしれない。

 

P.S. (2022/5/22)

Arduinoから線引き出して、同じ条件で二つのモーターの動作比較して、

・本体のモーターが片方向しか回転しないのは、モータードライバ基板へのArduino側の配線が一本外れてた。-> これは該当問題とは無縁の突発事象

・外部モーターもライブラリ使わないとFreeRTOS配下ではうまく動作しない。圧電スピーカーでもそうだったけど、どうも時間待ちという処理でFreeRTOSとリソース競合が起こるように見える。

・ライブラリ使っても、ライブラリなしと同様に回転速度を落とさないとパルスが抜けるように見える。

と言うことで、回転速度を” myStepper.setSpeed(5); // 10 -> 5回転/1分に設定、つまりライブラリなしでの時間待ちを長くするに相当、に落とすとまともに動いてるように見えるから、高速では動けないモーターだったということ。

アップデートは、

https://github.com/chateight/arduino/tree/master/smart_car_RTOS

にアップロードしました。

 

admin

Arduino carに圧電スピーカーを追加したけど、

立ち上げで初期化完了時にサウンド、バックするときにも違うサウンドを出す、としたいけど、初期化完了時はともかく、バックする時にサウンド出すと、なぜか前進切り替わり時にDCモーターの左側が動いたり動かなかったり(大半は動かない)。なんで圧電スピーカーならすDIO(pin14)とそれ以外のDIOが干渉するか分かりませんが、どうもタスクコントロールに問題があるんだろうからFreeRTOSに理解が浅いだけだろうと思う。

スピーカーはArduinoやDCモーター駆動基板を覆うような形で作ってみた。造形時間3時間ぐらいで、天井に圧電スピーカーをマウントできるようにしています。Arduinoとの接続はハンダ付だと分解が大変そうなので、ピンをArduinoのコネクタに差し込むようにして対応。

 

P.S.

タスクにしないで、直接関数呼び出しても同じ現象が起こるから、RTOS問題では無さそう。tone()関数はCPUのタイマー使っているから、実はそれがRTOSと競合しているとかあるのかな?

DIOを14から16に変えても状況に変化無し。

ということでback_sound()ではtone()関数使わないで、”ド4(およそ262Hz)”の音をおよそ0.3秒間出すようにしてみたらDCモーターがマトモに動くようです。

setup()からはtone()を呼び出してもこれは問題ないからそのまま使います。ArduinoライブラリにはFreeRTOS、つまりマルチタスク環境では上手く動作しない関数(thread safeでは無い関数)があるのかもしれません。

int pinNo = 16;
void buzzer_setup() {
  tone( pinNo, 98, 200 );   // Gの音を発信
  delay( 220 );
  tone( pinNo, 110, 200 );  // Aの音を発信
  delay( 220 );
  tone( pinNo, 123, 200 );  // Bの音を発信
  delay( 220 );
  tone( pinNo, 130, 200 );  // Cの音を発信
  delay( 1000 );
}

void back_sound() {
  //tone( pinNo, 98, 100 );  // Gの音を発信
  //delay( 150 );
  //tone( pinNo, 98, 100 );  // Gの音を発信
  //delay( 150 );

  for(uint16_t count=0; count<78; count++){
    digitalWrite(pinNo, HIGH);
    delayMicroseconds(1908);
    digitalWrite(pinNo, LOW);
    delayMicroseconds(1909);
  }
}

現状のソースコードやstlファイルのリンクはこちら。

https://github.com/chateight/arduino/tree/master/smart_car_RTOS

 

admin

Macbook Pro 16突然電源切れる(KP : Kernel panic)

特に何もしてない状態で電源切れる現象(ファンがいきなり高回転して電源断)が多発。

備え付けのdiagnosisでは問題発見できないけれども、現象からしてボード交換コースになりそうだ。

費用もともかく使えないのが困る、非常用はMacbook airだけれども、環境がまるで違うから、代替えにはなり得ない。

P.S.

近所のApple authorized repair centerで診断 : ハード診断は問題なし。とすると二年経過で、ACアダプタ常時つなぎっぱなしの電池あたりか。充電容量満充電付近では、頻繁に起きてたシャットダウンは発生しないようだから。

 

P.S._02

5月9日の朝も発生、

同じような時刻に再発して、もしかしたらnasへのtimemachineとタイミング的に合っているような気もする。

・特に操作していない時に起きる

・周辺機の接続はなし

・バッテリー容量には関係ないようだ、最初はバッテリーエラーを疑ったけど

・落ちる前にはポインティングデバイス無反応、つまりOSが処理続行不能状態

・昨日も今日もNASの電源落としている、つまりtimemachine動かない、と発生しない

ハードじゃなくて、ソフト問題で尚且つtimemeachine関連だね

 

P.S._03(2022/5/10)

早朝にMac sleep時にtimemachineバックアップ設定してたら、やはりKP起きてたから、現象は特定できたけど回避方法はこれから。

ローカルのディスク(USB)にはtimemachineバックアップ正常終了したから、ネットワークディスク関連で問題。

原因は特定できないので、NASに領域切り直してtimemachineは正常に完了。また出るかもしれないけど、その時はまた切り直せば凌げるだろう。あと領域が少なすぎるのも問題なのかもしれないから、いずれSSDが安くなれば交換か、稼働時間限定だからHDDを使うか。所詮Wi-Fi経由だと、速度的にもそれほどSSDのメリットもないし。

 

P.S._03(2022/5/11)

qnapのNASはボリュームの使用を80%推奨になってますが、95%とかギリギリに設定していたので、SSDを一台HDDに入れ替えて容量増やして、推奨条件で使うように再構成。アプリとかはSSDのままにしておいて速度が低下しないように変更。所詮Wi-Fi接続だからせいぜい60MB/secぐらいしか速度出ないから、SSDでもNASでも書き込み時間的には大差はない。

もともとバックアップは外部SSDやHDDにも多重化して持っているので、NASのディスクが壊れても致命的ではないから、NASはraid構成にはしていない。ディスクは生きてても、制御部が壊れることもあるわけだからNASを全面的に信用する運用は避けるべきだろう。

 

admin

PyGameのコントローラーにM5stack via Bluetooth

PyGameの迷路のコントローラーとしてM5stackを使ってみた。

M5stackとMacとの通信は以下の方法で。

https://isehara-3lv.sakura.ne.jp/blog/2022/05/05/m5stack-bluetoothでのmacとの送受信/

迷路ゲームについては、迷路作成は壁のばし法

https://yottagin.com/?p=1579

のクラスファイル流用して、ゲーム本体は、

https://news.mynavi.jp/techplus/article/zeropython-90/

から迷路作成ロジックだけ入れ替えですが、ほぼそのまま使えました。

M5stackのボタン処理は、ボタンが三つしか無いから、そのままではL/R/U/Dの処理ができないから、M5stackを傾けてボタンA/Cを操作したらU/Dになるように重力加速度の値で読み替えしてます。

ゲーム中にボタンBを押すとゲーム終了します。

#define M5STACK_MPU6886
#include "BluetoothSerial.h"
#include <M5Stack.h>

BluetoothSerial bts;
String btn;
float accX = 0.0F;  // Define variables for storing inertial sensor data
float accY = 0.0F;
float accZ = 0.0F;
float angle_th = 0.5F;  // r/l or u/l decision threashold

void read_imu() {
  M5.IMU.getAccelData(&accX,&accY,&accZ); //Stores the triaxial accelerometer. 
  M5.Lcd.setCursor(0, 90);
  M5.Lcd.printf(" accX");
  M5.Lcd.setCursor(0, 130);
  M5.Lcd.printf("%5.2f G", accX);
}

void setup() {
  M5.begin();
  M5.Power.begin(); //Init Power module.  
  M5.IMU.Init();    //Init IMU sensor.  
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0, 0, 2);
  M5.Lcd.println("Maze game");
  bts.begin("ESP32test");
}

void loop() {
  btn = "";                           // button info. clear
  
  M5.update();
  if(M5.BtnA.wasPressed())
  {
    btn = "r";
  }
    if(M5.BtnB.wasPressed())
  {
    btn = "t";
  }
  if(M5.BtnC.wasPressed())
  {
    btn = "l";
  }

  read_imu();   // imu data read

  if(btn != "")
  {
    if (btn != "t")       // t(ButtonB) key terminate the Maze game
    {
      if (accX < -angle_th | accX > angle_th)       // if M5stack is tilted, r/l keys are changed to u/d
      {
        if (accX < -angle_th){ if (btn == "r") { btn = "u"; } else { btn = "d"; } } if (accX > angle_th)
        {
          if (btn == "r")
          {
            btn = "d";
          }
          else
          {
            btn = "u";
          }
        }
      }
    }

    bts.println(btn);      // send pressed key info.
    M5.Lcd.setCursor(0, 50, 2);
    M5.Lcd.println(btn);
  }

  delay(100);

}

Bluetoothシリアルがコードを弄ってると繋がらなくなることが頻繁に起きて、その都度リブートしてるのは面倒です。本質的な原因はなんなんだろう?

全体のコードは、

https://github.com/chateight/PlatformIO/tree/master/bte_serial/src

にあります。

pythonのmaze.pyがメイン処理、make_maze.pyが迷路作成コード、receive.pyはM5stackのキー入力確認用のスクリプトでゲームと直接は関係ありません。

 

admin

 

M5stack Bluetoothでのmacとの送受信

プロトコルの煩雑なbleではなく、シンプルなbluetoothで接続してみます。

<環境>

・M5stack gray

・Macbook Monterey

・Python3 : mac側の動作確認用スクリプト記述

<ライブラリ>

bluetoothをあたかもシリアルのように見せるライブラリ(M5stack :

BluetoothSerial.h)とpythonでシリアルインターフェースを扱うための pyserialがあるのでそれらを使います。

 

・pyserialをインストールする

pip3 install pyserial

 

BluetoothSerial.hのインストール

BluetoothSerial.hはM5stackのライブラリから選択、インストールできます

 

<main.cpp>

#include "BluetoothSerial.h"
#include <M5Stack.h>

BluetoothSerial bts;

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0, 0, 2);
  M5.Lcd.println("Bluetooth TEST");
  bts.begin("ESP32test");
}

void loop() {
  M5.Lcd.setCursor(0, 20, 2);
  M5.Lcd.printf("Start Bluetooth");
  bts.println("message from the M5stack");
  //Serial.println("loop");
  String str = bts.readString();
  M5.Lcd.setCursor(0, 60, 2);
  M5.Lcd.println(str);

  delay(1000);
}

 

・シリアルポートを調べる

M5stackにコード書き込んで、シリアルポートを調べます。

% ls -l /dev/tty.*

crw-rw-rw-  1 root  wheel  0x9000008  5  4 18:03 /dev/tty.ESP32test

 

<write.py>

該当のポート情報に上の情報を設定します。

import serial

mes = "messge from my Mac"
# initialize bt serial
m5data = serial.Serial('/dev/tty.ESP32test',115200, timeout=3)
# read from bt
line = m5data.readline()
print(line.decode()[:-2:])
# write to bt
m5data.write(mes.encode())
m5data.close()

・実行

% python write.py 

b”

‘’に何も表示されないということはタイムアウトしている。

・macをリブートして、USBシリアル経由でpyserialの機能を確認してみる。

% ls -l /dev/tty.*

crw-rw-rw-  1 root  wheel  0x9000008  5  5 09:39 /dev/tty.SLAB_USBtoUART

write.pyに以下のデバッグ行追加

Serial.println(“loop”);

% python write.py

b’loop\r\n’

デバッグ用にコンソールに出力させて、シリアルポート切り替えると受信できるからpyserialそのものは動いているんだろう。

じゃ、本来のbluetoothでどうなの?この時MacからESPtestのbluetoothに接続はしない。

% python write.py

b’message from the M5stack\r\n’

ちゃんと受信できるから、どこかクリアされない状態があった?

リブートで状態がクリアされているようで、結果としてmacの設定でbluetoothの接続をしてしまうとダメ。一度接続選択すると接続選択解除してもpythonスクリプトからは使えなくなるから接続の権利(と言ってもmacに変わりはないけど)を他でキープしているようだ。

P.S ここでは接続しないと、% ls -l /dev/tty.*で見えないからダメだけど、

ここでは接続してはいけない。

 

読み出し文字列中のb’’はバイトストリングと言うことらしいけど、実際には必要ないからdecode()して普通の文字列に変換してやります。また書き込みの時にはencode()が必要です。

M5stackのスクショってどうすれば取れるんだろう?

bluetooth経由でデータの送受信ができるとやれることが広がります。

 

admin

c++ threadインスタンスを無名にしてvectorに格納

マルチスレッドで、スレッドに名称をつけてスレッド数を管理するのは面倒です。

スレッド名を無名にして、vectorに格納しても同じ処理でのスレッド名に意味はないからその方が便利です。

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <cmath>

std::mutex mtx_;                // mutex for exclusive control
std::vector vec{};         // prime numbers array
int cal_int = 1;                // calc target integer
int max_int = 10000000;         // calc target max number
std::vector threads;       // array of threads
int num_thread = 12;                    // number of threads



void add_prime(int i)           // store the prime numberns in the vector
{
    std::lock_guard lock(mtx_);
    vec.push_back(i);
}

int get_int()                   // get the integer to be tested
{
    std::lock_guard lock(mtx_);
    ++cal_int;
    if (cal_int > 2 && cal_int%2 == 0)      // do not return an even number larger than four
    {
        ++cal_int;
    }
    return cal_int;
}

void ThreadA()
{
    while (true)
    {
        bool flag = false;
        int i = get_int();
        if (i > max_int)
        {
            break;
        }
        int sqt = sqrt(i);
        for (int j = 2; j <= sqt; ++j)
        {
            if (i%j == 0)
            {
                flag = true;
                break;
            }
        }
        if (flag != true)
        {
            add_prime(i);
        }
    }
}

int main()
{
    std::chrono::system_clock::time_point  start, end;
    start = std::chrono::system_clock::now();

    std::cout << std::endl;
    std::cout << "Hardware concurrency = " << std::thread::hardware_concurrency() << std::endl;

    for(size_t i=0; i < num_thread; ++i){
        threads.emplace_back(std::thread(ThreadA));
    }

    for(auto& thread : threads){
        thread.join();
    }

    std::cout << std::endl;
    std::cout << "Number of threads = " << num_thread << std::endl;

    std::cout << std::endl;
    end = std::chrono::system_clock::now();
    double elapsed = std::chrono::duration_cast(end-start).count();
    std::cout << "elapsed time : " << elapsed << " ms" << std::endl;

    std::cout << std::endl;
    std::cout << "number of prime numbers : " << vec.size() << std::endl;

    std::cout << std::endl;
    std::cout << "last five prime numbers" << std::endl;
    std::sort(vec.begin(), vec.end() );
    
    for (auto itr = (vec.end() - 5); itr != vec.end(); ++itr)
    {
        std::cout << *itr << std::endl;
    }

}

こうすれば、変数を一箇所変えるだけでスレッド数が自由に変更できます。4以上の偶数は素数判定スレッドに渡さないで、処理時間短縮も図っています。

 

<実行結果>

Hardware concurrency = 12

Number of threads = 12

elapsed time : 1358 ms

number of prime numbers : 664579

last five prime numbers
9999937
9999943
9999971
9999973
9999991

https://isehara-3lv.sakura.ne.jp/blog/2022/05/01/c-マルチスレッドの効果/

で、およそ1.8秒でしたが1.3秒程度まで高速化。所詮、多数桁の素数計算には誤差とも言える範囲ですが。

 

admin

 

c++ マルチスレッドの効果

マルチスレッドは多くのアプリケーション、わかりやすいのはブラウザあたり、で普通に使われてますが、多重度を上げても必ずしも性能が向上するわけではありません。それはリソースの排他制御などでオーバーヘッドが発生するから。

で、素数計算プログラムでマルチスレッドの効果を検証してみた。

<ソースコード>

スレッド制御はstd::threadクラスを使います。

https://cpprefjp.github.io/reference/thread/thread.html

スレッドプログラミングで問題になる共通リソース、この場合には計算対象の整数(cal_int)と計算結果の格納(vec{})を排他制御(mutex)で、壊れないように制御します、理屈はセマフォーと同じです。

同じ処理の多重化ならば、特定の関数をスレッド化する訳なので、元のコードは一個で構いません。

スレッド数の可変は対象部分(std::thread th_x(ThreadA); とth_x.join();)をコメントアウトで対応。

算出結果のvectorはスレッドの出力タイミングでソートされた結果にはならないから、処理完了後にソートを実行。

スレッド処理の記述は、

https://qiita.com/nsnonsugar/items/be8a066c6627ab5b052a

を参考。

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <cmath>

std::mutex mtx_;                // mutex for exclusive control
std::vector vec{};         // prime numbers array
int cal_int = 1;                // calc target integer
int max_int = 10000000;          // calc target max number


void add_prime(int i)
{
    std::lock_guard lock(mtx_);
    vec.push_back(i);
}

int get_int()
{
    std::lock_guard lock(mtx_);
    ++cal_int;
    return cal_int;
}

void ThreadA()
{
    while (true)
    {
        bool flag = false;
        int i = get_int();
        if (i > max_int)
        {
            break;
        }
        int sqt = sqrt(i);
        for (int j = 2; j <= sqt; ++j){
            if (i%j == 0){
                flag = true;
                break;
            }
        }
        if (flag != true){
            add_prime(i);
        }
    }
}

int main()
{
    std::chrono::system_clock::time_point  start, end;
    start = std::chrono::system_clock::now();

    std::cout << std::endl;
    std::cout << "Hardware concurrency = " << std::thread::hardware_concurrency() << std::endl;

    std::thread th_a(ThreadA);
    std::thread th_b(ThreadA);
    std::thread th_c(ThreadA);
    std::thread th_d(ThreadA);

    th_a.join();
    th_b.join();
    th_c.join();
    th_d.join();

    std::cout << std::endl;
    end = std::chrono::system_clock::now();
    double elapsed = std::chrono::duration_cast(end-start).count();
    std::cout << "elapsed time : " << elapsed << " ms" << std::endl;

    std::sort(vec.begin(), vec.end() );
    for (auto itr = (vec.end() - 5); itr != vec.end(); ++itr){
    std::cout << *itr << std::endl;
    }

    return 0;
}

 

<実行結果>

対象が百万までではスレッド数が2以上による実行時間の差はほとんどない。スレッドの実行時間よりもオーバーヘッドの方が支配的だからだろう。

一方、千万までの計算ではスレッド処理の比重が増加して、スレッド数を増やせば実行時間は速くなるから、スレッド処理が支配的になるせいでしょう。

Hardware concurrency = 12

—100000まで計算—

1 thread

elapsed time : 223 ms
999953
999959
999961
999979
999983


2 threads 

elapsed time : 177 ms
999953
999959
999961
999979
999983


3 threads

elapsed time : 184 ms
999953
999959
999961
999979
999983


4 threads

elapsed time : 194 ms
999953
999959
999961
999979
999983


—10000000まで—

1 thread

elapsed time : 4519 ms
9999937
9999943
9999971
9999973
9999991


2 threads

elapsed time : 2646 ms
9999937
9999943
9999971
9999973
9999991


3 threads

elapsed time : 2103 ms
9999937
9999943
9999971
9999973
9999991


4 threads

elapsed time : 1829 ms
9999937
9999943
9999971
9999973
9999991



 

という結果が言わんとすることは、各スレッドの処理が重ければCPUのマルチコアが有効に働く、しかし処理が軽いとオーバーヘッドによりほとんど実行時間には影響しない。もちろんマルチスレッドの目的は処理の分散・並行処理による高速化以外に各スレッド処理のリアルタイム性の側面もあるのだから、一概には言えないわけだけれども、いずれにしろ適用アプリケーションを事前に考慮した上での実装が必要という当たり前の結論です。

 

admin

 

PyBind11 for c++

c++の高速性が必要でなおかつ、Pythonの書きやすさが必要な場合にはPythonからc++の処理の呼び出しが必要です。

いろいろな方法がありそうですが、PyBind11は2011年ごろに登場と比較的に新しく、それ故に機能も洗練されているだろうから動かしてみた。

ネットにも情報が多いから問題解決が難しくないだろうと思う。

<本家>

https://pybind11.readthedocs.io/en/stable/index.html#

“pybind11 is a lightweight header-only library that exposes C++ types in Python and vice versa,”

とあるようにpythonからc++も呼べるし、逆もまた可なりのヘッダーファイルライブラリにすぎないと。

<install>

$ pip3 install pybind11

—Installed path—

/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pybind11/include/pybind11

<sample program & compile>

https://qiita.com/takuyakubo/items/b7503d7555bbc6c44aba

このリンク先にある、以下のclangコンパイルで作成できた。本家のドキュメントと全く同じですが。

% clang++ -O3 -Wall -shared -std=c++17 -fPIC `python -m pybind11 –includes` -undefined dynamic_lookup py_call.cpp -o example`python3-config –extension-suffix`

『コンパイラオプションは、最適化(-O3)、共有ライブラリとしてビルド(-shared -fPIC)、言語標準の指定(-std=c+17)、インクルードディレクトリの追加( `python3 -m pybind11 –includes`)、コンパイル対象(py_call.cpp)、出力(cpplcm`python3-config –extension-suffix`)となります』

https://buildersbox.corp-sansan.com/entry/2019/12/09/110000

の説明から引用。

<sample code : py_call.cpp>

PYBIND11_MODULE以下がマクロで、pybind11で解釈されます。

m.def()中の”add”はPythonから呼び出される時の関数名で、&addはint add()関数がそれに相当すると定義しています。

#include <pybind11/pybind11.h>

int add(int i, int j) {

  return i + j;

}

PYBIND11_MODULE(example, m) {

  m.doc() = "pybind11 example plugin";                          // optional module docstring

  m.def("add", &add, "A function which adds two numbers");

}


<call from python>

コマンドラインで実行して、import exampleが実行できればモジュールが作成できています。

% python

Python 3.10.3 (v3.10.3:a342a49189, Mar 16 2022, 09:34:18) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin

Type "help", "copyright", "credits" or "license" for more information.

>>> import example

>>> example.__doc__

'pybind11 example plugin'

>>> example.add(24, 43)

67

作成されるのは、共有ライブラリファイルで、”example.cpython-310-darwin.so“がPythonから呼び出されるファイルになります。MacOSなのでこんな名前になります。Pythonも実装はcだから、インターフェースは出来て当たり前ということでしょう。

-rwxr-xr-x   1 hogehoge  staff  148016  4 28 10:07 example.cpython-310-darwin.so

このケースは一番単純な機能確認ですが、実際には配列などを引数にするときにはc++とPython間で何らかの変換が必要になるでしょう。

 

admin

‘wchar.h’ file not found #include_next

久々CMake使おうとしたら、buildでこのようなエラーが発生。

解決方法は、

https://qiita.com/m0n0/items/b13998de1da4c7c1964d

中にある、

% make SDKROOT=`xcrun --show-sdk-path` MACOSX_DEPLOYMENT_TARGET=
[ 33%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[ 66%] Building CXX object CMakeFiles/main.dir/header.cpp.o
[100%] Linking CXX executable main
[100%] Built target main

を実行すると解決。Xcodeに関連するようで、おそらくMacOSのアップデートと関係するようです。

以前のcmake記事

https://isehara-3lv.sakura.ne.jp/blog/2022/03/03/cmakec-ビルドツール/

 

admin