watermint.org - Takayuki Okazaki's note

BromptonとGarmin Varia RTL515のマウント

そろそろ乗り始めて丸6年になる折り畳み自転車Bromptonにサイクルコンピュータを導入することにしました。

昨年からiPhoneを使ってWithingsのHealth Mateアプリを使ったり、Stravaアプリを使ったりしてサイクリングの記録を残していましたが、 うまく記録が取れないことが増えてきていました。 ネットワークの調子なのかBluetoothの調子なのか、GPS信号がうまくiPhoneで取得できていないのか原因は定かではないですが 100kmぐらい走ったなかの前半50kmぐらいしか記録されていなかったり、全く記録されていなかったりと安定しません。

いろいろ検討の結果対策としてサイクルコンピュータ Garmin Edge 530 を導入しました。 今回はこのサイクルコンピュータと連動して使えるテールライト、Varia RTL515のお話。 このRTL515を使うと、レーダーで後続の車やバイクなどが接近してきたことをEdge 530と連動してアラームを出したり後方の状況が確認できます。

Garmin Edge 530とVarita RTL515

上図は実際にアラームが出ている状態です。写真では信号待ちで停車中ですが、後ろから車が接近していることを検出してアラームと表示で警告が出ています。

このように車やバイクなどが急接近すると赤色表示になって、複数台車がきていれば右側の丸印が複数表示されるという仕組みです。 最近はEVやハイブリッド車など静かに近づいてくる車も増えましたし、自転車専用道路を走っていても後ろからロードバイクなどで全速力で飛ばしてくる方もがいるのでヒヤヒヤします。 良識ある方々はスピードを落とした上で「通りま〜す」など、一声かけてくださるのですが残念ながらそういった方は少数で、強引に抜かそうとされる方も多く自衛手段を検討せざるを得ません。 こういったヒヤヒヤが少しでも緩和されるという意味ではとても価値のある製品かと思います。

さて表題の通りRTL515というテールライトのマウントについてですが、Bromptonは折り畳み自転車ということもあってマウントできる位置が限られます。 折りたたんだ後でも干渉しない位置にマウントしたかったのですが標準添付されているゴムパッドではうまく取りつきません。 どうしようか思案していたところ、面ファスナーで設置することを思いつきました。

Varita RTL515のマウント

少し強引ですがRTL515標準付属のシートポストマウントには幅1cm程度の穴が空いています。ここに面ファスナーを通して、ぐるりと回して取り付けました。 ややぐらぐらしますが、面ファスナーの安定性が高いので標準のゴムパッドで付けるよりはなんとなく面ファスナーの方が信頼性がありそうにも感じます。

面ファスナー

さて、この面ファスナーですが100円均一にちょうどいいサイズ感の物がありました。この製品の1cmの幅というのがなかなか絶妙で幅は調整することなくこのまま利用できました。 同じようにブロンプトンにRTL515をマウントさせようという方のご参考になれば幸いです。

Migrate to Cloudflare Pages

I mentioned that this site moved from GitHub Pages to Cloudflare Workers. This time, I changed the infrastructure to Cloudflare Pages. This change will not affect tracking code removal.

CLI (command-line utility) for Excel files

I added Google Sheets commands to watermint toolbox release 85. At the same time, I added Excel file commands to the tool.

For example, the export command will export data as CSV or JSON from the .xlsx file. The tool runs on multiple platforms without complex dependencies. Just download & extract executable file from the archive. Currently, the tool run on Windows (x86/amd64), Linux (x86), and macOS (amd64).

Export data

Export data from the .xlsx file

To retrieve data from an Excel file, run the following command.

$ tbx util xlsx sheet export -file EXCEL_FILE_PATH -sheet SHEET_NAME

If you want to specify output path, please add -data PATH_TO_EXPORT option. Please see more detail about the command at the command manual

Import data

Import data into the .xlsx file

To import data into an Excel file, run the following command.

$ tbx util xlsx sheet import -file EXCEL_FILE_PATH -sheet SHEET_NAME -data DATA_PATH

