2022年10月26日 (水)

【ROS】 gazeboの中にカメラを固定して移動ロボットの動きを追跡したい

gazeboのセンサプラグインを使って、地面にカメラを固定して定点観測する狙いでカメラ付きロボットのサンプルを参考にしながらあちこち試した。


◆gazeboのチュートリアルで見つけたrrbotをベースにした例
https://classic.gazebosim.org/tutorials?tut=ros_gzplugins#Laser

最初はこれでやってみた。rrbotのアームの先にカメラとLIDARを取り付けてセンサのトピックを見るというもの。
githubからrrbotをチェックアウトしたら、すでにカメラがくっついていた。
棒のようなロボットを地面に固定する方法はなんとなくわかった。

冒頭の部分で、worldというのが出てくる。robotをGazeboに固定するためにbase_linkというのを使う。というコメントがある。これはロボットのベースになるような部分、アームなら幹とか土台の部分と考えたら良いだろうか。
その次のjointタグのところでworldにlink1を固定している。
link1がrrbotの土台ということか。base_linkというラベルは一度も出てきていない。

<!-- Used for fixing robot to Gazebo 'base_link' -->
<link name="world"/>

<joint name="fixed" type="fixed">
<parent link="world"/>
<child link="link1"/>
</joint>

<!-- Base Link -->
<link name="link1">
ここの内容は省略
</link>



◆カメラ付きロボットやURDFの例
http://joe.ash.jp/program/ros/cbot/index.htm
まさに求めていたwebcamを備えた2輪ロボットのサンプルがあったので、ありがたく使わせてもらいました。
これを改造して行けば作れると思った。しかし地面に固定して使うカメラを想定しているのならrrbotをベースにしたほうが良かったのだろうかまだわからない。

冒頭に出てくるのが
<link name="base_footprint"/>
で、これを単純にworldに変えて、base_footprintを全部worldに変えたらいいと思った。

ところがこれをやるとgazeboにカメラが出てこなくなったので混乱した。エラーは出ていなかったにもかかわらずだ。
色々弄くり回した挙句、すべてをworldに固定しようとするとうまく行かないことがわかった。worldを親とするjointは一個だけにして、子をbase_linkにしたらうまく行った。

```
<joint name="base_joint" type="fixed">
  <origin xyz="0 0 0.045" rpy="0 0 0" />
  <parent link="world" />
  <child link="base_link" />
</joint>
```

base_link以外の、ホイール、カメラはbase_linkを親にした。
webcam.urdf.xacroはマクロの作用でurdfに変換されたときにwebcam_0というリンクになり、webcam_0_jointというジョイントで親をbase_link、子をwebcam_0として設定する。

これがわかってからは割とスムーズに行くようになった。カメラ以外のリンクをざっと消去して、base_linkとwebcam_0だけにしてもgazeboに表示されるようになり、カメラの表示もできるようになった。

rostopic list
すると、
/webcam_0_camera/image_raw
が配信されていることがわかったのでrvizで設定すると見ることができた。


gazebo座標のど真ん中x=0,y=0でz=3mのところにカメラ土台を固定し、真下を向けたときのrvizの画面。
どっち向きに配置されているかを確かめるためにブロックとcoke_canを置いてみた。


Ws000085

cbotからの変更点のおさらい
◎cbot_rviz.launch
・x_pos,y_posをゼロにする。
・あとfindのcbotになっている箇所をcbot_cam_onlyに変える。

◎cbot.urdf.xacro
・robot name="cbot_cam_only"に変える
・includeをcommonとwebcamだけにする。
・base_footprintというリンクをworldという名前に変える。
・base_linkのboxサイズを好きなのに変える
・body Definitionからcaster Definitionまでを削除
・最後のgazeboタグを削除
・base_jointのxyz,rpyを好きなのに変える
・webcamのタグのparentをbase_linkに変える。

あとはプロジェクトの名前に合わせてちょこっと編集したらいけるはず。


◆画像処理をメインにした例。カメラを地面に固定
https://qiita.com/srs/items/463bac79564c6bec97f3

 


◆vscodeでURDFのプレビューを表示する。
vscodeのROSのエクステンションをインストールする。
Ctrl+Shift+Pで検索ボックスを開いて、ROSと打つと下記のような項目が出てくる。
ROS: Preview URDF
URDFファイルを開いた状態でこれを実行するとプレビューが見えるようになる。

なのだが、xacroで作成していたらすぐにはプレビューを見られない。なのでxacroをurdfに変換する作業が必要。これはツールが用意されていて、

rosrun xacro xacro cbot_cam_only.urdf.xacro --inorder > cbot_cam_only.urdf

これでURDFが出せる。上記のファイルをvscodeで開いた状態でROS: Preview URDFを実行すると、たしかにモデルが表示された。

gazoboの世界の空中に固定した土台と、どの土台についたカメラ(緑色の立方体)が出てきている。

Ws000084


xacroファイルを編集してrosrun xacroを実行すると、urdfファイルが更新されてviewerの画面も更新される。ちょっとタイムラグがあるか、スクロールしたら表示が変わった。

カメラの土台base_linkをworld(gazebo空間)に固定すればカメラを空中に固定できる。そしてpitch軸で90度回転すればカメラは真下を向く。

```
<joint name="base_joint" type="fixed">
  <origin xyz="0 0 5" rpy="0 1.57 0" />
  <parent link="world" />
  <child link="base_link" />
</joint>
```


起動時にconfigのrvizファイルが読み込まれるようになっているので、launchすればいきなりフィールド全体が視野に入った状態で起動する。ヤッタネ

 

◆他のプロジェクトに入れ込みたいとき
座標系の名前が違ってるとうまくspawnできない。そんなときはベースの座標系が何と言う名前か調べる必要がある。下記コマンドでtfのグラフをPDFで出力し、一番上の親が何と言う名前か見られる。
rosrun tf view_frames

odomだったりworldだったり色々あるみたいなのだがどこで設定しているかはまだわかっていない。


◆重力の計算をOFFにしたいとき(モデル作るときとかに使ったはず。チュートリアルか何かで見たのだが情報元が思い出せなかった。)
下記のようにturnGravityOffのタグを用意したらいい。
<gazebo reference="base_link">
  <material>Gazebo/White</material>
  <turnGravityOff>false</turnGravityOff>
</gazebo>



2022年10月19日 (水)

【python】 unittestを使う ユニットテストの練習

 

