多重度を正しく書けていますか
はじめに
これはETロボコン Advent Calendar 2014 - Adventarの9日目のエントリーです。昨日はY_uuuさんのユニットテストの話でした。ユニットテスト必要ですよねー。QtにもQTestLibが有りますよ!ってその話はまた今度。
今日はクラス図の、それも多重度について「だけ」書いていきます。クラス図の関連につける多重度、みなさん正しく書けていますか?
ETロボコン2014の公式資料には多重度が誤って書かれているものが複数ありました。
全体メーリングリストでも指摘をしましたが、説明不足かと思うのでこちらに書いておきます。
とはいえ私はUMLの専門家ではなく、認識の誤りなどもあるかと思います。お気づきの点あればご指摘頂けると幸いです。
誤った多重度の例
fig.1 多重度を誤ってつけたクラス図
さて、fig.1を見て「このクラス図おかしいな」と思われたでしょうか。これは多重度を誤っている例です。今年のETロボコンに参加された方は見覚えがあるのではないかと思います。説明のために関連名を追加してあります。
どこがおかしい?
多重度を誤っている、と書きましたが、UMLの記法から逸脱している部分はありません。ただ、意味的に倒立振子と合わない部分があります。これはオブジェクト図と見比べれば分かると思います。
fig.2 倒立走行のオブジェクト図
fig.2は倒立振子で想定される倒立走行とモーターの関係を表したオブジェクト図です。説明のためにリンク名を書いてあります。オブジェクト図では、「クラス」は「オブジェクト」として、「関連」は「リンク」としてインスタンス化されます。
倒立走行クラスから見たモータークラスへの関連は「関連_左」「関連_右」の二つ、モータークラス側の多重度はどちらも1です。これはオブジェクト図の「倒立走行1」オブジェクトから見て「リンク_左」「リンク_右」にインスタンス化されています。
モータークラスから見た倒立走行クラスへの関連は同じく「関連_左」「関連_右」の二つ、倒立走行クラス側の多重度はどちらも1です。ところが、「モーター左」オブジェクトから見た「関連_左」は「リンク_左」にインスタンス化されていますが、「関連_右」がインスタンス化されていません。
これではクラス図における「関連_右」の倒立走行クラス側多重度1、という設計と合わず、「モーター左」オブジェクトはクラス図のクラス設計に沿ってインスタンス化されていない、という事になります。
同様に、「モーター右」オブジェクトも相手側多重度が1であるはずの「関連_左」がインスタンス化されておらず、クラス図とのトレーサビリティがとれていません。
どう修正すればいい?
この場合はオブジェクト図が正しく、整合のとれないクラス図の方が間違っていそうです。モーター側からみた関連が二つあってどちらも相手側多重度が1、というのが問題です。
インスタンス化されない関連の多重度には0を含める
最も簡単な修正の方法は、倒立走行側の多重度の記述を削除してしまうことです。以下3つは全て同じ意味です。
- 多重度の記述無し
- 多重度「*」
- 多重度「0..*」
モータークラスから見て一つの関連の先の倒立走行クラスは最大1つ、という事を表すには「0..1」とします。
fig.3 修正したクラス図
これで少なくともfig.2のオブジェクト図との不整合はなくなりました。このように、ある関連がオブジェクト図においてインスタンス化されない可能性がある場合、その関連の相手側多重度には0を含まなければいけません。
さらに曖昧さを取り除く
クラス図としてはこれでも充分と思いますが、このクラス図はまだ曖昧さを含んでいます。例えば次のようなオブジェクト図もこのクラス図から書くことができます。
fig.4 誤解されたオブジェクト図1
fig.5 誤解されたオブジェクト図2
どちらもクラス図と整合しており、UMLの表記上も問題ありません。でも倒立振子とは合わないオブジェクト図になってしまいました。このような誤解は実際の設計でも起こり得ると思います。
このような誤解をさける方法として、抽象クラスでまとめる方法、コメントを使う方法、xor制約を使う方法、unionを使う方法などが株式会社豆蔵様ホームページで紹介されています。
誤解しがちなモデリングの技:第2回:隠れた曖昧さ | 豆蔵ソフト工学ラボ
実際にこのケースでunionを使用した例を書いてみます。
fig.6 unionを使って曖昧さを取り除いたクラス図
どうでしょうか。fig.2のオブジェクト図にマッチしていてなおかつfig.4やfig.5のオブジェクト図に誤解されるような曖昧さが排除されています。
おわりに
ここでは倒立走行とモーターの関係のみを見てきましたが、尻尾制御に同じモータークラスを使用する場合は、fig.6ではunionの倒立走行側多重度が「0..1」となり結局曖昧さを含むクラス図になってしまいます。これを無理にxor制約を使って書いたりすると、曖昧さは無くなっても読みにくい図になってしまうかもしれません。
そもそも技術教育資料のクラス図に合わせて書いてきましたが、実際のところモータークラスが単独で存在できないような制限をつけることにはほぼ利点が無いです。普通に倒立走行クラス側にコンポジションをきちんと書いて、モータークラス側多重度を1にするだけで良いと思います。xor制約とかunion書いても見にくくなるだけです。
それから、この辺りは審査委員さんの中でも解釈が異なるようで、ETロボコンに限っては正しい多重度を書いても評価に反映されないかもしれません。(技術教育の時に講師の方に、地区大会懇親会でも別の運営委員の方にお話ししたのですが、資料のクラス図は間違っていないと言われてしまいました。)
ともかく、モデルは人に伝えるために書くのだという事をいつも意識して、伝わりやすいモデルを書けるように勉強しなければ、と思う今日このごろです。駄文にお付き合いくださいましてありがとうございました。
fig.7 尻尾制御入れてunion+xorでなんとかしてみた。すごく…見にくいです…
fig.8 (誤ったクラス図)元のクラス図にxor制約を入れると倒立走行が二つのモーターを持てなくなる?
ETロボコンにQt Creatorで参加してきました
はじめに
この投稿はQt Advent Calendar 2014 - QiitaとETロボコン Advent Calendar 2014 - Adventarのマルチポストな記事です。12月6日分です。
ETロボコンの紹介、Qt CreatorでnxtOSEKの開発環境を構築した手順など書いていきます。
Qtシール。ここしか貼るとこなかってん。。。
ETロボコンとは
正式名称「ETソフトウェアデザインロボットコンテスト」。
5年後、15年後に世界をリードするエンジニアの育成を目指し、若手、初級エンジニア、および中級エンジニア向けに、分析・設計モデリング開発、製品サービスの企画開発にチャレンジする機会を提供する。(公式ページより引用)
LEGO社のマインドストームというロボット教育向けのブロックで全チーム同一のロボットを組み立て、ソフトウェアの設計審査および走行競技の評価を競う、というコンテストです。
ハードウェアはマインドストームNXT*1。
参加登録
ETロボコンは今年から以下の2部門、3クラスに分かれています。
プライマリークラスよりアドバンストクラスの方が要求される技術レベル(設計・実装とも)が高く、アーキテクトはさらに企画・提案力を求められる審査内容になっています。
今回は初参加のうえ集まったメンバーがほぼ組み込み未経験者、NXTの使用経験もなし、ということでプライマリークラスに参加しました。
会社に打診したところ参加登録費・機材購入費・旅費交通費・宿泊費は支弁してくれるということで、企業枠での登録となりました。
チーム名は決定時にたまたま連れて行っていたうちの息子の名前(いずみ)から「いずみん」になりましあばばばば。
開発環境
OSとか
とりあえずJAVA分からんしC言語では書きたくないしC++だよね、ということでnxtOSEKを使用。
拡張NXTファームウェアで開発していたのだけれど東海地区大会直前にプログラムサイズが大きくなってリンクできなくなったので慌ててNXT BIOSに変更。
IDEといえばQt Creator!!
やっと本題です。
一応チームリーダーであるAtsushi4が
「どうしても普段使い慣れたQt Creatorじゃなきゃやだやだやだーーー」
とうちの3歳児*3ばりに駄々をこねて勝手に開発環境をセットアップしました。
Qt Creator初めての方も見られるかもしれないので、セットアップした内容を順番に説明します。
(nxtOSEKの環境はインストール済みの前提)
プロジェクトの作成
- 適当な、空白やマルチバイト文字を含まないフォルダに適当な名前のproファイルを作成します。ここではsampleフォルダにsample.proを作成したとします。
- 同じフォルダにnxtOSEK用のMakefileとかoilファイルも置いておきます。
- sample.proをQt Creatorで開きます。
それから、以下の設定をsample.proに追加していきます。
- Qt CreatorはデフォルトでQtライブラリを使用するようになっているので、これを使用しない設定をしておきます。
- nxtOSEKのヘッダファイルが見えるようにインクルードパスを追加
- qmakeがnxtOSEK用のMakefileを上書きしないように、qmakeの出力ファイル名を指定
- Makefile、oilファイルなどをQt Creatorで簡単に開けるようにプロジェクトに追加
- Qt Creatorのプロジェクトに追加したソースからnxtOSEKのMakefileにインクルードできるソースリストを出力するように設定
sample.pro
CONFIG -= app_bundle CONFIG -= qt # OSEK Path NXTOSEK_ROOT = ../../../../ INCLUDEPATH += \ $$NXTOSEK_ROOT/toppers_osec/include \ $$NXTOSEK_ROOT/ecrobot \ $$NXTOSEK_ROOT/toppers_jsp/windev/devicemanager \ $$NXTOSEK_ROOT/ecrobot/c \ $$NXTOSEK_ROOT/ecrobot/c++/util \ $$NXTOSEK_ROOT/ecrobot/c++/device \ $$NXTOSEK_ROOT/lejos_nxj/src/nxtvm/platform/nxt \ $$NXTOSEK_ROOT/ecrobot/nxtway_gs_balancer QMAKE_MAKEFILE = qt_makefile OTHER_FILES += \ balancer_param.c \ mascet.oil \ Makefile # Generate source list for nxtOSEK system(echo "TARGET_CPP_SOURCES=$$SOURCES>nxt_sources")
ビルド設定
nxtOSEK用のバイナリをビルドするための設定をします。この設定はプロジェクトごとに必要です。面倒です。(.proとかでできる方法があれば教えてメガネの人。)
- Qt Creator一番左のモードセレクタから「プロジェクト」を選択
- 「概要」の「シャドウビルド」のチェックを外す
- 「ビルドステップ」の「Make」の「詳細」を開き、「(MinGWのbin)\mingw32-make.exeの代わりに使用するコマンド」に"make"を、「Make引数」に"all"を指定
- 「ビルド時の環境変数」から「PATH」を探して先頭にcygwinのbinディレクトリのパスを追加
- 上の方の「実行」タブ(?)を押して、「実行」の「追加」ボタンから「カスタム実行ファイル」を選択
- 「実行ファイル」に"bash"、引数に"appflash.sh"(NXT BIOSの場合)を指定
また、自動生成したソースリストをnxtOSEK用のMakefileから見えるようにしておきます。
nxtOSEK用のMakefileに1行追加
include nxt_sources
これでQt Creatorの補完やジャンプ、検索、リファクタリングも使えるし、Ctrl+Shift+BでNXT用バイナリのビルドが、Ctrl+RでNXTへの転送ができるようになりました。
Qt Creatorの便利な使い方については、たすくせんせー(Tasuku Suzuki (@task_jp) | Twitter)が昨日の記事で紹介されているのでそちらをどうぞ。
Qt Creator を便利に使いこなそう - Qiita
その他
NXT用のMakefileとQt Creatorのproファイル両方に共通する設定(nxtOSEKのルートパス、ソースリストのファイル名など)をpriファイルにまとめておいて両方からincludeするようにしたり、Qt Creatorの自動ビルドチェックで波線が出ないように基本型をifdefで分けてtypedefしたりとかしていました。詳しくは割愛。
PC側ツール
走行中のNXTとBluetooth通信してスタート指示を出したりログを受信したりするツールもQtで作りました。Qt5はQSerialPortがあって良かった!connectもラムダが書けて快適です。
NXTへのコマンド送信、ログの受信、コースと走行経路の表示など。
走行練習用に適当に作ったのですが結局チャンピオンシップ大会本番まで活躍しました。
こんな画面
走行経路書いてみたり
ズームだって簡単
おわりに
組み込み分からん、モデリング分からん、NXT買ってみてもどこから触ったらいいか分からん、という状態から始まり、月に1~2度週末に生涯学習センターの会議室を借りて集合、それ以外は家事と育児の合間を縫ってコーディング、レプリカコースが無いのでA3コピー用紙に印刷して貼り合わせたり、スケジューリングをミスってモデル提出2週間前にモデルを書き始めたり、東海地区大会前日の帰宅2時間前にナニカが降りてきてマップ走行が突然成功したりと、波乱万丈でしたがともかくチャンピオンシップ大会優勝してきました。
ETロボコン2014大会詳細 | チャンピオンシップ大会【ETロボコン2014公式サイト】
ETロボコン2014ランキング
チームメンバーの頑張りはもちろん、東海地区大会の後レプリカコースをお貸しくださったビッグマウスさんをはじめ応援してくださった皆さんに、育児のピンチに関西から駆けつけてくれた妻の両親に、そして家族に、感謝。
QtとQt Creatorにもね。
TIPS: nxtway_gs_balancerのturn値処理にはバグがある
これは ETロボコン Advent Calendar 2014 - Adventar の2日目のエントリーです。
東海地区技術委員の清水さん( k.shimizu (@pulmaster2) | Twitter )より東海地区独自教育「初心者向け教育」の時に伺ったお話。
balance_control関数はバランスを取るためのPWM値を計算した後、turn値より計算した値を左に足し、右から引く事で旋回する。ただしPWM値は-100~100の範囲しか取れないので、超えないように制限をかける。この時、せっかくバランスが取れるように同じ値を左右に足し引きするのに、その後で片方だけ制限するのでバランスが崩れてしまうよ、という事でした。
例えば今、前に傾いているのでバランスを取るために左右のPWMが80必要として、turn値から計算した値が-40とすると左は80-40で40になるけど右は80+40が100を超えてしまうので100になり、左から40引いて右に20足した状態になってしまう。
具体的なコードの場所はbalancer.cの267行目前後から。
tmp_pwm_r_limiter = (((K_I * ud_err_theta) + tmp_pwm_r_limiter) / ((BATTERY_GAIN * args_battery) - BATTERY_OFFSET)) * 100.0F; /* Gain: '<S3>/Gain2' incorporates: * Constant: '<S3>/Constant1' * Inport: '<Root>/cmd_turn' * Product: '<S3>/Divide1' */ tmp_pwm_turn = (args_cmd_turn / CMD_MAX) * K_PHIDOT; /* Sum: '<S2>/Sum' */ tmp_pwm_l_limiter = tmp_pwm_r_limiter + tmp_pwm_turn; /* Saturate: '<S2>/pwm_l_limiter' */ tmp_pwm_l_limiter = rt_SATURATE(tmp_pwm_l_limiter, -100.0F, 100.0F); /* Outport: '<Root>/pwm_l' incorporates: * DataTypeConversion: '<S1>/Data Type Conversion' */ (*ret_pwm_l) = (S8)tmp_pwm_l_limiter; /* Sum: '<S2>/Sum1' */ tmp_pwm_r_limiter -= tmp_pwm_turn; /* Saturate: '<S2>/pwm_r_limiter' */ tmp_pwm_r_limiter = rt_SATURATE(tmp_pwm_r_limiter, -100.0F, 100.0F); /* Outport: '<Root>/pwm_r' incorporates: * DataTypeConversion: '<S1>/Data Type Conversion6' */ (*ret_pwm_r) = (S8)tmp_pwm_r_limiter;
そんなわけで、balance_control関数は常にturn=0でコールして、その後で左右のモーターのPWM絶対値が100を超えないようなturn量を左右に足し引きするようにしたところ、特に高速走行が格段に安定するようになりました。
おしまい。
Qtプロジェクトにコミットしてみた
※ より詳しい記事を@IoriAYANEさんが書かれているのでそちらをどうぞ。
Qtプロジェクトにコミットしようよ - 理ろぐ
自分用の備忘録としてMacからQtにコミットした時の手順を残しておきます。
git 超初心者なのと英語サッパリなのと
思い出しながら書いているのとで,間違っているところも多々有ると思います。
お気づきの点が有れば是非教えて下さい。
実施手順一覧的なもの
- JIRAアカウント作成
- sshの準備
- ホストの追加
- sshキーペア作成
- Gerritの準備
- ログイン
- 同意事項の確認
- ssh公開鍵登録
- Gitの準備
- ユーザ,メールアドレスの設定
- Change-Id自動付与設定
- 修正
- Qtリポジトリからクローン
- ブランチ変更
- トピックブランチの作成
- コード修正
- コミット,プッシュ
- レビュー
- レビュワー追加
- コメント返信
- コミット取り下げ
1つずつ説明します。
JIRA 及び Gerrit に,ユーザ名 "atsushi4" で登録するとします。
JIRAアカウント作成
sshの準備
Gerrit準備
ログイン
JIRAのID,パスワードでログインする。
同意事項の確認
Gerritにログインした状態で Settings ー Agreements の順に選択。
個人なので Individual で Agreement する。
Gitの準備
ユーザ,メールアドレスの設定
ターミナルから git のグローバル設定。
名前とアドレスは Gerrit の Settings ー Profile の Full Name と Email Address に合わせる。
$ git config --global core.autocrlf input $ git config --global user.name "Full Name" $ git config --global user.email "Email Address"
Change-Id自動付与設定
$ scp -p atsushi4@codereview.qt-project.org:hooks/commit-msg .git/hooks
修正
Qtリポジトリからクローン
今回はQt4.8をベースにしたので
$ git clone ssh://codereview.qt-project.org/qt/qt
/qt/qt の部分は Gerrit の Admin ー Projects を参照。
Qt5なら
$ git clone ssh://codereview.qt-project.org/qt/qt5
ブランチ変更
ブランチは Projects の対象プロジェクトページへ飛んで
Branches を参照。
Qt4.8をベースにしたので
$ git checkout 4.8 $ git pull
トピックブランチの作成
$ git checkout -b mytopic
コード修正
コードいじる。
コミット,プッシュ
変更をローカルにコミット
$ git commit
リモートにプッシュ
$ git push ssh://codereview.qt-project.org/qt/qt HEAD:refs/for/master
だったような気がする(ぇ
レビュー
レビュワー追加
Gerrit の My ー Changes あたりから自分の変更ページに飛んで
レビュワーを入力して Add Reviewer ボタンを押す。
自分はqmakeで検索かけて
なんとなく近そうな変更のレビュワーさんを追加した。
コメント返信
変更のページで Review ボタンを押す。
コミット取り下げ
変更のページで Abandan ボタンを押す。この時にコメントも付けられる。