Please see more detail about the command at the command manual

CLI (command-line utility) for Google Sheets

I added commands to deal with spreadsheets in watermint toolbox release 85. With these commands, you can export data from Google Sheets as CSV or JSON. Or, update Google Sheet with CSV file from the command line.

The tool runs on multiple platforms without complex dependencies. Just download & extract executable file from the archive. Currently, the tool run on Windows (x86/amd64), Linux (x86), and macOS (amd64).

Exporting data

Google Sheet Export

To retrieve data from Google Sheet, run the following command.

$ tbx services google sheets sheet export -id GOOGLE_SHEET_ID -range SHEET_NAME

If you want to specify output path, please add -data PATH_TO_EXPORT option. Please see more detail about the command at the command manual.

(Sorry for the long command name. Because the tool now has 200+ commands. :-)

Importing data

Google Sheet Import

To import data from CSV, run the following command.

$ tbx services google sheets sheet import -id GOOGLE_SHEET_ID -range SHEET_NAME -data DATA_FILE_PATH

The command changes only cell values. Please see more detail about the command at the command manual.

More commands

The latest release contains a few more commands to deal with Google Sheets.

Note:

The registration to Google is currently verification in progress.

Warning

You may see the warning on the authorization screen. Please verify safety before proceed it.

発掘昔のコード(1996年, C++): コンパイラと実行環境

ファイルを整理していたところ、高校生の頃に作ったコードが出てきたので25年ぶりに実行してみました。当時、郵便配達のアルバイトで購入したBorland C++を使って作っています。C++やオブジェクト指向についても図書館に通い少しこなれてきた頃に作ったもので、産業フェアというイベントに出展した記憶があります。プログラムは大きく分けて二つあり、BASICを参考にした簡単なスクリプト言語をバイトコードに変換するコンパイラと、MS-DOS画面ながらもマルチウインドウの仮想マシンです。

実行した様子

高校の図書室にあったコンパイラの解説本やスタックマシーンについて説明している本を参考にしつつ、当時話題のJavaやバイトコードといったエッセンスを混ぜて作ったのを思い出しました。コンパイラの部分をみてみると、実装逆ポーランド記法などへの変換などもがんばって実装しているのが懐かしいです。

void
Compile::ReversePolishNotation( int argc , char **argv )
{
  struct lsElement
  {
    int    r ;         //  優先順位
    char*  symbol ;    //  識別子
    int    output ;    //  出力
  } ;

  lsElement  elements[] =
  {
     { 0 , "'" , bc_nop }  //  NULL
  ,  { 1 , "and" , bc_and }
  ,  { 1 , "or" , bc_or }
  ,  { 1 , "xor", bc_xor }
  ,  { 2 , "<" , bc_lt }
  ,  { 2 , "<=" ,bc_le }
  ,  { 2 , "==" ,bc_eq }
  ,  { 2 , "!=" ,bc_ne }
  ,  { 2 , ">" , bc_gt }
  ,  { 2 , ">=" , bc_ge }
  ,  { 3 , "+" , bc_add }
  ,  { 3 , "-" , bc_sub }
  ,  { 4 , "*" , bc_mul }
  ,  { 4 , "/" , bc_div }
  ,  { 4 , "mod" , bc_mod }
  } ;
  
  const int  StackSize  = 256 ;
        
  //  '(' は 100
  //  としてスタックに積むことにします
  const int  vLeft    = 100 ;
  
  int  ss[ StackSize ] ;
  int  sp = 0 ;
  int  i ;
  int  j ;
  int  f ;  //  一致するものがあったかどうかのフラグ
  int elementnum = sizeof( elements ) / sizeof( elements[ 0 ] ) ;
  DataId  id ;
  
  ss[ sp ] = 0 ;
  
  for ( i = 0 ; i < argc ; i++ )
  {
    f = 0 ;
    
    for ( j = 0 ; j < elementnum ; j++ )
    {
      if ( strcmp( argv[ i ] , elements[ j ].symbol ) == 0 )
      {
        if ( ss[ sp ] == vLeft )
        {
          sp++ ;
          ss[ sp ] = j ;
        }
        else
        {
          if ( elements[ ss[ sp ] ].r >= elements[ j ].r )
          {
            id.value = 0 ;
            csPut( elements[ ss[ sp ]].output , id ) ;
            ss[ sp ] = j ;
          }
          else
          {
            sp++ ;
            ss[ sp ] = j ;
          }
        }
        f = 1 ;
        break ;
      }
    }
    
    if ( !f )
    {
      if ( strcmp( argv[ i ] , "(" ) == 0 )
      {
        sp++ ;
        ss[ sp ] = vLeft ;
        continue ;
      }
      
      if ( strcmp( argv[ i ] , ")" ) == 0 )
      {
        if ( ss[ sp ] != vLeft )
        {
          id.value = 0 ;
          csPut( elements[ ss[ sp ]].output , id ) ;
        }
        sp-- ;
        if ( sp < 0 )
          sp = 0 ;
        
        continue ;
      }
      
      if ( isalpha( argv[ i ][ 0 ] ))
      {
        id = VarId( argv[ i ] ) ;
        csPut( bc_push , id ) ;
      }
      else
      {
        long v = atol( argv[ i ] ) ;
        id.PutType( 0x01 ) ;
        id.PutVal( v ) ;
        csPut( bc_push , id ) ;
      }
    }
  }
  
  while ( sp != 0 )
  {
    if ( ss[ sp ] != vLeft )
    {
      id.value = 0 ;
      csPut( elements[ ss[ sp ]].output , id ) ;
    }
    sp-- ;
  }
}

