ブログ - 最新エントリー

ExcelでDXLIB2を動かす

カテゴリ : 
その他
2011-2-1 17:08
2011/2/2 dxlib2 Ver2.2公開にあたり

各開発環境毎でdllの扱いが違いすぎてごっつ使い辛いのがイラついたので、再度更新。
V2.0およびV2.1の使用を即刻中止し、V2.2に移行する事を強く推奨。

たびたびの修正ご容赦を。


これまで、Java,Ruby,Pythonよりdxlib2を使用したDynamixelの動作確認を行ってきた。

諸々試し始めている方は気付かれているかも知れないが、dxlib2はVBからの利用ができなくなっている。dxlib2の関数呼出規約がcdeclになっているが故に、VBから見えないという訳である。

そこで、VBないしVBAからの呼出しを可能にするため、dxlib2 Version2.1から呼出規約のデフォルトをstdcallに変更することとした。

それに伴う影響が以前紹介した言語にどこまで波及するか確認してみた。Javaはラッピング関数作成時のリンカオプションに-mrtdを付加することで解決。Pythonはcdllクラスからwindllクラスことで解決。Rubyに至っては影響なしという結果だった。
Ruby恐るべし。

肝心のVB(ここではExcelのVBA)での使用だが、通常のAPI呼出しと同様にdxlib2内の関数を適宜Declareするだけで使用することができる。
検証環境は以下の通り。
  1. OS: Windows 7(32bit)
  2. Microsoft Excel
  3. dxlib2 V2.1
準備はdxlib2.dllと同一フォルダに適当なExcelファイルを作成するだけ。
  1. VBAサンプル
    サンプルとして0~10のIDにPingを発行して結果をメッセージダイアログに表示する。
    宣言
    Declare Function DX_OpenPort Lib "dxlib2.dll" (ByVal pcom As String, ByVal br As Long) As Long
    Declare Function DX_ClosePort Lib "dxlib2.dll" (ByVal id As Long) As Boolean
    Declare Function DX_Ping Lib "dxlib2.dll" (ByVal devid As Long, ByVal uid As Byte, ByVal tout As Integer, ByRef terr As Integer) As Boolean
    本文抜粋
    Dim sMsg As String
    Dim devid As Long
    Dim i As Integer, terr As Integer
    Dim vRet As Variant
    ChDrive ActiveWorkbook.Path
    ChDir ActiveWorkbook.Path
    devid = DX_OpenPort("\\.\COM3", 1000000)
    If devid = 0 Then
    MsgBox "Port open failed!", vbCritical, "COMポートオープン失敗"
    Else
    For i = 0 To 10
    vRet = DX_Ping(devid, i, 50, terr)
    If vRet Then
    sMsg = sMsg & i & " Alive" & Chr(13) & Chr(10)
    Else
    sMsg = sMsg & i & " Dead : " & Hex(terr) & Chr(13) & Chr(10)
    End If
    Next
    DX_ClosePort devid
    End If
    MsgBox sMsg, , "DXLIB2 TEST"
  2. 実行結果

EXCELであればセルにデータを保持すればグラフなり何なりにする事も可能だが、既にdxlib2 V2.1のサンプルとして同梱されてるのでそちらをを参考に。

それと、dxlib2 V2.1をGCC Developer Liteで使う際は、コンパイルオプションに -mrtd を付けてビルドしないと自殺アプリになってしまうのでご注意を。

PythonでDXLIB2を動かす

カテゴリ : 
その他
2011-1-28 13:40
RubyでDXLIB2を動かすことができたので、更なるお試しとしてPythonでDXLIB2を動かすサンプルを作成してみた。
検証環境は以下の通り。
準備はRubyと同様、パスを通してHWの接続を確認。
  1. Pythonソース
    サンプルとして0~253のIDにPingを発行して結果をプロンプトに表示する。
    <SMPL1.py>
        from ctypes import *
    import sys
    # load library
    dxlib2 = cdll.LoadLibrary("dxlib2.dll")
    dxopen = dxlib2.DX_OpenPort
    dxclose = dxlib2.DX_ClosePort
    dxping = dxlib2.DX_Ping
    # set types for return and parameter of API
    dxopen.argtypes = [c_char_p, c_long]
    dxopen.restype = c_void_p
    dxclose.argtypes = [c_void_p]
    dxping.argtypes = [c_void_p, c_ubyte, c_int, c_void_p]
    # initialize
    terr = c_ushort()
    comport = "\\.\COM3"
    baudrate = 1000000
    timeout = 100
    procsw = 0
    OK = 1
    NG = 0
    cr = "\n"
    lf = "\r"
    # call API
    devid = dxopen( comport, baudrate )
    for idx in range(254):
    result = dxping( devid, idx, timeout, byref(terr) )
    if result == OK:
    sys.stdout.write( "\n%d alive" % idx )
    procsw = 0
    else:
    if procsw == 0:
    sys.stdout.write( cr )
    else:
    sys.stdout.write( lf )
    sys.stdout.write( "%d dead(%x)" % (idx,terr.value) )
    procsw = 1
    sys.stdout.flush()
    dxclose( devid )
  2. 実行
    a).以下のファイルが同一フォルダ内に存在していることを確認。
    SMPL1.py  dxlib2.dll
    b).コマンドプロンプトで実行。
    > python SMPL1.py
    結果はこんな感じ。