最初はここの記事を参考に、fizzbuzzをテストしてみた。
https://qiita.com/phorizon20/items/acb929772aaae4f52101

■わざと間違えてみて、failedが出るかを試す

ダウンロード - test_fizzbuzz.py

ダウンロード - fizzbuzz.py


■修正してみてパスするか試す

ダウンロード - test_fixed_fizzbuzz.py

ダウンロード - fixed_fizzbuzz.py

 

これが公式ドキュメント。バージョンにあったやつを読む。古いかもしれないが日本語もあった。
https://docs.python.org/3.9/library/unittest.html


■テストしたい関数を一個だけ指定したい場合のやり方。

example
テストを実行するファイル
test_fizzbuzz.py
の中の、test_buzzだけをテストする。

こんなふうに、"ファイル.クラス名.関数名"で指定する。
% python -m unittest test_fizzbuzz.FizzBuzzTest.test_buzz

 

2022年10月12日 (水)

Ubuntu+gvimにフォントをインストールする

入れ方自体は簡単。ここに書いてある通りstep2のやり方を試した。
/home/hoge/.fonts
ホームディレクトリに.fontsを作って、その中にttfファイルを入れたら完了。
フォントはこれをつかった。理由はチルダが見やすいから。
takaoフォントだとサイズを小さくしても見やすかったけれど、チルダが上横棒になってしまう。いろいろ試している途中。
Cica
■gvimへの設定方法
(ubuntuのvim-gtk3でインストールされるgvim。窓が出るやつ)
一旦gvimからフォント選択のダイアログを開いて指定する。
下記コマンドを打てばダイアログが出る。
:set guifont=*
gvimのechoで現在のフォントを見たら、なんと打てば今のフォントになるかわかる
このコマンドで表示できる。
:echo &guifont
表示された内容はこれ
Cica 12
参考にしたHPではh12と書いていたし、フォントファイル名は"Cica-Regular.ttf"だったので、これでいいのだろうか??
表示された通りに.gvimrcに書き込むようにする。
set guifont=Cica 12
すると、Cicaフォントに変更された。しかしサイズは10のままだった。12にするにはなんらかの書き方で入れなければならない。いろいろ試行錯誤した結果下記のようにバックスラッシュを入れる必要があった。なるほど空白文字があるのでエスケープしなければならなかったのだ。
set guifont=Cica\ 12
参考にしたHP

2022年10月 5日 (水)

本の買い方シフト

教科書や専門書は高いので、アマゾンの検索で出てくる中古本を探して買うことが多かった。しかしながら何冊買っても別々な店から届くので送料は別々になるし、せっかく本体価格が1円でも送料が高かったりして結局どこで買っても同じ。などということもあった。
それならと、近所の古本屋なり、ブックオフなりに行って直接読んでから買うほうがよくなってきた。
そしてたどり着いたのがこのサイト。
全国の古本屋から目当ての本を検索して、通販で買うことができる。
同じ店でたまたま目当ての本があれば、まとめて送ってもらうことも可能なはず?(自分はまだそういうパターンに当てはまったことがないが)
どちらにせよアマゾンの配送が雑になってきて気に食わないのと、しまいには置きハイなどという、放置プレーと変わらない配送方法を編み出してきて利用する気が失せてしまった。盗られたらどうするんだか。(どでかい本でなければポストに入れてくれますが。)
本はメルカリで買うという手段もありますな。ポイントキャンペーンやら何やらで500円分ぐらいゲットすれば、ただで1冊買えたりするんじゃあないでしょうか。

2022年9月28日 (水)

【python】 pillowでフォントを使うときにちょっとてこずった。windows環境下

ちょっとした情報を画像の中に入れたくて、フォントをロードしたくなることがある。linuxだとフォントを検索して絶対パスを指定するような単純なものだがwindowsだととたんに難しくなる。
linuxだと、使えるフォントを調べるときどうやるのか。
man -k font available | grep "(1)"
で検索したら、
fc-list (1) - list available fonts
なんていうのでリストが出せる。これの出力が
絶対パス: ちょっとした説明
という書式で出てくるので、そのままそこのパスを指定すればいい。
windows10だと
c:\Windows\Fonts
の中にある。しかしエクスプローラーで表示されたやつは使うことができなかった。OSに元から入っているやつだけが使えるのだろうか。
そもそもコマンドプロンプトから上記フォルダをたどってdirすると、後からインストールしたTakaoフォントは、ディレクトリに表示されてこない。。。
そして、pillowのImageFontでフォントファイルを読み込もうとしてもロードできなかった。
OSError: cannot open resource
というエラーが出てくる。
とりあえず使えそうなarialとかから試したら、これは英数字に対しては使えた。このフォントはれっきとした欧文フォントなので、日本語を打つと豆腐(白四角)が出てしまう。
日本語を表示するのは"meiryo.ttc"や"msgothic.ttc"だと可能だった
フォントファイルの指定のときに、拡張子がttfだったりttcだったりするのが意外にはまりポイントなので注意。
from PIL import Image, ImageDraw, ImageFont
im = Image.new('RGB', (512, 512), (128, 128, 128))
draw = ImageDraw.Draw(im)
# font = ImageFont.truetype('arial.ttf', 50)
# font = ImageFont.truetype('times.ttf', 50)
font = ImageFont.truetype('GOTHIC.TTF', 50)
draw.text((10, 10), 'hello world', fill=(255, 0, 0), font=font)
# font = ImageFont.truetype('meiryo.ttc', 50)
font = ImageFont.truetype('msgothic.ttc', 50)
draw.text((10, 70), 'ハローワールド', fill=(255, 200, 0), font=font)
im.show()

2022年9月21日 (水)

【python】spyderでanacondaの仮想環境を使う

pyenvはwindowsに対応してないのでpyenv-winを使うことになる。
windowsならGUIがあるanacondaかなと思って入れたら、こちらも沼にはまった。

pygameを使おうとして3.5を入れ、spyderから使おうと思った。
spyder5のPreferenceからインタープリタの設定で、anacondaの仮想環境を指定しようとしたらinvalid pathエラーが出て、原因がよくわからなかった。
base環境のspyderの代わりに、仮想環境にspyderを入れたら動くかもと思い、spyder5.1.5をいれようとしたら、下記エラーが出た。インタープリタの設定ができなかったのは、spyder5系が3.5に対応していないからだということが分かった。
UnsatisfiableError: The following specifications were found
to be incompatible with the existing python installation in your environment:
Specifications:
  - spyder=5.1.5 -> python[version='>=3.10,<3.11.0a0|>=3.8,<3.9.0a0|>=3.7,<3.8.0a0|>=3.9,<3.10.0a0']
