アルトラ PARADIGMとOn Cloudflyerのレビュー

自分の足に合う靴を探して、アルトラのPARADIGMとOnのCloudflyerの2つを購入。前回は買って実物を見てみたとこまで書きました。
alasixosaka.hatenablog.com
今回は、実際に履いて走ってみた感想です。

まずはアルトラのPARADIGMから

altrafootwear.jp
外観は見ての通り、お世辞にもスタイリッシュという感じではありません。どちらかというを無骨な感じ。重量は300gを越えてランニングシューズとしては重い部類に入ると思います。
足を入れた感じは、幅広で足先も余裕があり、かなりゆったりとした感じです。
走り始めは靴の重量でやや重く感じます。ゼロドロップというのはあまり感じません(あくまで個人の感想ですが)。クッションはそこそこという感じでしょうか。HOKAを履いているとどの靴もクッションは劣るように感じるのでそんなもんかなと思います。ドロップが低いというのはニュートンのシューズと同じコンセプトですが、ニュートンのように自然に足が前に出るという感じはありません。その分自分の足で走っているという実感が出てきます。
まだ坐骨神経痛が気になるのでロードを7㎞ほどしか走っていませんが、足先に関しては、このシューズが最もゆったりしていると思います。幅も広く、幅広の自分でも余裕を感じるくらいで、逆に幅の狭い人はゆとりがありすぎて履きにくいかもと思ってしまいました。かなり靴ひもをきつく締めてようやく丁度という感じでした。こんな靴は初めてです。
ただ、ゼロドロップのため、走り終わった後はふくらはぎに軽い張りを感じました。これは、ニュートンのシューズでも同じです。アルトラのHPには普段8㎞走る人はまず800mから始めてと書いてあります。ニュートンのシューズをちょこちょこ履いているので、私の場合はそこまで足にきませんでしたが、いきなり普通の靴からアルトラを履くと足にくるのではないかと思います。

次はOnのCloudflyer

www.sportsauthority.jp
買ったのは旧モデルの方です。安くなっているのでサイズが合えばお買い得かもしれません。
スタイルはこっちのほうが圧倒的にかっこいい。色も新モデルより旧モデルの青が個人的にはお気に入りです。
足を入れた感じは、PARADIGMよりもやや窮屈に感じるものの、それほどきついわけではないくらい。クッションについてもそこそこで、PARADIGMと同じくらいに感じました。固い路面でもそれほど衝撃を感じることはないです。普通のCloudを普段履きに使っていますが、Cloudだと結構足に衝撃を感じます。Cloudflyerはそれに比べるとショックは全く感じません。走り始めは、幅がややきつく感じました。自分の足は幅広なのでこういう感じがすることが結構多いです。たいていはしばらく走ると気にならなくなるので大きなトラブルになることはないです。今回もしばらく走ると気にならなくなりました。アッパーの素材が固くないので足になじんでくるのかもしれません。Cloudflyerでは9㎞ほど走りました。こちらもロードを走りました。走った感じは、ややニュートンのシューズに近く足が自然に前に出る感じがしました。ニュートンよりはその感じは弱めではありましたが。走りやすいのは走りやすいのかなと思いました。ちょっと調子に乗ると4㎞/㎞台にスピードが上がっていました。あまり早く走るつもりはなかったのですがついついスピードが出てしまう感じですね。そのへんはしつこいようですがニュートンのシューズに近い感じです。足先は距離が短いこともあって特に気にならなかったです。

総括

今回2つのシューズを履き比べてみて、どちらが長距離向けかというとPARADIGMの方かなという感じがしました。これは足にあうあわないというのを評価基準にしています。クッションとか走りやすさといった仕様で判断すると別の結果になると思います。あくまで、足先が当たらず、血豆にならないということを基準に考えています。ただし、ドロップがゼロという極端な低さなので、足(ふくらはぎ)をもう少し鍛えないと足の方が長い距離には耐えられないと思います。そしてもう一つ、今回の新しいシューズを眺めてみて、あることに気が付きました。そして手持ちのシューズをその観点で比較し、ますますその思いを強くし、今回2足を履き比べてほぼ確信に近い思いになりました。それは、ある方法で自分の足に合うシューズを見分けるというものですが、詳しくはまた次回にでも書いてみたいと思います。

ランニングシューズ探し

坐骨神経痛の方はようやく回復してきた。今回は思ったより大変だった。結局注射を3回する羽目に。1回目は痛めた3日後、2回目がその3日後、更にその1週間後と計3回。注射は即効性があるが、効き目が切れると痛みが再発し、その都度注射を打ってもらった。始めはロキソニンの投薬で何とかしようとしたのだが、アレルギー体質で足にむくみが出たのでロキソニンは1回/1日として、後は注射とリハビリで回復させるという療法になった。
ところで、坐骨神経痛もさることながら、足の爪に内出血がでた。昔から長い距離を走ると内出血することがあったが、最近は頻発するようになり、特に、東海自然歩道を二ノ瀬から大津まで走った時に両方の足の爪に内出血ができてしまった。
alasixosaka.hatenablog.com