雑感、Rubyと同様、簡単にDynamixelの制御が可能となった。
ただ、Rubyよりもコーディングに若干のクセがあるようだ。

RubyでDXLIB2を動かす

カテゴリ : 
その他
2011-1-24 16:52
JavaからDXLIB2を動かすことができたので、引き続きお試しとしてRubyでDXLIB2を動かすサンプルを作成してみた。
検証した環境は以下の通り。
Rubyのパスを通し、HWを接続したら準備完了。
  1. Rubyソース
    サンプルとして0~253のIDにPingを発行して結果をプロンプトに表示する。
    <SMPL1.rb>
    require "dl/import"
    module DXLIB2
      extend DL::Importer
      dlload "./dxlib2.dll"
      extern "int DX_OpenPort( char *, long )"
      extern "int DX_Active( int )"
      extern "int DX_Ping( int, unsigned char, int, unsigned short * )"
      extern "int DX_ClosePort( int )"
    end
    comport = "\\\\.\\COM3"
    br = 1000000
    timeout = 50
    terr = ' ' * 2
    mark = "\n"
    devid = DXLIB2.DX_OpenPort( comport, br )
    if ( devid != 0  ) then
      ret = DXLIB2.DX_Active( devid )
      if ( ret == 1 ) then
        sleep 1
        i = 0
        while ( i <= 253 )
          ret = DXLIB2.DX_Ping( devid, i, timeout, terr )
          if ( ret == 1 ) then
            printf( "\n%d alive", i )
            mark = "\n"
          else
            printf( "%s%d dead(%x)", mark, i, terr.unpack('S')[0] )
            mark = "\r"
          end
          i += 1
        end
      end
      ret = DXLIB2.DX_ClosePort( devid )
      if ( ret == 0 ) then
        print "CLOSE ERROR\n"
      end
    end
    print("\nnormal end")
  2. 実行
    a). 以下のDLLとソースファイルが同じフォルダに存在していることを確認。
    SMPL1.rb  dxlib2.dll
    b). コマンドプロンプトで実行。
    > ruby SMPL1.rb
    結果はこんな感じ。
雑感、Javaよりは簡単だった。Ruby恐るべし。

New ZEAL

カテゴリ : 
新商品
2011-1-20 18:11
リリース中のBluetoothモジュール ZEAL-C01 は一部パーツの廃盤に伴い既に再生産は終了。在庫が終了次第おニュー版に移行する予定です。
外形やI/Fは互換性を有しますが、ソフト的な互換性が保てないのがつらいところ。

現在評価中ですが、量産等のまとまったご注文の際は ZEAL-C02 でのご提案になると思われ、先行して詳細な情報を入手されたいといった場合はこちらをご参照ください。

Javaついでに

カテゴリ : 
雑記
2011-1-18 15:50
猫も杓子もAndroid。寄らば大樹の陰といった所なのだろうか。


それはさておき、今のところAndroid端末は野良アプリのインストールを許容しているので、Javaついでという事で遊んでみた。

端末単体で動くアプリを作っても味気ないので、ちょっと欲張って大概の携帯についてるBluetoothを使ったRC-100Bモドキアプリにトライ。

RC-100BはBluetoothとしてマスターにしかならないが、今回のアプリではスレーブ構成でFDIII-HCへつなぎに行く事にした。基本的に公開されているチャットアプリのサンプルをちょっといじくっただけなので、ペアリング等のお膳立てがちゃんとしていないとうまくつながらなかったり、デザインなんぞ無視してたり、Android 2.2以上でないと動かないといったトコはご愛嬌。マルチタッチにまともに対応している端末であれば、ボタンの同時押しは一応再現できるといったところ。

動いてるとこの絵


後はGUIを凝ってみたり、一方通行の通信を双方向にてステータスをモニタしたりぶるぶるさせてみたり、勝手に死なないようにしてみたり、なんて事ぐらいだろうか。

怪しい野良アプリをインスコできる勇者はこちらからどうじょ。