実行対象となるプログラムはカレンダーを表示するプログラム、素数の計算、フィボナッチ数列など4つほどでしたが、当時単体テストすらまともに実施しておらず、サンプルコードの問題なのかコンパイラの問題なのか、ランタイムの問題なのかデバッグは困難を極めあまり複雑なコードは時間切れで作れなかった記憶があります。

'  LeftScript Sample Program
'  (c) by Takayuki Okazaki 1996
'  $Id: prime.ls 1.1 1996/11/03 17:53:09 Okazaki Exp Okazaki $

print "素数を求める"

e = 1000  ' 何処まで求めるか

i = 2
c = 1
print c , "個目の素数は" , i , "です"
c = c + 1
for i = 3 to e
  y = 0
  for j = 2 to i - 1
    if i mod j == 0 then
      y = 1
    endif
  next
  
  if y == 0 then
    print c , "個目の素数は" , i , "です"
    c = c + 1
  endif
next

print "1 から" , e , "までの整数のうちの素数は以上です"

実行環境は擬似マルチタスクで、各プログラムのバイトコードを1つ実行するたびに次のプロセスの実行に移ります。一応、キー入力などの実行命令も作っていたのでIO待ちなどの状態管理もしていました。仮想マシンのクラス定義をみてみると、スタックメモリはメインメモリの制約からかファイル上にマッピングしていたようです。

class ByteComputer : public UserWin
{
private :
  char  ls_filename[ asd_BufSize ] ;
  char  cs_filename[ asd_BufSize ] ;
  char  ds_filename[ asd_BufSize ] ;
  
  FILE*  stack ;
  FILE*  ds ;
  FILE*  cs ;
  long   sp ;
  DataId io_port ;
  int    status ;

  void   Push( DataId x ) ;
  DataId Pop() ;
  DataId GetVar( DataId x ) ;
  void   Input() ;
  
public :
  ByteComputer( const char *filename ) ;
  ~ByteComputer() ;
  
  virtual  int         InputChar( int c ) ;
  virtual  procStruct  GenUser() ;
} ;

コンパイラと実行環境合わせて全体で5000行ほどのプログラムです。記憶が正しければ当初は情報処理技術者試験で使われていたCASLアセンブリ言語のコンパイラとCOMET実行環境を作る予定でしたが仕様がそれなりに大きく間に合わないと判断してより簡易的なスクリプト言語の実装という方向性になったのだと記憶しています。