その後、ネットで調べたりして靴紐の結び方を変えて少し改善したが、それでも坐骨神経痛になった時はせっかく治りかけていた爪がまた内出血してしまった。
cotanote.hatenablog.com
runsmile.fun
ちなみに、今試している紐の結び方は、下の方のリンクサイトに書いてあるヒールロックという方法です。足が靴の中でなるべく動かないように足首のところで固定するようになります。
元々はオーバーラップという方法で結んでいました。これは、短距離向きの結び方なのだそうです。でも、ランニングシューズって買うと大概オーバーラップの紐の通し方で箱に入ってたりするので、今まで何の疑問も持たずにこの結び方をしていました。アンダーラップという方法もあってこっちのほうが長距離向きなのだそう。こちらも家の中だけで試した感じはオーバーラップよりは足首が固定できそうだが、ヒールロックの方がよさそうな感じでした。
先日のランではそれでも右足に内出血できてしまい、結び方が甘かったのかもしれないが、靴にも原因があるかもしれないと思い始めた。東海自然歩道の時はHOKAのスピードゴートを履いていて、先日は、HOKAのクリフトンを履いていた。HOKAの靴は履き心地が抜群で、足を入れたときの感覚も問題ないし、長距離の時はHOKAを選んでいたが、思い切って別の靴を試すことにした。今回購入したのは2足。
足にやさしいシューズはナイキやアシックスも出しているが、自分の場合は基本がフォアフットで走るのでドロップの大きいシューズはあまり履きたくないということで選択した。
まずは、トレランシューズでお世話になってるOn RunningのCloudflyer。

ドロップは7㎜でロードロップとは完全には言えないレベルかも知れないがOnの中では低い方。ちなみに、HOKAのクリフトンはドロップは4㎜。
サイズはいろいろ悩んで結局25.5cmを選択。Onのトレランシューズが25.5㎜で丁度良い感じだったので26㎜は大きいかもしれないと思った。足を入れてみるとサイズ感はトレラン用のCloudventureとほぼ同じで25.5㎜でいい感じだった。クッションはOnの中では柔らかめということで、まだ家の中でしか履いていないが、結構クッションを感じる。もちろんHOKAなんかのフワフワ感はないけど。あと、Cloudflyerの特徴は靴紐を通すところが変わっている。
普通は靴ひもを通すところは穴が開いているのだが、Cloudflyer場合、靴の先の方にひも状の輪っかがあって、そことその一つ下側の穴を使ってクロスのような感じで紐を通している。下の写真の左足の方がその通し方。右足はヒールロックにしてみた。左右アンバランスなのが気になるが面白いのでちょっとこれで走ってみようと思っている。

f:id:alasixOsaka:20210321105721j:plain
左足が箱から出したまま、右足はヒールロックに直している

次に、アルトラのPARADIGM 5。
altrafootwear.jp
こちらはゼロドロップを謳うシューズ。自分の持っているシューズの中ではニュートンのMotion9がドロップが3㎜で最も低いモデル。ニュートンも履きやすくて走りやすいモデルで気に入っているが、難点はふくらはぎに結構負担が来るということ。このシューズを履いて走るとあとでふくらはぎに張りが強く出る。ドロップの低い靴に履き慣れていないとそうなるらしいが、HOKAとニュートンで1㎜しかドロップが変わらないのにふくらはぎの張り具合はかなり違うのがちょっと不思議な気がしている。おそらくシューズのコンセプトからして違うのだと思う。ニュートンは自然に足が前に出るような独特のソールの形状をしていて、本当にその通りにどんどん足が前に出てしまう。自然に任せて走ってしまうとあっという間に5分/㎞を切るスピードが出てたりする。足が十分に鍛えられて早く走るのには良いシューズだと思う。ということで、ニュートンのシューズは今のところ短い距離のトレーニングにだけ使っている。HOKAは足にやさしいシューズというコンセプトなのでそこまで負担が来ないのかもしれない。
アルトラのシューズはいろいろラインナップがあって、レース用から長距離ラン用、更にはトレラン用のシューズも展開している。今回は長距離用の靴が欲しいのでアルトラの中でもクッション性の大きなPARADIGMを選んだ。PARADIGMはサイズが25.5㎜の設定が無く、25㎜の上は26㎜になっている。そこで、こちらのサイトを参考に自分の足を測ってみた。
blog.stridelab.jp
すると足の長さは25cmくらいだったので、+1.3cmすると26.3cmとなる。普通に考えると26.5cmのシューズがいいのかもしれないが、いままでそんな大きなサイズの靴は履いたことがないので、ここは26cmにしてみた。26cmはたまにメーカーによっては選ぶことがあるのでありかも知れないと思った。昔、ナイキのシューズは26cmがぴったりだった。最近はナイキのシューズは足の型が変わってしまって自分の足には全然合わなくなっている。ナイキの厚底も試してみたい気がするが足に合わないので今のところは無理みたいだ。
アルトラのシューズに戻って、PARADIGMの26cmを履いてみるとサイズは丁度良い感じだった。サイズ的には他社の25.5cmよりほんの少し大きいという感じか。ゼロドロップは歩いてみるだけでわかる感じで本当に足が地面と平行になっているように感じる。これで長い距離を走ったらどうなるのか少し不安はあるが試してみようと思う。アルトラの公式HPにも、初めは普段8㎞走っている人は800mから始めて見て下さいと書いてある。
altrafootwear.jp
自分の場合HOKAやニュートンなどのロードロップを普段履いているのでそこまで極端にする必要はないのかもしれないが、いきなり20㎞とかはやはり冒険になりそうなので少しずつ履きならしてみたい。