JavaでDXLIB2を動かす

カテゴリ : 
雑記
2011-1-17 17:02
じゃばじゃばうるさいので、お試しとしてJavaからDXLIB2を動かすサンプルを作成してみた。
検証した環境は以下の通り。
お試しという事もあり、細かい事は抜きに動けばOKといったノリで条件付け。
  • DXLIB2を直接呼出すことはできないため、一旦ラッピング用DLLを作成する。
  • ラッピング関数名は使用するJavaのクラス名に依存。
  • unsigned short型やlong型はJava上でintとして使用する。
    必要に応じてラッピング関数内で型変換。
  • 全て同一フォルダ内に収める。
  • コンパイラ等へのパスは適宜通しておく。
スペースの都合かなり端折ってるが、こんな感じでやるのかなといった雰囲気だけ。
  1. Javaソース
    サンプルとして0~253のIDにPingを発行して結果をプロンプトに表示するソース。
    <SMPL1.java>
    public class SMPL1 {
      private native int DxOpenPort( String com, int br );
      private native boolean DxClosePort( int devid );
      private native boolean DxPing( int devid, int uid, int tout, char[] terr );
      static {
        System.loadLibrary( "dxtest" );  // 今回作成するラッピング用DLL(dxtest.dll)
      }
      public static void main( String args[] ) {
        String COMPORT = "\\\\.\\COM3";  // COMポート名
        int BUADRATE = 1000000;  // ボーレート
        int TIMEOUT = 50;  // タイムアウト
        char terr[] = new char[1];
        int devid, i;
        String msg = "Ping to ID:", mrk = "\n";
        SMPL1 me = new SMPL1();
        devid = me.DxOpenPort( COMPORT, BUADRATE );
        if ( devid != 0 ) {
          for ( i = 0; i < 253; i++ ) {
            if ( me.DxPing( devid, i, TIMEOUT, terr ) ) {
              System.out.printf( "\nPing to ID:%d...OK", i );
              mrk = "\n";
            }
            else {
              System.out.printf( "%sPing to ID:%d...NG(%x)", mrk, i, (int)terr[0] );
              mrk = "\r";
            }
          }
          if ( !me.DxClosePort( devid ) ) System.out.printf( "Close error\n" );
        }
        else
          System.out.printf( "Port not open\n" );
      }
    }

  2. ラッピング関数名の取得
    a). Javaソースをコンパイル(SMPL1.classを作成)。
    >javac SMPL1.java
    b). ヘッダファイルを作成(SMPL1.hを作成)。
    >javah -classpath . -d . SMPL1
    以下作成されるヘッダファイルの抜粋。
    <SMPL1.h>
    JNIEXPORT jint JNICALL Java_SMPL1_DxOpenPort  (JNIEnv *, jobject, jstring, jint);
    JNIEXPORT jboolean JNICALL Java_SMPL1_DxClosePort  (JNIEnv *, jobject, jint);
    JNIEXPORT jboolean JNICALL Java_SMPL1_DxPing  (JNIEnv *, jobject, jint, jint, jint, jcharArray)

  3. Cソース作成
    a). SMPL1.hをdxtest.cに変更。
    b). ラッピング関数の中身を作成。
    JavaとDLLの仲介役だが、相互の規約を気にしないと話にならない。とりあえず最低限必要なOpen/Close/Pingだけ作った。
    <dxtest.c>
    #define __MAKE_LIB__
    #include <stdio.h>
    #include <stdlib.h>
    #include <jni.h>
    #include "dxlib2.h"
    JNIEXPORT jint JNICALL Java_SMPL1_DxOpenPort
      (JNIEnv *env, jobject jobj, jstring pCom, jint br) {
      DXDEVICEID dev;
      char *port;
      int sz = (*env)->GetStringLength( env, pCom );
      // java文字列より取得
      const char *comPort = (*env)->GetStringUTFChars( env, pCom, 0 );
      port = (char *)malloc( sz + 1 );
      strcpy( port, comPort );
      port[strlen(port)] = 0x0;
      dev = DX_OpenPort( port, br );  // dxlib2.dllのDX_OpenPort()の呼出し
      // memory解放
      free( port );
      (*env)->ReleaseStringUTFChars( env, pCom, comPort );
      return (jint)dev;
    }
    JNIEXPORT jboolean JNICALL Java_SMPL1_DxClosePort
     (JNIEnv *env, jobject jobj, jint id) {
      return DX_ClosePort( (DXDEVICEID)id );
    }
    JNIEXPORT jboolean JNICALL Java_SMPL1_DxPing
      (JNIEnv *env, jobject jobj, jint devid, jint id, jint tout, jcharArray terr) {
      TDxErrorCode  err;
      BOOL      bResult;
      UCHAR   uID;
      jchar        *arrays; // local領域
      int             sz;         // 配列size
      jboolean jbl;         // isCopy
      uID = (UCHAR)(id & 0x00ff);
      bResult = DX_Ping( (DXDEVICEID)devid, uID, tout, &err );
      // 配列の取得
      arrays = (*env)->GetCharArrayElements( env, terr, &jbl );
      if ( (*env)->GetArrayLength( env, terr ) > 0 ) arrays[0] = err;
      // 配列の解放(Javaへ適用)
      (*env)->ReleaseCharArrayElements( env, terr, arrays, 0 );
      return bResult;
    }

  4. DLL作成
    a). dxtest.cをDLLにする。
    >gcc -shared -o dxtest.dll dxtest.c -l dxlib2 -Wl,-kill-at -I Javaのincludeパス -I Javaのincludeパス\win32 -L .
    Javaのincludeパスに空白が含まれている場合はダブルクォーテーションで括る等の措置を講じるべし。

  5. 実行
    a). 以下のDLLとクラスファイルが同じフォルダに存在していることを確認。
    SMPL1.class  dxtest.dll  dxlib2.dll
    b). おもむろにコマンドプロンプトで実行
    >java SMPL1
    実行結果はこんな感じになるだろうか。