Your python: python=3.5
If python is on the left-most side of the chain, that's the version you've asked for.
When python appears to the right, that indicates that the thing on the left is somehow
not available for the python version you are constrained to. Note that conda will not
change your python version to a different minor version unless you explicitly specify
that.



2022年9月14日 (水)

【python】Spyderをpyenvで使う

Spyderをインストールすると、spyderにpython3.7とかが付属する。
何も設定しなければインタプリタ―はそっちが使われる。
基本的に実行するのはIPythonの窓なので、そこに表示されているversionで実行されることになる。
ここをpyenvで入れたpythonのバージョンにできれば目的が達成できる。
最初にpyenvでlocalなりに好きなバージョンのpythonを入れる。環境をすでに作ってあるならそれに切り替える。
ローカルの仮想環境にspyder-kernelsというパッケージをインストールする
pyenvならpipでいれるといい
pip install spyder-kernels
下記コマンドを仮想環境で実行する。

python -c "import sys; print(sys.executable)"
こんな感じで実行ファイルが表示されるwhichコマンドみたいに
C:\Users\xxxxxuser\.pyenv\pyenv-win\versions\3.6.8\python.exe
SpyderでToolから設定して、IPythonコンソールを閉じて再起動したら、pyenvで選んでいるバージョンが表示される。そうしたら仮想環境に切り替わっている。

情報ソース

2022年9月 7日 (水)

【python】 numpy ちょっと癖あるshape

行列のサイズを調べるのにshapeをよく使う。使い方はあっているはずなのに、なぜかエラーが出るという場面に遭遇した。
a = np.array([1,2])
これに対して、
w,c = a.shape
としたら行数、列数がそれぞれw,cに入るはず。
しかし、
ValueError: not enough values to unpack (expected 2, got 1)
これはなんだと調べてみると、
In[32] : a.shape
Out[32] : (2,)
行数だけしか出てきてない。np.arrayするときに[]が1重のときは列数が出ない仕組みになっている?!
仕方がないので、[]を二重にして、
a = np.array([[1,2]])
これなら想定した戻り値になる。
In[36] :a.shape
Out[36]: (1, 2)
しかしまあ、なんか忘れそうな気はするなあ。

2022年8月31日 (水)

【python】スライス操作をすると、新しいオブジェクトが作られる。

ミュータブル(変更可能)なオブジェクトを関数に渡すと、それは通常参照渡しになるので、関数の中で内容を書き換えた場合は、呼び出し元のオブジェクトも同時に変更が加わる。
しかし途中でスライス操作をすると、スライス操作自体が新しいオブジェクトを生成するので、呼び出し元のオブジェクトに変更が残らない。
これは関数の中だけで変更を閉じたいときには楽でいいが、関数の中で内容を書き替えることを想定していた場合は思った動作をしないわけで、ちょっとややこしい。

下記、適当に書いて試したコード。多分numpyとかも転置とかスライスやると新しいオブジェクトができるのだろう。
C言語のときもそうだったけれど、ふと気づいたことを実際に書いて動かしてみるというのは大事。最初のころはこういうことに気づくこともできない。

pythonでオブジェクトのIDを調べるには"id(a)"と書けばいい。C言語でアドレスが同じになってるか違うのかを調べるときにやっていた手法とよく似ている。

def edit(a):
    a[0] = 12
def do_slice(t):
    a = t[:2]
    print(f"at do_slice: {a}") #スライスした時点で別オブジェクトなので元のaには影響しない
    b = a
    b[1] = 30
    print(f"at do_slice: {b}")
    print(f"{a},{b}")
a = [0,1,2]
print(f"{id(a)}")
edit(a)
print(a)
do_slice(a)
print(a)

2022年8月24日 (水)

【エディタ】vimのコマンドモードが便利すぎた件 入門して少し使えるようになったら早めにヘルプドキュメントを読もう

vimのコマンドモードについていろいろ試していたら、sedに似ている点をいくつも発見した上に、
文字列置換についても理解が深まった話。

いつも保存するときは":w"するが、この時の頭のコロンがコマンドモードへの入口。
wのほかにもmとかtとかpとかいろんなのがある。

まず、コロンだけでいろんなことができることが初耳だったのだが、
行単位の処理がものすごく短いキー操作でできる。

:1
一行目に移動。"gg"でもできるけれど。

:105
百五行目に移動。"gg"の後、"105j"したら同じことができる。

:10,20p
10から20行目までを選択して表示。下のペインに選択した部分がprintされる。
通常コマンドなら"gg"+"10j"+"V10j"ってやればできるけれど一行ずれちゃった。

ここで気づいたのだが、sedでもこの操作が似たようなやり方でできる。
cat text | sed -n '10,20p'

:/FUJITA/,/NAKADAIRA/p
正規表現でマッチした行で選択するやり方。

これもsedに同じ表現がある。
cat test | sed -n '/FUJITA/,/NAKADAIRA/p'

 

ちなみにmはmoveで、行単位のカット&ペーストをいっぺんにできると考えられる。
これは1~4行目をファイル末尾に移動させるコマンド。
:1,4m$

ビジュアルモードで範囲を選択した後、コロンを押すと
:'<,'>
のような状態になる。これは選択範囲に対して何かをすることを指定できる状態で、
この後にmoveなりprintなりを指定すると、その範囲に対してのみ処理が可能になる。

指定範囲に対してだけ文字列置換をしたい場合、(文字列置換はsubstitute→sコマンド)
<>で囲まれている部分をシングルクオーテーション囲みに変更するときは、
:'<,'>s/\v[<|>]/'/g

いつも
:%s/\v[<|>]/'/gc
とやって、y/nで一個ずつ選択していたのだが、範囲指定ができたらいちいち見なくてもいけるので速い。

ちなみに置換や検索のとき単語が長いときなんかは、狙いの単語の上にカーソルを置いたうえで、
C-r,C-w
とやるとコマンドラインにコピーされる。これが無茶苦茶便利。

さらに強力なのはマクロを指定行に対して繰り返し行うように応用が効くこと。
normalはノーマルモードのコマンドを実行せよの意味。
:'<,'>normal @a