ついでに、インソールも試してみようと思っている。前から気になっていたフォームソテックスというインソール。
formthotics.jp
こいつは、履いていると自然に自分の足に合うように変形して足にピッタリのインソールができるというもの。自分の足を測って自分の足にピッタリのインソールを作るのが理想なんでしょうが、そうすると1足2万円くらいしてシューズより高くついたりする。さすがにまだそこまでは必要ないかなと思って、とりあえずこれを試してみることにした。今回購入したCloudflyerかPARADIGMのどちらにしようかまだ迷っている。とりあえず1回ずつ試しに走ってみてから考えようと思っている。

Android 地図アプリの修正

少し前に書いたように、開発した地図アプリに不具合があったので修正を試みました。
alasixosaka.hatenablog.com

今回はソースコードの修正部分だけを書いています。ソースコードの全体は過去の記事を見て下さい。
alasixosaka.hatenablog.com
alasixosaka.hatenablog.com
alasixosaka.hatenablog.com

POIファイル選択時にテーマ選択画面がオーバーラップして表示される

今回初めてPOIファイルを本格的に活用したのですが、メイン画面から”SELECT POI FILE"をタップしてファイル選択画面を出すと、引き続きテーマ選択画面が表示されるようになっていました。
これは単純なミスで、メイン画面で各種設定選択画面でタップするところの処理でBreakが抜けていたためでした。具体的には、”MainActivity.java”の”public void onClick(View view){”以下のところで下記のように、case R.id.btPOISelect:のところの最後にBreakを追加しました。

case  R.id.btPOISelect:
                    preferences = getSharedPreferences("DATA", Context.MODE_PRIVATE);
                    Path = preferences.getString("path", sdPath);
                    fillter = "poi";
                    FileListDialog dlg2 = new FileListDialog(MainActivity.this);
                    dlg2.setOnFileListDialogListener(MainActivity.this);
                    dlg2.show(Path,Path,fillter);

                    break;

頻繁にアプリが再起動する

前に書いたように、この症状が一番困ったことでした。アプリが頻繁に再起動して地図もまともに読めないし、再起動すると軌跡が消えてしまう、更に再起動を繰り返しているうちにアプリが落ちてしまうということまで起こった。端末を再起動すると症状は少し改善したが、結局この日は、あまり長い時間地図を見ずにだましだまし使うことでなんとか対処した。帰ってから少し調べて原因は端末が向きを検知して画面を回転させているためだと推定した。地図アプリ専用端末にするなら端末側の設定で回転を固定してしまえば問題ないが、他のアプリも使う場合はアプリ側で回転しないように固定してやる必要がある。
設定は、"android.manifest.xml"を書き換えることで行う。"activity"の部分で元のファイルでは特に方向指定をしていなかった。

   <activity android:name="com.example.mpf_rotationE.RotateMapViewer" />
        <activity android:name="com.example.mpf_rotationE.RotateMapViewer2"/>
        <activity android:name="com.example.mpf_rotationE.ThemeSelect"></activity>
        <activity android:name="com.example.mpf_rotationE.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.example.mpf_rotationE.SimplestMapViewer"
            android:configChanges="keyboardHidden|orientation|screenSize" />
        <activity
            android:name="com.example.mpf_rotationE.OverlayMapViewer"
            android:configChanges="keyboardHidden|orientation|screenSize" />
    </application>

回転してしまって困るのは、地図を表示する部分なので、初めの2つ、"RotateMapViewer"と”RotateMapViewer2"にスクリーン方向を指定するandroid:screenOrientation="portrait"を追記した。

<activity
            android:name="com.example.mpf_rotationE.RotateMapViewer"
            android:screenOrientation="portrait" />
        <activity
            android:name="com.example.mpf_rotationE.RotateMapViewer2"
            android:screenOrientation="portrait"/>
        <activity android:name="com.example.mpf_rotationE.ThemeSelect"></activity>
        <activity android:name="com.example.mpf_rotationE.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.example.mpf_rotationE.SimplestMapViewer"
            android:configChanges="keyboardHidden|orientation|screenSize" />
        <activity
            android:name="com.example.mpf_rotationE.OverlayMapViewer"
            android:configChanges="keyboardHidden|orientation|screenSize" />
    </application>

現在地がずれる

現在地のマーカーが何故だかずれていて、ズレはそれほど大きくなかったのでそれほど大きな影響はなかったが、なんとなく気持ち悪いので調べてみた。
どうやら、Androidの仕様が9以降で変更になっているみたいで、Android StudioエミュレータでAndoroi8では正しく表示されるのに、Android9ではずれることが確認できた。地図の縮尺も、キャプチャのサイズも違ってちょっと不細工だが、下の図で比較すると、Android8では正しく現在地の円が表示されているのに対し、Android9では精度の円の中心が正しい現在地なのだが、現在地表示の円は右下にずれている。

f:id:alasixOsaka:20210306131823j:plain
Andoriod9では現在地がずれている。

このずれの原因はどうやらAndroidの仕様変更に伴うようで(調べてもよくわからんかったが)、図形を描写するときにAndroid8以前であれば、図形の中心を描写する中心点にして描いていたものが、変わっているようだ。
ちなみに、現在地を示すマーカーは42×42のグラフィックスで描かれているので、オフセットの位置を調整して42ポイントずらすようにしたらよいかと思ってやってみたら、ずらしすぎになってしまい35ポイントずらすと丁度良い位置に表示された、何故35ポイントなのかは謎。
修正ポイントは"OverlayMapViewer.java"の”protected void createLayers(){"以下のMakerを指定する部分のMarker marker=...でMarkerを指定するところで、以前は最後のオフセット値を0,0としていた(一番下の行)。

protected void createLayers() {
        super.createLayers();
        //setGPS=(SamplesApplication)getApplication();
        globals=(SamplesApplication)getApplication();

        // we just add a few more overlays
        //Layers y = mapView.getLayerManager().getLayers();
        addOverlayLayers(mapView.getLayerManager().getLayers());
        //Layers z =mapView.getLayerManager().getLayers();
        Drawable drawable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? getDrawable(R.drawable.ic_maps_indicator_current_position) : getResources().getDrawable(R.drawable.ic_maps_indicator_current_position);
        Marker marker = new Marker(null, AndroidGraphicFactory.convertToBitmap(drawable), 0, 0);

この部分をAndroidAPIを判断して、27以下ならオフセットを0、28以上ならオフセットを-35とした。オフセットの値は変数ofsetに持たせて、if文でAPIを判断して代入している。

protected void createLayers() {
        int ofset = 0;
        super.createLayers();
        //setGPS=(SamplesApplication)getApplication();
        globals=(SamplesApplication)getApplication();

        // we just add a few more overlays
        //Layers y = mapView.getLayerManager().getLayers();
        addOverlayLayers(mapView.getLayerManager().getLayers());
        //Layers z =mapView.getLayerManager().getLayers();
        Drawable drawable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? getDrawable(R.drawable.ic_maps_indicator_current_position) : getResources().getDrawable(R.drawable.ic_maps_indicator_current_position);
        if (Build.VERSION.SDK_INT <= 27){
            ofset = 0;
        }else if (Build.VERSION.SDK_INT >= 28) {
            ofset = -35;
        }
        Marker marker = new Marker(null, AndroidGraphicFactory.convertToBitmap(drawable), ofset, ofset);

POIの追加

今まではPOIとしては矢印だけだったのですが、この際なので少しマークを追加してみました。
追加したのは、トイレ、レストラン、水場、チェックポイントの4つです。コンビニも入れようかと思いましたが、まあレストランマークで代用できるので良しとしました。
ただ、これらのマーク(以前からある矢印も含めて)やっぱり、Android9ではずれるので対策が必要でした。
以前にも書いたように、POIを表示させるためのファイルはカシミール3Dで作成しています。したがって、カシミール3D上のアイコンと地図アプリのアイコンに相関を持たせる必要があります。
alasixosaka.hatenablog.com

まずは、マークの追加から。カシミール3D側はもともとあるものを使っています。

カシミール3Dでのアイコンの決定

トイレはGarmin GPS カラーアイコンのアウトドアの中にあるトイレです、GPXファイルに書き出した場合の記号は952010でした。
レストランは同じくGarmin GPS カラーアイコンのスポットの中にあるレストランです、GPXファイルに書き出した場合の記号は956005でした。
水場は同じくGarmin GPS  カラーアイコンのアウトドアにある水場です、GPXファイルに書き出した場合の記号は959037でした。
チェックポイントは同じくGarmin GPS カラーアイコンのマークの赤旗、GPXファイルに書き出した場合の記号は951003でした。

f:id:alasixOsaka:20210307101720j:plain
カシミール上でPOIアイコンを配置した様子。右からトイレ、レストラン、チェックポイント、水場
Androidアプリ上で表示するための画像を作成

次に、Androidアプリ上で表示するための画像を作成します。
ネット上で適当に無料素材をダウンロードして使いました。
ダウンロード素材は背景が透明の場合もありますが、背景が白だったりすることもあるのでその場合は、少し加工が必要です。
今回はPowerPointを背景を透明にしてみました。まず、PowerPointで新規ファイルを作成します。
ここに、ダウンロードした画像を挿入します。挿入→画像→このデバイスからファイルを選択して挿入します。
挿入した画像をクリックし、書式タブを選択、色をクリックして、透明色指定をクリックします。画像の背景の部分をクリックすれば背景が透明になります。
出来た画像は右クリックして、図として保存、保存形式はpngです。画像サイズは適当に調整してください。30-50ピクセル四方くらいが適当なサイズだと思います。
ちょっとめんどくさいですがこうすれば背景は透明にできます。

Android Studioで画像の読み込み

出来た画像をAndroid Studioに読み込みます。
Android Studioでプロジェクトを開き、左のペインのdrawableを選んだら、左端の縦タブのResource Managerをクリックします。ここでタブがdrawableになっていることを確認し、左上の「+」をクリック、import drawableをクリックします。するとファイル選択画面が表示されるので作成した画像ファイルを選択します。背景が透明になっていれば、グレーのチェッカー模様が背景になっているのでここで確認できます。

プログラムの修正

POIで配置するアイコンもやはりAndroid9ではずれることが分かったので、修正が必要です。アイコンの位置を決めている部分は、現在地を表示している”OverlayMapViewer.java"と同じファイル内にあり、”addOverlayLayers(Layers layers) {”の中に書いてあります。ここではGPXファイルを解析してルートを表示し、POIファイルを解析してアイコンを表示しています。めちゃめちゃ長いですが、下の方のPOIファイルを解析する部分の下に”POIname"でswitch~ case でそれぞれのアイコンに対する画像を読み込んでmarkaersにaddしています。例えば、左折の矢印1番の場合case"1001009"以下の部分で処理を行っています。

try {
            String listXmlPath = Path + "/"+ POI_FILE;
            is = new FileInputStream(new File(listXmlPath));
            BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
           ~省略~
           
                    case XmlPullParser.TEXT:
                        POIname = xpp.getText();
                        Log.i("MainActivity", "テキスト = " + POIname);

                        if (XPname.equals("icon")){
                            switch (POIname) {
                                case "1001009":
                                    markers.add( Utils.createTappableMarker(this, R.drawable.left1, latLongX));
                                    break;
                                case "1001010":
                                    markers.add( Utils.createTappableMarker(this, R.drawable.left2, latLongX));

ところが、この処理の部分”markers.add( Utils.createTappableMarker(this, R.drawable.left1, latLongX));”では、オフセットを設定することができないので、この部分を下記のように変更します。

Drawable drawable = getResources().getDrawable(R.drawable.left1);
Bitmap bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
Marker poimarker = new Marker(latLongX, bitmap, ofset, ofset);
markers.add( poimarker);

ちょっとめんどくさいですが、一旦画像をdrawableに読み込んで、ビットマップに変換し、poimarkerに位置とビットマップとオフセットを設定してからmarkersにaddしています。こうすることでオフセットが設定できます。オフセットの値"ofset"は現在地表示の時と同様にandroidAPIで判断して”0"か"-40"を設定するようにしています。本当は画像ファイルのサイズがそれぞれ微妙に違うので正確に表示するためには個別に設定したほうが良いのですが、処理が煩雑になることと、POIの位置についてはそれほど厳密でなくても実用上差し支えないと判断して一律の値にしています。

int ofset =0;
if (Build.VERSION.SDK_INT <= 27){
   ofset = 0;
}else if (Build.VERSION.SDK_INT >= 28) {
   ofset = -40;
}

実際の地図上にはこんな感じで表示されます。

f:id:alasixOsaka:20210307113314j:plain
エミュレータ上でPOIのアイコンを表示

実機(AQUOS SENSE PLUS)でも問題ないことが確認できました。

参考にしたサイト
[Android] Activity のライフサイクルと画面の回転
AndroidOSのバージョン(APIレベル)によって処理を変える方法 | 一番かんたんなJava入門
パワーポイントで簡単に画像の背景を透過するかんたんな方法│BtoBのデジタルマーケティング戦略ラボ
mapsforge でポップアップするマーカーを試す - プログラマーのメモ書き
【2021年度版】無料&商用利用できるフリーアイコン配布サイト14選! | S.Design.Labo

アンドロイドアプリの不具合発見、そしてまたも故障

先週の土曜日に受験生の子どもたちの合格祈願とトレーニングを兼ねて、近所の神社を走って巡ることにした。最大の目標は茨木神社。このあたりでは高槻の天神さんと並んで格式のある神社だし、上の子は茨木の高校に通っているし、下の子は茨木の高校を受験するので、ここには是非行かないとということで、茨木神社を折り返しにして、近所のランニングコース途中で見かける神社や、北摂フォトロゲでチェックポイントになっていた神社、更にグーグルマップで調べた神社などを組み込んでコースを設定し走ることにしていた。

スタート早々にアプリが不具合

コースを自作の地図アプリに入れて持っていったが不具合が発覚。

 

 

alasixosaka.hatenablog.com

 

 

alasixosaka.hatenablog.com

 

いつもはXperiaZ4に入れて持っていくところを、今回は荷物を軽くするためとトレランやロングライドのときと違って時間が短いということもあってメインで使っているAquasSensePlusを持ってでかけた。ところが、今まで気づかなかったが、AquasSenseだとすぐにアプリが落ちて再起動がかかる。おまけに現在地が微妙にずれる。ずれは小さいのでまあ気にならなくもない程度で我慢できるが、アプリが頻繁に落ちるのは結構閉口した。こんなことならZ4を持って来ればよかったと後悔した。家に帰ってから、少し考えて頻繁に落ちるのはだいたい原因が予想できた。今度時間のあるときにプログラムを見直してみようと思っている。しかし、現在地がずれるのは原因がさっぱりわからない。Z4なら問題ないのにAquasSenseだとずれるとは。もうそろそろAquasSenseも引退して地図アプリ専用にしようかと思っていたところなので不具合はなんとかしないとと思っている。しかし、結構長いことアプリのプログラムを見ていないので簡単に治せる気がしない。困ったもんだ。

そして、足にまた故障

正月に30kmのトレランを近所で走ったときに、いつもはなんともない左足の外側の付け根あたりに強いこりが出た。このときはすぐに治ったが、それ以降走るたびに同じところがこるようになった。しかし、普段は強く抑えない限り何ともなかったので今回も大丈夫と思って走り始めたが、走り始めてすぐに違和感を感じ始めた。今までは長い距離を走った後半か、走った後にコリが出る感じだったが、走り始めてすぐに違和感が出たのは初めてだった。それでも少し痛いが走るのにそれほど支障がないのでなんとかなると思って走り続けたが、茨木神社の手前で痛みが強くなり走るのが辛くなった。それでも今回は茨木神社にはなんとしても行かないとと思って少し無理して走り続け、なんとか茨木神社のお参りを済ませて帰る途中でピキッと来て、そこから走るどころかまともに歩くこともできなくなった。仕方ないので、予定のコースは諦めてショートカットして歩いて家に帰った。帰ってからも痛みが引かず、今日になってもまともに歩けない状態なので、病院に行って見てもらった。診察の結果は筋肉のトラブルに加えて腰の影響がかなりあるのではということだった。もともと腰が悪くて骨と骨の感覚が若干狭いところがあり(いわゆるヘルニアというやつ)、時々病院で引っ張ってもらっていたのだが、今回は腰には違和感がまったくなかったので油断していた。病院で腰を引っ張ってもらい、電気治療してマッサージしてもらったらだいぶ良くなった。マッサージしてもらっているときに腰のあたりをもんでもらうと結構張っているのがわかって知らない間に腰にも疲れが溜まっていたのかもしれない。

緊急事態宣言が開けたら、六甲山の全縦をしようと思っていたがしばらくは休養とリハビリになりそう。

今回は腰にも来ているのでチャリでも無理はできないし、おとなしくしているしかなさそうだ。ロードバイクは腰に負担がかかるので、前回腰が痛くなったときはドクターストップがかかった。今回はそれはなかったが、なんとコルセットを巻いて走れと言われた。ちょっとびっくり。まあ、とりあえず今週は休養に当てて(天気もよくなさそうだし)、来週あたりに試してみようと思う。

ステッピングモータを2つ同時に動かす

ちょっと間があいてしまいましたが、電子工作ネタのステッピングモータを動かすシリーズの続きです。

前回はリミットスイッチを使ってステッピングモータを停止するということをやりました。

 

 

alasixosaka.hatenablog.com

 

今回は、2つのモーターを同時に動かすということをやります。

今回のお題は、わかってしまえばなんてことないのですが、CNCシールドの使い方が今ひとつわかってなかったのでまたしてもハマってしまいました。自分の恥を晒すようなもんですが、備忘録と同じようなことをやろうとしている人の参考になればと思って書きます。

CNCシールドの同期機能

CNCシールドにはモータードライバーを4つ刺すことができます。それぞれX、Y、Z、Aと名前がついています。

f:id:alasixOsaka:20210205205516j:plain

CNCシールドにはドライバを4つ刺すところがある。X,Y,Z,Aとなっている。

X、Y、ZはそれぞれX軸、Y軸、Z軸用という意味合いです。それではAはというと、X軸、Y軸、Z軸のいずれかと同期させることができます。CNCシールドの左下の部分にジャンパーピンを刺すところがあり、X、Y、Zとラベリングされています。X、Y、ZのいずれかとAを同期させるためには、ジャンパーピンをジャンパーさせて使用します。例えばXとAを同期させたければXの部分をジャンパーします。

f:id:alasixOsaka:20210205205954j:plain

 

ということで早速やってみました。

 

f:id:alasixOsaka:20210206211703j:plain

写真のような感じでステッピングモータを2つ平行に並べて配置し、モーターにはネジ山の切った棒をカップリングを使って接続してあります。ネジ棒には例の四角い箱が刺してあって、それぞれが縦方向の柱に通してある滑車に接続しています。滑車の台どうしをL字の金具を使ってアルミの角棒につないでいます。つまり、2つのモーターを同時に動かすことでアルミの角棒が上下に動きます。Arduinoのスケッチは初回のものと同じものです。すなわち前進1000ステップ、後退1000ステップを行い無限ループに入ってストップします。

ところが、下には動くのですが上には動きませんでした。はじめは、写真をみてわかるよう角棒にステッピングモータがつけてあるので(こいつの使い方はまた次回にでも書いてゆきます)、重くて上に動かないのかと思って、角棒を外して見たら、なんと片方は上下に動かず下向きに2度動いていることが判明しました。

ここで前回の悪夢が蘇ってきました。前回もステッピングモータの方向転換が働かずに一方向のみに動く現象が出ました。そのときはモータードライバーを交換することで正常に動作するようになりました。ただ、今回は新しいドライバーを使ったのでまた壊れたということは考えにくかったのです。何はともあれ検証のため色々と接続を変えて試してみました。まず配線を入れ替えると、モーターの動きが左右逆になり、正常に動いていたのがダメになって、ダメだったほうが正常に動いたので、モーターには問題がないことがわかりました。

次にダメだった方のケーブルを別のものに交換してみましたが症状は変わらずケーブルにも問題がないことがわかりました。次にドライバーの刺す位置を変えて、Y軸、Z軸でも試してみました。また、ドライバーも入れ替えて見ました。その結果A軸だけが正常に動作しないということがわかりました。ここでCNCシールド自体の問題ではないかと考えましたが、冷静になってもう一度回路図を見直してようやく気が付きました。

ジャンパーピンは一つではダメ

ジャンパーピンは何をしているかというと、Arduinoからのシグナルをブリッジして2つのモータードライバーに同じシグナルを送るようになっています。ブリッジするのはStepとDirの2つです。ですのでジャンパーピンも2つ必要です。

 

 

f:id:alasixOsaka:20210205210247j:plain

CNCシールドの回路図。ジャンパーはStepとDirの両方をジャンパーする必要があることがわかる。

写真のようにZ軸ならZとプリントしてあるところの隣の2ピンをジャンパーし、更にその隣の2ピンもジャンパーする必要がありました。

 

f:id:alasixOsaka:20210206212252j:plain

 

ほんとわかってしまえば何でもないことですが、これにハマってああでもないこうでもないと結局2日がかりでした。

 

 

参考にしたサイト

全自動成形綿あめ機械と印刷クッキーの開発日記: CNCシールドを流用するにあたってのメモ

 

Zaim用データ変換Pythonスクリプトを改良

前回、ZaimのエクスポートデータをLet's家計簿で読めるように変換するPythonスクリプトを作りました。
alasixosaka.hatenablog.com
しかし、少々使いづらいところがあったので改良を行いました。
具体的な改良点は3点。

  1. スクロールに対応
  2. 口座の情報をデフォルトで入れるように変更
  3. 日付のフォーマットを修正

スクロールに対応

前回のスクリプトでは多数のレシートを読み取った場合に画面からはみ出してしまって見えなくなるという不具合がありました。
エクスポートするデータの件数を絞れば対処できますが、そうすると読み取ったデータを一度に処理することができないのでこのままでは少々不便。なのでスクロールできるようにに改良しました。
PythonGUIであるTkinterにはスクロールバーという機能があり、これを使えばよいのですが、今回のスクリプトのようにたくさんのウィジェットをいっぺんにスクロールしようとすると少し工夫がいります。
前回は、Tkinterの親画面であるrootにframeを貼りつけ、ここにラベルとコンボボックスを直接貼り付けていました。こうすると実はスクロールバーが使えないのです。そこで、canvasという主にグラフィックなどを書くためのウィジェットを使います。まず、rootにcanvasを貼りつけ、その中にframeを貼りつけ、frameにラベルとコンボボックスを貼りつけます。スクロールバーはrootに貼り付け、canvasの横につけます。
文字で書くとややこしいですがこんなイメージです。

f:id:alasixOsaka:20210130184544j:plain
左が前回。右が改良後。

canvasをスクロールするのに色々試行錯誤していじくっているので前のスクリプトと見た目が結構変わってしまっていますがやっていることはほぼ一緒です。まず関係するところだけ抜き出します。

root = tk.Tk()
root.title(u"Zaimデータ変換")
root.geometry("500x500")


~ 省略 ~

#キャンバスエリア
canvas = tk.Canvas(root, width = 400, height = 500)#Canvasの作成

frame = tk.Frame(canvas)

ます、500×500のrootを作成し、それに400×500のcanvasを貼りつけます。そしてそのcanvasにさらにframeを貼りつけています。
ウィジットを貼りつける部分はframeにウィジットを貼りつけるので処理は同じです。ウィジットをframeに貼り付けた後、canvas.create_window(0, 0, anchor='nw', window=frame)として、canvas中の左上にframeを表示させ、
scroll = tk.Scrollbar(root, orient="vertical", command=canvas.yview)としてスクロールバーをrootに貼りつけます。scroll.grid(row=0, column=1, sticky='ns')でスクロールバーは、0行、1列目に配置。sticky='ns'は上下方向に貼りつくという意味です。canvascanvas.grid(row=0, column=0, ) として0行、0列に置いています。次に canvas.configure(yscrollcommand=scroll.set)としてスクロールバーを有効化し、最後にcanvas.configure(scrollregion=canvas.bbox("all"))として、スクロール範囲を指定しています。今回は全スクロールを指定してます。

    for i in range(m):

        list_Items[k] = ttk.Combobox(frame,values=valuelist,width=10)
        list_Items[k].grid(row=i+1, column=2)
        
  ~ 省略 ~

        k+=1
    canvas.create_window(0, 0, anchor='nw', window=frame)
    scroll = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
    scroll.grid(row=0, column=1, sticky='ns')
    canvas.grid(row=0, column=0, )  # Canvasの配置
    canvas.configure(yscrollcommand=scroll.set)

  ~ 省略 ~

    canvas.configure(scrollregion=canvas.bbox("all"))

これでラベルとコンボボックスをずらずらと貼り付けたcanvasがスクロールします。

口座情報のデフォルト設定

zaim を使っていて気がついたんですが、レシートの項目にメモという自由記述欄があります。メモに口座情報を入力しておけばエクスポートしたデータに反映されるので、こいつを読み込んでコンボボックスにデフォルトで表示させるようにしました。メモ欄の入力は自由記述なので何でも入力する事ができます。ですがプログラム上では、コンボボックスにプルダウンで表示するテキストと比較しているので両者が正確に一致する必要があります。一致するテキストがリストにない場合コンボボックスのデフォルトは空欄になります。
実はこの空欄は便利な使い方があって、既に一旦Let's家計簿に読み込んであるデータも一緒にエクスポートしてしまった場合、コンボボックスを空欄にして口座情報を入力しないでおくとLet's家計簿にインポートされません。ですので重複してインポートされないようにするために便利に使えます。zaim のデータエクスポートは日付指定でエクスポートされるので、後から古いレシートが出てきてスキャンした場合など、既にLet's家計簿にインポートしたデータも一緒にエクスポートされる事になります。こんな時にこの機能は便利に使えます。
まず、メモ欄を読み込むところですが、メモ欄はrow[7]に入りますので、それを一旦str=row[7]としてstrに代入し、nullでなければkozaxに代入。if shop!=oshop以下の部分(店の名前が更新されたところ)でkozal.appned(kozax)として口座情報をリストkozalに追記しています。

    for row in reader:

        if n != 0:
            shop = row[8]
            date = row[0]
            str = row[7]
            if str !="":
                kozax = str
            if shop =="-":
                shop = oshop
            if shop != oshop:
                shoplist.append(shop)
                datelist.append(date)
                kozal.append(kozax)
                kozax=""
                n=n+1
            oshop = shop

口座情報の表示は、ok_ckick関数のところで、if kozal[k] in valuelistとしてkozalのリストの中身とvaluelistを比較して一致するものがあれば、kozai=valuelist.index(kozal[k])でリストの何番目と一致するかをkozaiに代入し、list_item[k].current(kozai)としてデフォルトで表示するようにしています。

def ok_click(m):
    ~省略~
    valuelist = ['現金', ’カード', 'ICOCA']
    for i in range(m):

        list_Items[k] = ttk.Combobox(frame,values=valuelist,width=10)
        list_Items[k].grid(row=i+1, column=2)
        if kozal[k] in valuelist:
            kozai=valuelist.index(kozal[k])
            list_Items[k].current(kozai)
       

日付のフォーマットの修正

zaim からエクスポートしたデータの日付のフォーマットは“2021-01-20”というように年と月、月と日の間をハイフンでつないだ形式になっています。Let's家計簿では日付のフォーマットは“2021/01/20”というようにハイフンではなくスラッシュを使わないと正しく読んでくれません。
実はこれははじめのうちは気がついていませんでした。何故かと言うとはじめのうちは確認のため一旦エクセルで開いてからセーブしたデータをLet's家計簿にインポートしていたからです。一旦エクセルで開いてからセーブすると何故か日付のフォーマットが変わってしまってLet's家計簿に対応したフォーマットになっていました。この事自体知らなかったのですからpython で変換したデータを直接Let's家計簿にインポートする迄全く気が付きませんでした。
ハイフンをスラッシュに変換するのは簡単で、date = row[0].replace("-","/")とすればできます。

実行結果はこんな風になり、口座情報の欄はメモに記入した情報がデフォルトで表示されます。また、あふれた行はスクロールで表示させることができます。

f:id:alasixOsaka:20210205204100j:plain
メモに入れた現金がデフォルト表示、行があふれたらスクロールできるようになった。

全文です。

import csv,sys,os,tkinter.filedialog, tkinter.messagebox
import tkinter as tk
import tkinter.ttk as ttk

def ok_click(m):
    list_Items = [0]*m
    shop_Items = [0]*m
    date_Items = [0]*m
  
    k=0
    N=m
     valuelist = ['現金','カード', 'ICOCA']
    for i in range(m):

        list_Items[k] = ttk.Combobox(frame,values=valuelist,width=10)
        list_Items[k].grid(row=i+1, column=2)
        if kozal[k] in valuelist:
            kozai=valuelist.index(kozal[k])
            list_Items[k].current(kozai)
        shop_Items[k] = ttk.Label(frame,text=shoplist[k])
        shop_Items[k].grid(row=i + 1, column=1)
        date_Items[k] = ttk.Label(frame,text=datelist[k])
        date_Items[k].grid(row=i+1,column=0)

        k+=1
    canvas.create_window(0, 0, anchor='nw', window=frame)
    scroll = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
    scroll.grid(row=0, column=1, sticky='ns')
    canvas.grid(row=0, column=0, )  # Canvasの配置
    canvas.configure(yscrollcommand=scroll.set)

    def ButtonClicked_Run():
        B = [0]*(N)

        for i in range(N):
            B[i] = list_Items[i].get()
            #kozal.append(B[i])
            kozal[i] = B[i]
        root.destroy()

    button_Run = ttk.Button(frame, text='実行', padding=5, command=ButtonClicked_Run)
    button_Run.grid(row=k+1, column=1)

    frame.update_idletasks()
    canvas.configure(scrollregion=canvas.bbox("all"))
#
# GUI設定
#
root = tk.Tk()
root.title(u"Zaimデータ変換")
root.geometry("500x500")
#frame_main = tk.Frame(root)
#frame_main.grid(sticky='news')

fTyp = [("", "")]
iDir = os.path.abspath(os.path.dirname(__file__))
tk.messagebox.showinfo('oxプログラム', '処理ファイルを選択してください')
file = tk.filedialog.askopenfilename(filetypes=fTyp, initialdir=iDir)
ffile = file.replace(".csv", "_lets.csv", 1)

koza = ""
kozal =[]
kozai = []

#キャンバスエリア
canvas = tk.Canvas(root, width = 400, height = 500)#Canvasの作成

frame = tk.Frame(canvas)

#
# GUIの末端
#

with open (file) as f:
    reader = csv.reader(f)

    n = 0
    data = []
    str =""
    oshop = "-"
    shop =""
    date =""
    kozax =""
    shoplist = []
    datelist =[]

    for row in reader:

        if n != 0:
            shop = row[8]
            date = row[0]
            str = row[7]
            if str !="":
                kozax = str
            if shop =="-":
                shop = oshop
            if shop != oshop:
                shoplist.append(shop)
                datelist.append(date)
                kozal.append(kozax)
                kozax=""
                n=n+1
            oshop = shop

        if n == 0:
            str = row[1]
            n = n + 1
m = len(shoplist)

ok_click(m)

root.mainloop()

n=0
with open (file) as f, open(ffile , 'w') as g:
    data.clear()
    reader = csv.reader(f)
    writer = csv.writer(g, lineterminator="\n")
    for row in reader:

        if n != 0:
            shop = row[8]
            if (shop!=shoplist[n-1])&(shop!="-"):
                n = n +1
            koza = kozal[n-1]
            date = row[0].replace("-","/")
            data.append(date)
            data.append(shoplist[n-1])
            data.append(row[6])
            data.append(row[10])
            data.append(row[11])
            data.append(row[3])
            data.append(koza)
            writer.writerow(data)
            data.clear()

        if n == 0:
            data.append(str)
            writer.writerow(['日付','お店','内容','収入','支出','費目','口座'])
            n = 1
            data.clear()

58回目の誕生日

今日は誕生日でした。別にどうと言う事もないのですが、ケーキを作って食べました。


f:id:alasixOsaka:20210131215744j:image

娘のリクエストでザッハトルテ風のチョコケーキにして見ました。チョコケーキは始めてだったのでちょっと難しかったですが、味の方はそこそこおいしかったです。