雑感、何が楽しいのかさっぱり・・・。

インターンシップ

カテゴリ : 
その他
2011-1-17 13:59
今年も3ヵ月間電子回路・プログラミングなどを学びに、海外から研修に来ている女子学生がいます。
来日した当初は挨拶以外の日本語ができず、コミュニケーションは全て片言の英語。既に1ヵ月が経った事もあり、日常会話であれば多少なりとも何が通じる様になりましたが。
おかげで私のボディーランゲージの勉強になりましたw。

自学自習にも熱心に取り組んでくれるおかげで、毎日夜遅くまで帰ってくれません。しかし、プログラム言語と電子回路はほぼ世界共通ですので、ここで得た知識が将来役に立つ日が来る事でしょう。

日本にもこういった学生がもっと増えると嬉しいですねぇ。

Dynamixel Library2の64bit対応

カテゴリ : 
その他
2010-12-6 19:13
今週中には詳細と正式版を公開する予定ですが、多少ご要望がありましたWindowsの64bitネイティブに対応中です。とはいっても単にコンパイラが64bitに対応していれば良いまでで、インストーラのサイズが肥大化するのですが同梱する方向で検討しています。

その他に先に問題を言ってしまうと、実際には正常に処理されている通信がWindowsからの応答遅延によりタイムアウトになるといったケースは回避不能ですので悪しからず。
また、ftdi社の仮想シリアルドライバが頻繁にバージョンアップしている様なので、PCに合わせてドライバのバージョンを選ばないとパフォーマンスに影響を及ぼす様です。

MATLAB EXPO 2010

カテゴリ : 
イベント
2010-11-30 17:38
11月26日(金)に開催されましたMATLAB EXPO 2010展示コーナーにおいて、弊社のコントローラおよびDynamixel RX-28を使用したロボットアームを展示していただきました。

MATLAB Simulinkのリアルタイムシミュレーションを使用したアプリケーションの紹介として、Windows上のMATLABからDynamixelコンフィギュレータを介してロボットアームをコントロールするデモを行いました。



また、MATLAB上のソースをEmbedded Corderで組み込み向けマイコンのソースに変換し、FDIII-HCから制御させるといった手法も紹介しました。



低コストなMATLAB Simulinkの教材です。ご興味をお持ちの方は弊社にお問い合わせ下さい。

FDIIIでToppers

カテゴリ : 
TOPPERS
2010-11-16 22:17
FDIII-HCのブートローダのアップデートと同時に、GCC Developer Liteも新しいライブラリを同梱して公開する旨のニュースがありました。
実際何をやってるかというと、ToppersをFDIII-HCに適用するネタでして、本家ではかなり昔から移植されていたのですが、とっても煩雑なためにGCC Developer Liteのライブラリとして同梱させるまでには至っていませんでした。
既にAT91SAM7S単体とUD3でToppersが使用できるようになっているので、そのリソースを利用してユーザーアプリケーション内でマルチタスクが実現できるように仕込中といった所です。

従来のインターバル割り込みで駆動される似非タスクでは即時復帰を要求されるために、処理時間が長いサブルーチンをバックグラウンドで走らせることができなかったのですが、Toppersのタスクを使用していろんなことを同時にかつテキトーに動かすなんて事が簡単になるはず。

公開までもう少しだけお待ちください。