この辺の詳しい話はヘルプを見るとたくさん載っている。というかヘルプの見方を最初に知っておくべきだった。
:help なんかキーワード
:h なんかキーワード
でみられる。kaoriya-vimだと日本語で読めるので楽ちん。HPにも日本語ドキュメントが公開されている。

2022年8月17日 (水)

【shell script】sedの活用レベルを上げる。マニアックな技の調べ方


sedのmanページに、SEE ALSOでURLが書いてあり、
さらに詳しい解説がテキストファイルになってまとまっている。
これが中々マニアックな技の宝庫で、ブログで見る分の数十倍の分量がある。

manに入っているURLはこれ
http://sed.sf.net/grabbag/tutorials/sedfaq.txt

そのファイルの中に、さらに
2.3.4 General web and ftp sites
という項目があり、さらにマニアックな内容にリンクしている。

その中の一つに、ワンライナーFor sedというのがある。
"Handy One-Liners For Sed", compiled by Eric Pement. A large list
of 1-line sed commands which can be executed from the command line.
http://sed.sourceforge.net/sed1line.txt
http://www.student.northpark.edu/pemente/sed/sed1line.txt

"Handy One-Liners For Sed", translated to Portuguese
http://wmaker.lrv.ufsc.br/sed_ptBR.html


下記抜粋。
とりあえず一番上の行のやつを試したらいい。
パッと見て、なぜこれでCRだけを削除できるのか?と思ったら、
sedはデフォルトでは'\n'区切りで行を判断しているので、行末尾の一個前はCRになるのだった。

# IN UNIX ENVIRONMENT: convert DOS newlines (CR/LF) to Unix format.
sed 's/.$//' # assumes that all lines end with CR/LF
sed 's/^M$//' # in bash/tcsh, press Ctrl-V then Ctrl-M
sed 's/\x0D$//' # works on ssed, gsed 3.02.80 or higher

これはとても便利。nkfとかブログで見ながら試してみたがちっともうまくいかず、結局ウィンドウズのフリーソフトを落としてきて
ドラッグアンドドロップしてやっていた。そこだけコマンドラインじゃないのがいかにも苦痛だったのである。


manを活用するようになって、ようやくわかったのもある。
-zというなにやら難しいオプションである。これはsedが行を認識するのを'\n'でやる代わりに'\0'で行うものである。
こうすると、今までsedからは区切り文字として見ていた'\n'を普通の文字として見ることができ、
普通の文字と一緒に置換も検索も思いのままになるのだ。
今までtrを使ってチマチマ消していたのがずいぶん簡単になった。

2022年8月10日 (水)

【python】遺伝的アルゴリズム再び。Interface誌の記事を参考にpythonでライントレースロボを進化させる。


Interface 2017年12月号の人工知能コーナーでやっていた
遺伝的アルゴリズムの記事を読んで実際にやってみた。
https://interface.cqpub.co.jp/magazine/201712-2/

遺伝的アルゴリズムを使ってライントレースをする話で、
進化が進んでいく様子がグラフフィックで見やすくなるようにProcessingを使って書かれている。

 


■フローチャート的な図
大まかに見たら2重のループになっていると考えられる。
外側のループがgene(遺伝子)の作成とシミュレーションを回す部分。
geneは10本を1セットにして作成し、10回シミュレーションループを回す。
geneはスコア順にソートして決まったルールでペアを作り交配、新しい1セットを作成する。
外側のループは無限ループなのでCtrl+Cで適当に中断させる。
シミュレーションループの中が内側のループで、機体モデルをコースの中で走らせたときのセンサ応答を見て、機体をどう動かすかを決める。
内側のループは決まった回数分だけ回ったら終了する。

センサの応答は現フレーム+過去2回分の計3回分を用い、
この値によってgeneの読み取り位置を変える。
geneは長いビット列で、10bitバイナリ→intに変換して左右輪の正負を持った回転スピードに変換する。

Pygacar


■pythonで書き直してみた
サンプルを動かすだけでは面白みがないので、pythonで書き直せるかどうか試した。
Processingでは簡単だったグラフィック表示やマウス処理は、pygameでやることにした。
やってみるとpythonのほうが動作が少し遅くなってしまったが、一応使えるものにはなった。

https://github.com/morokyuu/pyGAcar.git

今後の展開:
・LIDARのように広範囲の障害物を検知できるセンサを想定した台車のモデルや、GA以外のアルゴリズムを試したいので、取り換えが簡単になるようにしたい。
・グラフィック表示部分が肥大化していくと困るので、台車が動いた軌跡はテキストに出して、後でビューワーを使って表示するやり方にしたい。
・フローチャート的な図で書いたように、入力と出力を明確にしてデータがフィルターを通り抜けていくイメージで作りたい。
・シミュレーションループをマルチプロセスで流して並列化したい。センサの計算をGPUで高速化できるかやってみたい。


オマケ
以降書籍を読みこんだときのメモ

ソース全体は500行程度で、大まかな流れは
遺伝子はビットで表現され、台車の左右のタイヤの速度は各5ビットずつで記録されている。
まずInit()でランダムなビット列をgen[][]に入れた後、SetActionでgenを読み取って左右タイヤの速度を決める。
車を10台動かした後Kouhai()で遺伝子交配をして次の世代を試行する。

■SetAction()
ビット列を取り出して速度指令値に変換するのだが、ビット操作を読み解くのに苦労した。
本文にかかれている計算式と、ソースの内容が違うみたいなのだ。

gen[][]は1ビットずつの情報が入っている。
配列要素0番目がbit0で、3番目がbit3桁目になる。
※サンプルプログラムを実行して出力されるdata.txtもこの並び方だ。

float s = 0; //遺伝子を速度に変換した値が入る
int r = 1; //bitを10進数に変換するためのもの

//このループでbit列を10進数に変換。r=32になる。
for(int i=0;i<ACTION_NUM/2;i++){
s += gen[cCount][state*ACTION_NUM+i]*r;
r *= 2;
}

//16以上だったらMSBが1になってる
if (s >= r/2){
s -= r; //sからrを引いた値をsに入れる
}
s /= (r/2);
s *= -5;
vel_R = s;

本文の式と合わせて書くなら
vel_R = s / 32 * 10 - 5;
であり、こっちで試しても正しく動くことを確認した。

2022年8月 7日 (日)

なんか面白くてよく見に行くブログ

検索エンジンでヒットした先でたまたま見つけたブログとかで、なんとなく読みに行ってしまうブログのアドレスを晒す。

ラック・セキュリティごった煮ブログ
テーマ自体がマニアックで面白い。
海外製ルーターの脆弱性検討というのが一番面白かった。ファームウェアの中身、バイナリの解析とか普段あまり触れないテクニックが出てくる。

 

遊ぶエンジニア
メインフレームというコンピュータの技術者だった人のブログ。やってみた系の記事から、いろんな時事ネタについての考察など。

 

2022年7月 2日 (土)

【Android】 huawei P30lite アプリ 容量いっぱい問題

huawei P30lite アプリ 容量いっぱい問題
容量がいっぱいになったらSDカードにデータを移動するしかない。
その際の操作
1.huaweiアプリの、「ファイル」を起動 (最初にデフォルトで入ってる、huawei製のアプリで黄色い棚のようなアイコンのアプリです)
2.SDへ移動させたいファイルを選んで長押し
3.移動かコピーが出てくるので、行き先を指定する
Ubuntuでマウントしたら、買ってきたSDXCのメモリーカードが読み込めなかった
こんなエラーが出る
ror mounting /dev/mmcblk0p1 at /media/zotac/700C-27B3: Command-line `mount -t "exfat" -o "uhelper=udisks2,nodev,nosuid,uid=1000,gid=1000,iocharset=utf8,namecase=0,errors=remount-ro,umask=0077" "/dev/mmcblk0p1" "/media/zotac/700C-27B3"' exited with non-zero exit status 32: mount: unknown filesystem type 'exfat'
対処方法は、
exFATをマウントできるようにするには下記コマンドでいける
sudo apt-get install exfat-utils exfat-fuse

2022年6月30日 (木)

【ココログ】 ココログへの愚痴 ソースコードをアップするときの苦労と、画像・ZIPファイルのアップロードについて

どうにも使いにくいと思うのは、syntax highlighterでソースコードを綺麗に表示できるように、通常エディタモードでちまちまとタグを書いたのに、リッチテキストボタンを押すか何か操作をすると勝手にリッチテキストのモードに切り替わってしまう。
すると苦労して打ち込んだソースに余計な<BR>とか<P>とかが入り込んで元に戻らない。
これには閉口する。改善を求める。


画像以外のファイルを挿入しようとした時に、ブログ本文を打ち込む画面の下に、「クリック、もしくはここにファイルをドロップ」というエリアがあり、それをクリックするとZIPファイルもアップロードできそうに見えるのだが、これが罠。それが証拠にダイアログが立ち上がった時デフォルトでjpgなどの画像の拡張子が表示されている。
じゃあZIPを上げたいときはどうするんだーとブログやら公式QAやらを探すのだが、焦っているとなかなか見つからず。

よぉうく見ると、本文・追記のタブの右に、「画像の挿入」「ファイルの挿入」というオレンジ色のボタンが独立で2こ並んでいる。
なんと、ここだった。前も同じことで探しまわったような気がする。

せっかく大きなエリアを割いているのだから、画像専用にせずにZIPや他のファイルもアップロードできるようにしたらどうなのか。
この使いにくさには長らく憤慨している。

Cocolog_file_insert


2022年6月28日 (火)

【ROS】 gazebo チュートリアルやってみた

公式の英語のチュートリアルを見て2輪ロボットのモデル作成をやってみた
そのときに詰まったりしたことをメモした。
まず最初にディレクトリを作る
~/.gazebo/models/my_robot

そこへ、テキストファイル2個

model.config
model.sdf
を置く。
configからはmodel.sdfを<sdf>タグで指定する。
staticというタグを設定すると物理法則を無視して、決めた位置に必ず来るようにできる。
Build the Model's Structure
を丸写しして
gazeboを起動し、Insertからmy_robotを選ぶと、何もない空間に定義した長方形のモデルが表示される。
あとはコピペしながらシャーシに対して球状のキャスターと、左右のホイールを定義する。この時点では宙に浮いたまま物体同士は接続していない。

<joint type="revolute" name="left_wheel_hinge">

こいつを定義するとホイールとシャーシがジョイントで関連付けされる。parentがchassisでchildがleft_wheel。あとは軸の方向を定義する。
jointを定義したらApply force/torqueでホイールを回して確認できる。プルダウンツリーのModels/my_robotの上で右クリックメニューを開くとそういうメニューがあるので選ぶと、ダイアログが表示される。(HPに記載してる、画面の右端のdotsをクリックしてUIを開くという記述はどうやら古いバージョンのときのものらしい。試したのはGazebo ver9





オレンジ色の巻いた矢印がトルク。茶色の矢印が力の向き。
一旦かけた力はかかったままになるので、力をかけてから0でApplyしても止まってはくれない。




ここまでのおさらい
~/.gazebo/my_robot
というフォルダを作って
model.configとmodel.sdfを置くと、gazeboのGUIからInsertで選べるようになってworldに追加できる。

ダウンロード - model__1.zip

 

meshは今のとこいらないのでスキップした
sensorをくっつける


事前にHokuyoのモデルを落としてきてから、gazeboを起動する。
こういうコマンドを実行するとモデルが落ちてくる

cd ~/.gazebo/models
wget -q -R *index.html*,*.tar.gz --no-parent -r -x -nH http://models.gazebosim.org/hokuyo/


</model>のタグの前に<include>以下を貼り付ければ、モデルにHokuyoがくっついて登場する。青いLaserも表示される。
どうしても出てこないときはHokuyoとhokuyoの違いよりも<include>を入れる場所が間違っている。

ダウンロード - model__2.zip

 





最後に、自分でやってみようのコーナーがあり、hokuyoの代わりにcameraを入れてみようとなっていたが、入れ替えただけではカメラは出てこなかった。いろいろ調べたがcameraのチュートリアルは出てこなかった。
gazeboで使えるセンサプラグインとその種類のリスト
台車にカメラをくっつける例
関節を動かすプラグインの作り方例



RRbotというサンプルがgitに落ちてるので、それをベースにカメラをくっつけるチュートリアルがあった。これでやってみる
カメラのシミュレーションとopenCV
こっちのほうがカメラ単体に絞った例になってる
結局RRBOTがあまりうまくいかなかったので、RRbotのカメラのくっつけ方を見ながら最初にチュートリアルで作った2輪ロボットにカメラをくっつけられるように試すことにした。
とりあえずカメラっぽい長方形を表示できるようにした。
カメラをロボットから離して(空中に浮かして)取り付けると、ロボットにもカメラにも質量もイナーシャも定義していないにもかかわらず、前につんのめってしまった。カメラの重心が車体の中に入るようにしたらその現象は起きなくなった。
※何度も試さなければならなかったが、gazeboを再起動する必要はなく、同じmy_robotのモデルを何度もInsertしたらいいだけ。Insertしたときに修正した内容が反映されている。
sdfはsimulation description fileで、
urdfは unified robotics description file。
xacroはマクロが定義できるxmlで、xml+macro=xacroというもの。そしてxacroはurdfを書きやすいように分割できるようにするためにできた形式で、例えば2輪ロボットを作るときに左右で別々のxmlをダラダラと書いていられないので、xacroでタイヤを一個作れば、上位のurdfでタイヤのxacroファイルを2こincludeすれば事足りるように構成したということ。そして実際には全部xacroで書いているらしい。こまかくいえばxacroで作ったやつをurdfに変換してgazeboに登場させている。xacro→urdfコンパイルみたいなものが間に噛んでいるというわけ。
MEMO sdfのバージョン
今気づいたが、チュートリアルやブログにはsdfのバージョンがいくつかある。今試してるのがsdf 1.4だった。なにがちがうのだろうか。

MEMO パラメータの書き方
サンプルを見ているとurdf,sdfとxacroではパラメータの書き方が違う。xacroの時は<center xyz="0 0 0" rpy="0 0 0">みたいにして書くのだがurdfの時は<center>0 0 0 0 0 0</center>のようにして書いている。

xacroの書き方がわからんことにはモデルを作成するのは難しいですな。


2022年6月25日 (土)

【トランジスタ技術】2020/9月号 ROSの記事 第六章を試したときの記録

トランジスタ技術2020年9月号を参考にして、第6章のurdfを書いたときのメモ。
gazeboで使えるロボットモデルを自作しようという内容のもの。
ラズパイマウスがモデルになっていて、4つの光センサを取り付けて、車輪を回して走らせるところまでが紹介されていた。

XMLを書くのになれておらず、モデルを完成させるまでが大変すぎたので、
結局Gazeboに表示されているのを見て、センサtopicが出てきて壁に当たると変化するなぁというのを確認しただけで終わってしまった。
※成功した時のソースはあるのだが著作権のこともあるのでアップロードは控えた。


<その1>

最初はurdfを使って書いてみようというもの。
トランジスタ技術の記事はrobot.urdf.xacroのスラッシュもタグもきえてしまっているので、こちらで解釈して書き直したらうまくいった。
確か<robot></robot>で1セットで、閉じる方のタグにはスラッシュが要るのだ。
子パーツのファイルを書き換えたら、assembly.urdfを再作成する必要がある。同じ箇所のエラーがいつまでも消えないなと思ったら、この作業を飛ばしていないか確認する。

確認結果↓
% check_urdf assembly.urdf
robot name is: SimpleMouse
---------- Successfully Parsed XML ---------------
root Link: base_link has 1 child(ren)
    child(1):  body
        child(1):  wheel_l
        child(2):  wheel_r
ここまででrvizに表示できるようになった。
このコマンドで実行する。
roslaunch urdf_tutorial display.launch model:=urdf/robot.urdf


<その2>

つぎが物理パラメータを設定してGazebo上に表示させる実験。
途中にxacroを使った書き換えもやっていて、少し立て込んでくる。
リスト2だけスペースが大きくて、95pageに掲載されているので見落とさないように。


リスト2、リスト3をそのまま打ち込んで
roslaunchで起動してみたら、
$ roslaunch robot_description robot_simulation.launch


そんなファイルない。というエラーが出た。
commandのところがエラーを起こしているらしく、ただしい書き方もよくわからなかったので、リスト4の方法に書き換えて実行したらロボットモデルが読み込まれてGazeboが立ち上がった。しかし画面には表示されず、赤文字で、
Ros could not parse collision for Link element {wheel_r}. {wheel_l}
というエラーが出ていた。


wheelのxacroがおかしいので調べてみると、<collision>のところにcylinderのタグはあるのだが、geometryのタグを入れ忘れていることに気づいた。


追加して再度roslaunchしたが全く同じエラーが出る。一旦collisionのタグごとコメントアウトしたが変わらず。
assembly.urdfファイルの中身を見たら、collisionのところの修正が反映されていないことが判明。

もう一回xacroをurdfに変換する操作
$ xacro robot.urdf.xacro> assembly.urdf
をやってからroslaunchしたらエラーなく起動し、パラメータもgazeboから確認できるようになった。

全部動くようになってから、リスト3のファイルも試してみたらこちらも動くようになった。


Gazeboのモデルを動かすためにgazeboプラグインを追加した。リスト5の内容を追加するのだが、並び方の順番を間違えると動かない。
xacro:wheelのタグの後ろに追加しなければ、gazeboタグで記載している、leftJoint, rightJoinが指定できなくなる。


一応gazeboで読み込まれて、teleop keyopで動かせることを確認できた。
しかしinertiaの表示が、wheelのgeometryがcylinderなのにboxで表示されていた。
これだけ原因がわからなかったが、そのままにして次に進むことにした。


<その3>

リスト9と10を打ち込んで、launchしてみたら
下記のようなエラーが出てきた。

unexpected EOF while parsing (<string>, line 1)
when evaluating expression 'find robot_description'
when processing file: /home/ros/urdf_ws/src/robot_description/urdf/robot.urdf.xacro
RLException: Invalid <param> tag: Cannot load command parameter [robot_description]: command [/opt/ros/melodic/lib/xacro/xacro --inorder '/home/ros/urdf_ws/src/robot_description/urdf/robot.urdf.xacro'] returned with code [2].

Param xml is <param command="$(find xacro)/xacro --inorder '$(find robot_description)/urdf/robot.urdf.xacro'" name="robot_description"/>
The traceback for the exception was written to the log file


原因は、robot.urdf.xacroの${find robot_description}のところのカッコが{}ではなくて()を使うべきだった。修正したら新しいエラーが出た。
こんどはlight_sensor.urdf.xacroの方だ。


ML parsing error: mismatched tag: line 59, column 6
when processing file: /home/ros/urdf_ws/src/robot_description/urdf/light_sensor.urdf.xacro
included from: /home/ros/urdf_ws/src/robot_description/urdf/robot.urdf.xacro

Check that:
- Your XML is well-formed
- You have the xacro xmlns declaration: xmlns:xacro="http://www.ros.org/wiki/xacro"
RLException: Invalid <param> tag: Cannot load command parameter [robot_description]: command [/opt/ros/melodic/lib/xacro/xacro --inorder '/home/ros/urdf_ws/src/robot_description/urdf/robot.urdf.xacro'] returned with code [2].
Param xml is <param command="$(find xacro)/xacro --inorder '$(find robot_description)/urdf/robot.urdf.xacro'" name="robot_description"/>
The traceback for the exception was written to the log file


これもタグの閉じ忘れが原因だった。
<xacro:macro>のタグの開始側がなく、いきなり閉じていた。
これを修正したら無事gazebo上に表示された。

一緒に起動するrvizにセンサの情報が表示できるようになっている

2022年5月29日 (日)

【python】 numpy 行列で回転・並進を計算する


線形代数をやったんで、いろいろ応用。
行列の意味を理解していると、回転行列を覚えていなくてもググらなくてもスラスラ書ける。

 


import numpy as np
import matplotlib.pyplot as plt

 

fig, ax = plt.subplots(figsize = (5,5))
ax.grid()
span = 3
ax.set_xlim(-span,span)
ax.set_ylim(-span,span)

 

#2Dの回転行列A。30度左に回転する
th = 0.5
A = np.array([[np.cos(th), -np.sin(th)],[np.sin(th),np.cos(th)]])

 

#2点(1,0),(0,1)のベクトルを作ってる
a0 = np.array([1,0]).T
a1 = np.array([0,1]).T

 

#上記2ベクトルに回転行列Aを作用させている所
b0 = np.dot(A,a0)
b1 = np.dot(A,a1)

 

#4点をまとめて定義。(x,y)でリストに並べたあと、Tで転置してる。
body = np.array([[1,1.5],[1,-1.5],[-1,1.5],[-1,-1.5]]).T

 

#行・列の数を取得するときに使うやつ。sizeは要素数を返すやつなので注意
r,c = body.shape
print(c)

 

#4点まとめて定義した点それぞれにAを作用させている。
body_ = np.dot(A,body)

 

#作用させる前後の比較
ax.scatter(body[0],body[1])
ax.scatter(body_[0],body_[1])

 

#(1,0),(0,1)の行列A作用前後での比較。青矢印が作用前。赤が作用後。
ax.quiver(0,0,a0[0],a0[1],color="blue",angles="xy",scale_units="xy",scale=1)
ax.quiver(0,0,a1[0],a1[1],color="blue",angles="xy",scale_units="xy",scale=1)

 

ax.quiver(0,0,b0[0],b0[1],color="red",angles="xy",scale_units="xy",scale=1)
ax.quiver(0,0,b1[0],b1[1],color="red",angles="xy",scale_units="xy",scale=1)

 

回転行列Aの他に、並進行列Bを追加してみた。

 


th = 0.5
A = np.array([[np.cos(th), -np.sin(th), 0],[np.sin(th),np.cos(th), 0],[0,0,1]])
B = np.array([[1,0,0.5],[0,1,0],[0,0,1]])

 

#座標を定義するときに、3番めの要素を1にする。
body = np.array([[1,1.5,1],[1,-1.5,1],[-1,1.5,1],[-1,-1.5,1]]).T

 

#A、Bを同時に作用させてみよう
#まずABxの順で作用させるとどうなるか
AB = np.dot(A,B)
body_A = np.dot(A,body)
body_AB = np.dot(AB,body)

 

これはBを作用させてからAを作用となるので、並進移動してから回転させることになる。

 

#座標を定義するときに、3番めの要素を1にする。
body = np.array([[1,1.5,1],[1,-1.5,1],[-1,1.5,1],[-1,-1.5,1]]).T

 

#A、Bを同時に作用させてみよう
#まずABxの順で作用させるとどうなるか
AB = np.dot(A,B)
body_A = np.dot(A,body)
body_AB = np.dot(AB,body)

 

これはBを作用させてからAを作用となるので、並進移動してから回転させることになる。 

 

Ab_figure-20220529-120224


#次に、BAxの順で作用させるとどうなるか
AB = np.dot(B,A)
body_A = np.dot(A,body)
body_BA = np.dot(BA,body)

Aで回転させてから、Bで並進移動するので、回転のみ作用させた橙の各点が右にずれた図になる。

Ab_figure-20220529-120224

 

回転行列、並進行列に1次元足して、3x3行列にした時に、上のように3番目に1をくっつける理由について自分なりに勝手に考えてみる。
行列の中身についてだが、これは縦ベクトルが横に束ねられてこの形になったと考えられる。Aの各列のベクトルは、左の列から順番に、x座標の行き先、y座標の行き先を表していて、並進行列を作るときに新たに追加した3列めは、xでの並進移動量、yでの移動量、?での移動量を表していると言える。今2Dなので?の移動量は使わない。だからどんな時も常に1にすればXY座標に影響しないようにしておける。そんな?への移動量を勝手に付け加えた。
ある点p=(0,1,1)に対して行列Bを作用させると、
Bの1列目のベクトルの方向へ0個分→x変化なし
Bの2列目のベクトルの方向へ1個分→y=1で変化なし
Bの3列目のベクトルの方向へ1個分→x方向に+2で、?方向は変化なし
と解釈できる。結局pは(2,1,1)になる。
?要素は1のままなので変わらず、x,yにだけ作用することがわかる。

 

 

 

 

2022年5月26日 (木)

【python】 pyenvの活用


tensorflowを使っていると、何かとライブラリのバージョンを気にしなければならず
anacondaはちょっと重いかなと思い始めてpyenvを使ってみたらそれなりに手に馴染んだのでまとめを作ってみた。

■どんなときに重宝するか??

ROS環境をインストールしていると、システムにすでに入っているpython2.7に余計なライブラリを入れた時にROSが動かなくなることがあった。
しかしpyenvで別な環境を用意しておけば安心してpython3.7を使える。

apt-installでは入れられないようなバージョンもpyenvなら簡単に選んでインストールできる。
これがpyenvの便利さ。

pyenvはCUIベースのpython環境切り替えツールで、動作が軽いのが特徴。
"pyenv is a tool for simple Python version management."
https://github.com/pyenv/pyenv

仮想マシンやDockerの中でも重宝する存在で、やっぱり軽いのがいい。
素でpythonを入れるときでも、バージョン指定がある場合はやっぱりpyenvのお世話になる。
一回入れるのをミスっても、pyenvを消したらやり直せるのもいい。

■どこで使っているか

pyenv使うのはだいたいubuntu専用マシンとかvirtualboxで、
windowsではあんまり使ったことがない。WSLならubuntu専用マシンとそんなに変わらないか。

■ほかの環境ツールと比較すると??

virtualenvというのもあり、こちらは同じバージョンに複数の環境を作ることができるのがメリット。
しかしそういう機会はあんまりないのでpyenvで十分だろうといった所。

最初はanacondaを使っていたがやっぱり重たい。windows版は特に重たく感じた。
condaというコマンドもwindowsだと素のコマンドプロンプトからだと認識されなかったりして、ちょっと癖が強い。
専用のプロンプトからしか使えないので厄介だったりする。でもまあ専用プロンプトからspyder5を立ち上げたら
強力なIDEで開発ができるので、windowsだったらこっちの組み合わせがいいか。

他にも聞いたことあるやつがあるけれど、使ったことはない。


■入れ方
aptやdepではなく、gitからクローンしてくる。
proxy環境とかいろいろ面倒なときはgitからzipをダウンロードしてきて所定の場所においたらいい。

0.pyenvをダウンロード
gitクローンでhomeディレクトリに保存
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

1.リポジトリアップデート
sudo apt update

2.必要なパッケージをインストール
sudo apt-get update; sudo apt-get install make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

3.bashrcにpyenvの設定を書き込む
"~/.bashrc"を開いて下記3行を書き込む。PYENV_ROOTという環境変数の設定、PATHを通す、pyenv initを実行

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"

.bashrcを書き換えたあと、bashとだけ打ってエンター押すと、"source ~/.bashrc" と同じ効果になる。※bashrcが実行される。

4.すきな環境を入れる
pyenvとだけ打つなり"pyenv -v"するなりしたらpyenvが動くはず。
そうしたら
pyenv install バージョン番号
で好きなバージョンを入れていく。

バージョンの候補は、
pyenv installのあとにタブキーを押すか
pyenv install --list
でリストが出てくる。

インストールした後、
適当なディレクトリを作って、その中を仮想環境にすることができる。
ディレクトリに入った後で、
pyenv local 3.7.7
とすると、その中でだけ3.7.7が実行される。

pyenvはバージョン1個につき1環境しか構築できない。という割りきった制約があるので、そこだけ注意が必要。

※プロキシに阻まれてしまうときは、
https_proxy=https://プロキシのアドレス:ポート pyenv install hogehoge
とすれば通してもらえる。たいていのプロキシ設定はこうやって冒頭にアドレスをつけて実行するようにしたほうが簡単かもしれない。
ツールによって.curlrcだの.gitrcだの設定ファイルをいじった挙句動かないこともあるから。
そしてこの冒頭にくっつけるやり方は、たいていのツールで通用してくれる。(個人の感想)

■実行してるpythonがどれかわからなくなったら
which python
とやると、パスが表示される。


■パッケージを入れる
目的の環境に切り替えたあとで、pipを使って入れる。
pip install hogehoge

入れたパッケージなんだったか確認するときは、
pip list
だけで行ける。anacondaはたっぷり出力されるので、たいていはgrep使いますが。
pip list | grep hogehoge


プロキシに阻まれてしまうときは、
https_proxy=https://プロキシのアドレス:ポート pip install hogehoge
とすれば通してもらえる。


■anacondaを使う
pyenvからanacondaを入れることもできて、あれこれpipで入れるのが面倒なときは
いきなりanaconda3を入れてしまってもいい。anacondaを入れるとspyderも一緒に入ってくるので、
anaconda環境を作って、spyderを使うやり方がセットになっていて楽。
pandas,numpy,scipy,matplotlibなど定番ライブラリを使いたいときはこれを入れておけば間に合う。
環境として一個は入れておきたい。
ただしspyder5とか新しいのは使えない。最新のanaconda3に入っているspyderでもspyder3でだいぶ古い。

※pyenvを選んだのにわざわざanacondaに戻ることもできるちょっと不思議な感じ。


■spyderを使う
pythonを使い始めて以来、pythonを書くときだけはこのIDEを使っている。
なぜなら実行した時の変数の中身がすぐvariable explorerで見られるから。printデバッグの手間がなくて楽になる。
spyderも5になって、補完機能が充実してきた。デザインもダークカラーになり今風に。
※デバッガはもっさりしているのであんまり使わない

spyderの最新版にこだわる場合はちょっと注意が必要。
anaconda3を入れた後、conda update spyderとかでアップデートできるが、これをすると元あったライブラリが消えたり、
pythonが3.7だったのが3.9になってしまうことがあった。

spyderだけは単独で入れておいて、立ち上げてからインタプリタの設定でpyenv環境を選択すれば
選んだ環境で実行するようにできる。
※spyderを入れるときにspyderに付属のpythonもインストールされ、何も設定しなければインタプリタ―はそっちが使われる為。

tools -> preferences -> Python Interpreterの、
Use the following python interpreter:に、実行ファイルのパスを入れる。

 

 

2022年5月23日 (月)

【python】 spyderからpyenvで作った仮想環境を使う

Spyderをインストールすると、spyderにpython3.7とかが付属する。
何も設定しなければインタプリタ―はそっちが使われる。
基本的に実行するのはIPythonの窓なので、そこに表示されているversionで実行されることになる。
ここをpyenvで入れたpythonのバージョンにできれば目的が達成できる。

最初にpyenvでlocalなりに好きなバージョンのpythonを入れる。環境をすでに作ってあるならそれに切り替える。

ローカルの仮想環境にspyder-kernelsというパッケージをインストールする
pyenvならpipでいれるといい
pip install spyder-kernels

下記コマンドをpyenv仮想環境で実行する。
```
python -c "import sys; print(sys.executable)"
```

こんな感じで実行ファイルが表示される
C:\Users\xxxxxuser\.pyenv\pyenv-win\versions\3.6.8\python.exe

linuxならwhichコマンドを使えばどこのpythonが実行されるかわかる。
pyenv/shimsなんちゃら というのが出てくるはず。
spyderのインタープリタ選択のプルダウンメニューから出てくることもある。そっちが正解か

SpyderでToolから設定して、IPythonコンソールを閉じて再起動したら、pyenvで選んでいるバージョンが表示される。
そうしたら仮想環境に切り替わっている。

 

«pandasの活用