GoogleAppsScriptしか勝たん

本記事はWMMCAdventCalendar2021

adventar.org

の4日目の記事です。

昨日はImanishi君のEagleでユニバーサル基板の回路設計 - 気ままな日々日記でした。
自分が3年生の時の研究室課題でユニバーサル基板の回路設計があったんですけど、その時eagleでやろうとして面倒くささのあまり途中で投げてしまった記憶が…2.54mm…とか意識してビア開けたんですけど…心が折れたので来年の指導の際に参考にします…


 えーみなさん3日ぶりです。初日がついこないだ終わったと思ったらもう4日目が来てしまい、
記事が足りません。(OB・OGは参加してくださいね(圧力))
というかこのサークルにいる人間は24日と25日は絶対暇だろなんで空いてんだ忙しぶるな

12月4日追記:
aluminum君が24日に入れてくれました!
ありがとう!そして同志すぎる!
そして25に先輩が入ってくれました。
誰に脅迫されたんでしょうか…?
怖い人もいるものですねぇ…?

初日の記事は[これ](https://judge.hatenadiary.com/entry/2021/12/01/000000)です。

目次

0.まずはじめに
1.Google Apps scriptって?????
2.Google Apps ScriptでLINEに通知してみる
3.Google apps ScriptでSlackに通知してみる
4.Google apps Scriptでカレンダー情報を取得してみる
5.Google apps Scriptでのトリガー
 5-1.Google apps Scriptでトリガーを作製する
 5-2.Google apps Scriptでトリガーを削除してみる
6.これまでのすべてを組み合わせると...?


0.まずはじめに

 ことの始まりはすごく単純で、あまり研究室の話は外部に出してはならないので簡潔に話しますと、
今年から研究室のイベントが総務からメール通知されなくなりました。
以前までは会議やイベントの会場や議事録の提出先、資料のアップロード先などがリンクとともに通知されていたのですが
それが廃止となり、各自で「Google Calendar」を見る流れとなったわけです。

僕「いや~でもみるのめんどくさ。」

ちくいち開いて確認するのもだるいし、いきなり明日会議か!?になる未来が容易に想像できました。
そこで毎日1週間先のイベントまで通知してくれないかなって思ったのがGoogleAppsScriptを本格的に触るきっかけとなったわけです。

*実は1年前に仮想彼女を作ってLINEをしようという大層気色悪いユーモアにあふれた記事を投稿したのですが(リア滅の刃(無限爆破編) - judgeのブログ)
あの時は簡単にしか理解してなかったので再度やっていることになるのですが.....

1.Google Apps Scriptってなに

 Googleが提供するJavaScriptベースのプログラミング言語(というかGoogleソフトをCUIで扱うための開発環境に近い気がする)です。
何か自動化するとき、ラズパイだったりだと電源つけっぱにしないといけないのですが、
これは一度書いて実行してしまえば(かつトリガーを管理すれば)電源消しても動くので便利です。
まずは準備です。
Google Apps Scriptのエディタに移ってみましょう。
もちろんこれを見ている諸君はGoogle Chromeを使っているだろうから(エクスプローラerいないよな....?)
Googleアカウンコにログインし、Google Driveに移りましょう。
下の画像の①のところをクリックするとDriveがあるはずです。
f:id:WMMCsaiteihen:20211202011334p:plain

そうしたら②の「新規」→「その他」→「Google Apps Script」の順で進みますと以下のような画面に移ります。
なければ「アプリを追加」から追加してみてください

f:id:WMMCsaiteihen:20211202011832p:plain

これで一応GoogleAppsScriptのエディタ画面に移れたわけです。
これで一応の準備はできました。
ここでこの後の説明が面倒にならぬように「GoogleAppsScript」を「GAS」と略して表記いたします。
よろちくbi

2.Google Apps ScriptでLINEに通知してみる
 なぜ最初がLINEなのでしょうか。というのもSlackへの通知の布石です。
個人的にLINEのAPIの説明は初心者に優しいドキュメントなので実装が楽で勉強になります。
またここでLINEでの実装をしておくとほぼそのままSlackでの実装につなげられます。要するにエッセンス的な感じです。
では早速初めて行きましょう。
そもそもまずAPIをたたく手順を軽く説明します。
LINEからメッセージをいただくには以下の手順を踏みます。

①こちらから「リクエスト」と呼ばれるものをLINEのサーバに送ります。

②「リクエスト」を受け取ったサーバが「リクエスト」内容にそって情報を処理します

③サーバからデータが送られてきます。

④メッセージを受け取れます

これを実行するためにまずは「リクエスト」なるものの中身をどう書けばいいのか、それを調べる必要があるのです。

従ってLINEが公開しているAPIのドキュメント
developers.line.biz
を読みに行きます。が、その前に大切な準備があります。

上記のリンクを踏むと右上にログインボタンがあるのでLINEアカウントでログインしてください。
(日本人の70%がLINEユーザらしいのでさすがにアカウントはもっているものとします)
すると新規プロバイダーを「作製」というボタンがあるのでそれを押してLINEの通知用のアカウントを作成していきます。
名前を決めたら次に以下の画面になると思うので真ん中をクリックしてください
f:id:WMMCsaiteihen:20211202015844p:plain

するとアカウントの名前や説明などを入力することになるのでお好きにしてどーぞ
通知用アカウントを作製したら、まずは「Basic Setting(基本設定)」の項目に移りましょう。
一番下に「Your user ID」があると思うのでそれを保存しておきます
f:id:WMMCsaiteihen:20211202020951p:plain

また、その次に「Message APIの項目に移り、
その一番下にあるAccess Token」「issue」します。
(要するにアクセストークンというURlみたいなのを発行します)
f:id:WMMCsaiteihen:20211202021549p:plain

これもコピーして保存しておいてください
f:id:WMMCsaiteihen:20211202021729p:plain

ではここまでのことをコードに記述しておきます。

function NotifyLINE() {
  const USER_ID="あなたのUserIDを入力";
  const ACCESS_TOKEN="あなたのACCESS_TOKENを入力";
}

ここで関数の名前を「NotifyLINE」にかえておきました。

さぁ!ようやくドキュメント
Messaging APIリファレンス | LINE Developers
を読みます。

「Message」の項目のリクエスト部分の一行目は以下のようになっていると思います。
f:id:WMMCsaiteihen:20211202025557p:plain

その下は「ヘッダー」について
f:id:WMMCsaiteihen:20211202025620p:plain

更にその下は「ボディ」について
f:id:WMMCsaiteihen:20211202025644p:plain

書かれています。
「ボディ」の中の「messages」はさらに配列構造を持っていて
その中身は以下のようになっているということもわかりました。(テキストを送信する場合)
f:id:WMMCsaiteihen:20211202131132p:plain
今回はテキスト(文章)を送信するのでスタンプや動画を送りたいときは
同ドキュメントの別の項を参照してください。

「ヘッダー」やら「ボディ」やらと言いましたがこれらは「リクエスト」の中身です。
つまりこれらを含む「リクエスト」を作製して送り付ければよいのです。
これらをコードに落とし込んでいきましょう

function NotifyLINE() {
  const USER_ID="あなたのUserIDを入力";
  const ACCESS_TOKEN="あなたのACCESS_TOKENを入力";

  //以下が今回新しく記載した部分
  var url="https://api.line.me/v2/bot/message/push";

  var text="Hello, world";

  //リクエストヘッダー
  headers={
  "Content-Type":"application/json; charset=UTF-8",
  "Authorization":"Bearer "+ACCESS_TOKEN
  };

  //リクエストボディ
  body={
    "to":USER_ID,
    "messages":[{
      "type":"text",
     "text": text
    }]  
  };

  //リクエストの作製
  request={
    "method":"post",
    "headers":headers,
    "payload":JSON.stringify(body)
  };

  //fetch:引っ張ってくる
  UrlFetchApp.fetch(url,request);
}

これで準備ができました。
「Ctrl + s」で保存したら実行してみましょう!の前に、
ここで先程の「Message APIのところに行き、
QRコードから先程作製した通知用アカウントを友達登録しておきます。
f:id:WMMCsaiteihen:20211202133902p:plain

友達登録を終えたらGASのエディタから実行ボタンを押すことで通知が来るはずです。
         f:id:WMMCsaiteihen:20211202135521p:plain
これでGASを使ってLINEにメッセージを送ることができるようになりました。


3.Google apps ScriptでSlackに通知してみる

 先程のLINE通知を応用すればSlackへの通知も簡単です。
ちょちょいとコードを軽く変えるだけなのとドキュメントを読めばわかるので詳細は省きます。
それよりもLINEとは異なってSlackに「Incoming Webhook」を入れておく必要があります。
slackを開き①~③の順番でクリックし、
「カスタムインテグレーション」より
「Incoming Webhook」と検索し、インストールします。
f:id:WMMCsaiteihen:20211202142508p:plain
f:id:WMMCsaiteihen:20211202142821p:plain

その後、「Webhook URL」を保存しておきましょう
f:id:WMMCsaiteihen:20211202143537p:plain

これで準備が終わりました。
これらをコードに落とし込むと

function notifySlack() {
 //自分用のslack
  var url="先程のコピーした部分";
  var text="Hello, world";
  
  var body={
    "username":"予定リマインダー",
    
    "text":"<!channel>\n\n"+text,
    
    //自分のSlackの宛先チャンネル
    "channel":"#general"
  }

  var request={
    "method":"POST",
    "contentType":"application/json",
    "payload":JSON.stringify(body)
  } 
  
  UrlFetchApp.fetch(url,request);
}

通知は以下のようになります。
これでGASを使ってSlackへの通知をすることができました!
f:id:WMMCsaiteihen:20211202140434p:plain

4.Google apps Scriptでカレンダー情報を取得してみる
Google Chrome「GAS Calendar」などと検索すると公式のドキュメントに到達します。
これです。
developers.google.com

ではドキュメントを読んでいくのですがサポートされている関数が膨大なので今回は雑に省いていきます。

上から関数を見ていくと
「getEventById」という関数が見つけられま。
f:id:WMMCsaiteihen:20211202164039p:plain

クリックしてみると
関数の詳細が以下のように載っています。
f:id:WMMCsaiteihen:20211202164151p:plain

「Return」のところをみると「CalendarEvent」というものが返ってくるようです。
これをクリックしてみると
このように「CalendarEvent」クラスが表示されます。
クラスの中にある関数(=メソッド)も出てくるのでさらに調べることができます。
また、サンプルコードが出てくることもあります。
さぁコードを書いてみましょうと行きたいですがまず準備があります。
「GoogleCalendar」を開き、以下の①をクリックすると②の部分が出てくるので「設定と共有」をクリックします。
f:id:WMMCsaiteihen:20211202170133p:plain

その後下に移っていくと「カレンダーID」があるのでこれを保存しておきます。
f:id:WMMCsaiteihen:20211202170506p:plain

これにて準備は完了です。
ではまず簡単にカレンダー情報をとってくるコードを書いてみましょう
ここではまず例としてイベント名を取得するコードを書いてみます。

function getCalendar(){
  //もしgooglecalendarが変更になった場合、以下のCALENDAR_IDを変更
  const CALENDAR_ID="    ";//ここに先程のIDを入力!!!!!!

  //calendarIDを元にcalendar情報を取得
  var my_calendar=CalendarApp.getCalendarById(CALENDAR_ID);
  //イベント情報を取得する日を本日に指定
  var start_date=new Date();
  var my_events=my_calendar.getEventsForDay(start_date);
  
  my_events.forEach(function(my_event){
    //ここではためしにイベント名を取得してみる
    var title=my_event.getTitle().toString();
    Logger.log(title);
  })
}

上記の出力結果は以下のようになります
f:id:WMMCsaiteihen:20211202174848p:plain
今日のイベント名は「研究」でした。(してない)

他にも同様の情報を取得できます。
後のコードで紹介するのですが
大体はいかのこのメソッドで取得できます
f:id:WMMCsaiteihen:20211202180013p:plain

以下のコードでやってみます。

function getCalendar(){
  //もしgooglecalendarが変更になった場合、以下のCALENDAR_IDを変更
  const CALENDAR_ID="    ";//ここに先程のIDを入力!!!!!!

  //calendarIDを元にcalendar情報を取得
  var my_calendar=CalendarApp.getCalendarById(CALENDAR_ID);
  //イベント情報を取得する日を明日に指定
  var start_date=new Date();
  start_date.setDate( start_date.getDate() + 1 );

  var my_events=my_calendar.getEventsForDay(start_date);
  
  my_events.forEach(function(my_event){
    //ここではためしにイベント名を取得してみる
    var title=my_event.getTitle().toString();
    var mtg_url=my_event.getLocation();
    var my_event_description=my_event.getDescription();
    var event_start_time=my_event.getStartTime();   
    var event_end_time=my_event.getEndTime();

    Logger.log("イベント名:"+title);
    Logger.log("リンク:"+ mtg_url);
    Logger.log("開始時刻:"+ event_start_time);
    Logger.log("終了時刻:"+ event_end_time);
    Logger.log("説明:"+ my_event_description);
  })
}

結果はこうなります。
f:id:WMMCsaiteihen:20211202181049p:plain

しかしこれだと時刻が見にくいので修正します。
以下のコードに直すと

function getCalendar(){
  //もしgooglecalendarが変更になった場合、以下のCALENDAR_IDを変更
  const CALENDAR_ID="      ";//ここに先程のIDを入力!!!!!!

  //calendarIDを元にcalendar情報を取得
  var my_calendar=CalendarApp.getCalendarById(CALENDAR_ID);
  //イベント情報を取得する日を明日に指定
  var start_date=new Date();
  start_date.setDate( start_date.getDate() + 1 );

  var my_events=my_calendar.getEventsForDay(start_date);
  
  my_events.forEach(function(my_event){
    //ここではためしにイベント名を取得してみる
    var title=my_event.getTitle().toString();
    var mtg_url=my_event.getLocation();
    var my_event_description=my_event.getDescription();
    var event_start_time=my_event.getStartTime(); 
    event_start_time=Utilities.formatDate(event_start_time,"Asia/Tokyo","HH時mm分");  
    var event_end_time=my_event.getEndTime();
    event_end_time=Utilities.formatDate(event_end_time,"Asia/Tokyo","HH時mm分");

    Logger.log("イベント名:"+title);
    Logger.log("リンク:"+ mtg_url);
    Logger.log("開始時刻:"+ event_start_time);
    Logger.log("終了時刻:"+ event_end_time);
    Logger.log("説明:"+ my_event_description);
  })
}

結果はこうなります
f:id:WMMCsaiteihen:20211202181410p:plain

見やすくなりましたね。

これでGooglecalendarから1日のイベントは取得できましたね。
(逆に言えばfor文を使えば何日分もイベントは取得できますね)

7日分のイベント情報を取得するコードは以下のようになります。

function getCalendar(){
  //もしgooglecalendarが変更になった場合、以下のCALENDAR_IDを変更(以下は2021年現在のもの)
  const CALENDAR_ID="  ";

  //calendarIDを元にcalendar情報を取得
  var my_calendar=CalendarApp.getCalendarById(CALENDAR_ID);
  //イベント情報を取得する日を本日に指定
  var start_date=new Date();
  
  //1日のイベントを取得し${SHOW_PERIODS}回繰り返してtextを作成する
  for(var i=0;i<SHOW_PERIODS;i++){
    //今日一日のイベントを配列で取得
    my_events=my_calendar.getEventsForDay(start_date);
    my_events.forEach(function(my_event){//配列の各項目に対して以下の処理を行う
      var title=null; //イベント名
      var mtg_info;   //イベント情報全体
      var mtg_url;    //イベントのURL
      var my_event_description;  //イベントの備考欄
      var event_start_time;       //予定開始時間
      var event_end_time;         //予定終了時間

     //MTGのURLがLocationプロパティに入っているので今回はgetLocation()メソッドを使う
      mtg_url=my_event.getLocation();

      //イベント説明の取得
      my_event_description=my_event.getDescription();

      //イベントの開始・終了時刻を取得、それをフォーマット化する。(Utilities.formatDateをコメントアウトしてLogger.logすれば意味が分かる)
      event_start_time=my_event.getStartTime();
      event_start_time=Utilities.formatDate(event_start_time,"Asia/Tokyo","HH時mm分");
      event_end_time=my_event.getEndTime();
      event_end_time=Utilities.formatDate(event_end_time,"Asia/Tokyo","HH時mm分");      

      title=my_event.getTitle().toString();
      text+="・${month}月${date}日[${day}]の予定\n".replace("${month}",(start_date.getMonth()+1).toString()).replace("${date}",start_date.getDate(). toString()).replace("${day}",day_array[start_date.getDay()].toString());
      text+="`"+title+"`"+"\n";
      text+=" 時間:"+event_start_time+"~"+event_end_time+"\n";
      text+=" MTG場所:"+mtg_url+"\n";

      if(mtg_url!=""){//URLが存在する場合
        text+=" MTG場所:"+mtg_url+"\n";
      }

      if(my_event_description!=""){//説明がある場合
        text+=" [補足事項]\n"
        text+=" "+my_event_description+"\n\n";

        //正規表現をもちいてHTMLタグを消去
        text=text.replace(/(<([^>]+)>)/gi,'');
        text=text.replace(/&nbsp;/gi,"");
        text+="----------------------------------------------------------------------------------------------\n";         
      }else{//説明がない場合
        text+=" [補足事項]\n 無し\n\n"
        text+="----------------------------------------------------------------------------------------------\n";      
      }
    })
    //日付を進める
  start_date.setDate(start_date.getDate() + 1);
  }
      //予定がないとき
    if(text==""){
      text+="この1週間は学部・修士生に関係するイベントはありません";
    }
    //送信するtextの内容を確認する時用の関数
    Logger.log(text);
  return text;
}

結果はこのようになります。
f:id:WMMCsaiteihen:20211202183856p:plain

正規表現などの部分は自分で勉強しておいてください...

5.Google apps Scriptでのトリガー

5-1.Google apps Scriptでトリガーを作製する
トリガーというのは、これまで書いたコードを実行開始する何かしらのきっかけのことを指します。
コードは以下のようになります。
なお実行させたい関数の名前を「ScriptApp.newTrigger」関数に入れておけばオッケーです。

/****************************************************************
 * setTrigger()
 * 引数:なし
 * 返り値:なし
 *
 *[処理の説明]
 *・次の関数実行の時間トリガーを設定する(次の日の0:00) 
 ****************************************************************/
function setTrigger() {
 var setTime = new Date();
  setTime.setDate(setTime.getDate() + 1)
  setTime.setHours(0);
  setTime.setMinutes(00); 
  ScriptApp.newTrigger('実行させたい関数の名前').timeBased().at(setTime).create();  
}

実際に実行し、
以下のように画像の左の時計のマークをクリックすると
トリガーが作製されていることが確認できます。
f:id:WMMCsaiteihen:20211202144706p:plain


5-2.Google apps Scriptでトリガーを削除してみる

上節と同様にトリガーを消すことも可能です。

/*****************************************************
 * deltrigger()
 * 引数:なし 
 * 返り値:なし
 * 
 *[処理の説明]
 *・関数実施トリガーをいったんすべて消す
 *****************************************************/
function deltrigger() {
  const triggers = ScriptApp.getProjectTriggers();
  for(const trigger of triggers){
    if(trigger.getHandlerFunction() == "関数の名前"){
      ScriptApp.deleteTrigger(trigger);
    }
  }
}

6.これまでのすべてを組み合わせると...?

//**グローバル変数の定義***************************************//
//本文の変数text.これに本文を追加していく
var text="";
//曜日の配列
var day_array = new Array('日', '月', '火', '水', '木', '金', '土');

//以下のマクロ(的なの)を変えることでcalendarのイベント情報取得期間を決定している(以下では7日)
const SHOW_PERIODS=7;
//***********************************************************/

/****************************************************************
 * setTrigger()
 * 引数:なし
 * 返り値:なし
 *
 *[処理の説明]
 *・次の関数実行の時間トリガーを設定する(次の日の0:00) 
 ****************************************************************/
function setTrigger() {
 var setTime = new Date();
  setTime.setDate(setTime.getDate() + 1)
  setTime.setHours(0);
  setTime.setMinutes(00); 
  ScriptApp.newTrigger('notifySlack').timeBased().at(setTime).create();  
}

/*****************************************************
 * deltrigger()
 * 引数:なし 
 * 返り値:なし
 * 
 *[処理の説明]
 *・関数実施トリガーをいったんすべて消す
 *****************************************************/
function deltrigger() {
  const triggers = ScriptApp.getProjectTriggers();
  for(const trigger of triggers){
    if(trigger.getHandlerFunction() == "notifySlack"){
      ScriptApp.deleteTrigger(trigger);
    }
  }
}

/******************************************************************
 * getCalendar()
 * 引数:なし 
 * 返り値:Slack通知内容本文
 * 
 *[処理の説明]
 *・GoogleCalendarより1週間分の予定を取得して本文作成
*******************************************************************/
function getCalendar(){
  //以下にCALENDAR_IDを入力
  const CALENDAR_ID= "              ";

  //calendarIDを元にcalendar情報を取得
  var my_calendar=CalendarApp.getCalendarById(CALENDAR_ID);
  //イベント情報を取得する日を本日に指定
  var start_date=new Date();
  
  //1日のイベントを取得し${SHOW_PERIODS}回繰り返してtextを作成する
  for(var i=0;i<SHOW_PERIODS;i++){
    //今日一日のイベントを配列で取得
    my_events=my_calendar.getEventsForDay(start_date);
    my_events.forEach(function(my_event){//配列の各項目に対して以下の処理を行う
      var title=null; //イベント名
      var mtg_info;   //イベント情報全体
      var mtg_url;    //イベントのURL
      var my_event_description;  //イベントの備考欄
      var event_start_time;       //予定開始時間
      var event_end_time;         //予定終了時間

     //MTGのURLがLocationプロパティに入っているので今回はgetLocation()メソッドを使う
      mtg_url=my_event.getLocation();

      //イベント説明の取得
      my_event_description=my_event.getDescription();

      //イベントの開始・終了時刻を取得、それをフォーマット化する。(Utilities.formatDateをコメントアウトしてLogger.logすれば意味が分かる)
      event_start_time=my_event.getStartTime();
      event_start_time=Utilities.formatDate(event_start_time,"Asia/Tokyo","HH時mm分");
      event_end_time=my_event.getEndTime();
      event_end_time=Utilities.formatDate(event_end_time,"Asia/Tokyo","HH時mm分");      

      title=my_event.getTitle().toString();
      text+="・${month}月${date}日[${day}]の予定\n".replace("${month}",(start_date.getMonth()+1).toString()).replace("${date}",start_date.getDate(). toString()).replace("${day}",day_array[start_date.getDay()].toString());
      text+="`"+title+"`"+"\n";
      text+=" 時間:"+event_start_time+"~"+event_end_time+"\n";

      if(mtg_url!=""){//URLが存在する場合
        text+=" MTG場所:"+mtg_url+"\n";
      }

      if(my_event_description!=""){//説明がある場合
        text+=" [補足事項]\n"
        text+=" "+my_event_description+"\n\n";

        //正規表現をもちいてHTMLタグを消去
        text=text.replace(/(<([^>]+)>)/gi,'');
        text=text.replace(/&nbsp;/gi,"");
        text+="----------------------------------------------------------------------------------------------\n";         
      }else{//説明がない場合
        text+=" [補足事項]\n 無し\n\n"
        text+="----------------------------------------------------------------------------------------------\n";      
      }
    })
    //日付を進める
  start_date.setDate(start_date.getDate() + 1);
  }
      //予定がないとき
    if(text==""){
      text+="この1週間は学部・修士生に関係するイベントはありません";
    }
    //送信するtextの内容を確認する時用の関数
    Logger.log(text);
  return text;
}

/******************************************************************
 * notifySlack()
 * 引数:なし 
 * 返り値:なし
 * 
 *[処理の説明]
 *・getCalendar()関数より帰ってきた本文をそのまま通知する
*******************************************************************/
function notifySlack() {
  deltrigger();
  setTrigger();
  var text=getCalendar();

  var body={
    "username":"Calendar",
    "text":"<!channel>\n\n"+text,
    //自分のSlack時
    "channel":"#random"//好きなチャンネル名に変えてください
  }

  var request={
    "method":"POST",
    "contentType":"application/json",
    "payload":JSON.stringify(body)
  } 

  //自分用のslackのID
  var url="   ";
  
  UrlFetchApp.fetch(url,request);

}

f:id:WMMCsaiteihen:20211202184633p:plain
結果としてSlackにカレンダー情報を1週間分取得して通知してくれるシステムが完成しました。


さて、明日はxfa君の
GMSなんていらん!?」
です。
すまん単語がまずわからん…から何書いてくれるのかわからんけどとりあえずお楽しみに!

WMMC AdventCalendar 2021 1日目

この記事は

WMMC Advent calendar 2021

adventar.org

の1日目の記事です。

当方は素人で、内容についての厳密性などが欠けていることがありますのでご了承ください。

0.開催者の戯言

さて!皆さまお久しぶりです。 コロナ第三波?の中始まったなんとも楽しくなさそうな1年も大半が過ぎ、今思えばなかなか楽しかった気もします。(気のせいです) そんな一年の最後の師走。 皆さんはどんな一年でしたか?

卒論・修論で大変な人もいると思います。(僕です) 社会人一年目で早くも転職を考えている人もいるでしょうか() それとも、初の対面授業にやっと大学生活っ!を感じた人もいるのかもしれません。

僕は、まぁ寂しさと悲しさが多かった一年でした。 研究室が違うとコロナも相まって仲の良かった同期とも会うことはなくなりました。 中には一人で何かを抱えてしまう人もいたでしょう。 悲しいこともいくつかありました。

寂しい、といえば入学して仲の良くなった先輩達(今年だと2つ上)はもう卒業ですね。 気が早いんですけど少し寂しいです。未だに自分が1年生の気分でいるときがあるので..

とまぁしんみりはおいといて 最後ぐらい楽しくブログのリレーでもしましょうか。(記事をたくさん書くことになると卒論と相まってつらくなるんでOBOGの人参加者募集です)

1.本題

 AdventCalendarの予約の内容を見ていると各々が結構楽しそうな記事を上げそうなので 僕はここ1週間で頑張ってまともな技術的な記事を書いてみました。 内容はそれなりに複数用意していたんですけどいくつかお粗末すぎるのでまともなやつを先に上げておいて、 参加者がいなければお粗末すぎるやつも挙げていきます(仕方ないので) 最悪まともなやつを2分割すればよいので大丈夫ですが。 (11/30追記:結局今回の記事の類似版を別の記事にするかもです)

以下のリンクを踏むとここから先が読めます(変なサイトとかじゃないので踏んで大丈夫です。) ただ、開くならPCがおすすめです

ここから先

2.最後に

バトンを渡し損ねる前にここで渡しておきます(笑) 明日はぱわぷろさんの記事で

「動画…作ってみないか?」とのことです。

例の某SAMURAIのほうで培ったスキルの紹介なんですかね...? よくわかんないですけど読むの楽しみにしてます。 忙しい中2日目に入れてもらって助かりましたありがとうございました!!!!!!!! ついでに3日目も入ってくれた後輩くんもカンシャッ!

また、その他の参加者の皆さんも年末のお忙しいところ大変ありがとうございました。 ちなむと今のうちに言っておくと僕に気力さえあれば()来年も僕が主催でやるつもりなので 参加よろしくお願いします!

飲食における「●/円」の追求

1.はじめに
お久しぶりです。皆さんお元気でしょうか。
コロナという聴き慣れなかった単語も、もはや聞かない日が1日もない、そんな1年半を過ごしていると思います。
その中で仕事が無くなったり、バイトが減ったりと収入面で困った方はいるのではないでしょうか。

収入が減ると、食費の点で非常に苦労しますよね?
そこで、私はある素晴らしい評価単位を考えました。
(ここでいう評価単位は独断と偏見に満ちた評価関数のようなものです)

そう、

「○/円」

です。
これの素晴らしいところは、食材に求める目的に対してのコスパがわかるというところにあります。

例えば、食材毎に
「ビタミンC含有量/円」
を調べるとしましょう。
ビタミンCには以下の効果があります。

ビタミンCが不足すると、コラーゲンが合成されないために、血管がもろくなり出血を起こします。これが壊血病です。壊血病のそのほかの症状としては、いらいらする、顔色が悪い、貧血、筋肉減少、心臓障害、呼吸困難などがあります。また、毛細血管・歯・軟骨などを正常に保つ働きがあるほか、皮膚のメラニン色素の生成を抑え、日焼けを防ぐ作用や、ストレスやかぜなどの病気に対する抵抗力を強める働きがあります。

 最近はビタミンCの抗酸化作用が注目され、がんや動脈硬化の予防や老化防止にビタミンCが有効であることが期待されています。

引用:ビタミンCの働きと1日の摂取量 | 健康長寿ネット(2021年8月20日現在)

例えば、あなたが壊血病を防ぐ食生活をしたい時、この評価単位を用いればどの食材がコスパよく壊血病を防げるか、がわかるのです。
でも、自分で勝手に作っておいてアレですが、
本当にコレでいいのでしょうか。
工学的には評価関数はある程度厳密に作成するものですが、今回はおふざけなのでガバガバ評価をしてみたいと思います。

これによる評価は本当に適した食材に行き着くのか、それを知るべく、我々は日本社会の食材に目を凝らし始めた…


2.これはアカンかった
いや結果から言ってアカンかった。
色々調べてみたので実際に紹介しつつ、読者にも「これはアカン」を追体験していただこう。

➀「kcal/円」
以前Twitterで見かけた気がするが、この評価指標は結構なじみがある人も多いと思う。
コスパ良く太りたい人・安くエネルギー源を補給したい人に向けている。

まずは身近にあるもののの中でカロリーの高そうなものを3つほど調査してみよう。
ここでは「ラーメン」・「ポテトチップス」・「カロリーメイト」を調べてみる。

まずはデブ食代表の「ラーメン」だ。
ラーメンといっても味や種類によってカロリーが違うと思われるのでネットにあった二郎情報で算出を行った。

二郎系ラーメン
値段:900円(アバウト)
カロリー:2500kcal(大盛時)
kcal/円:2.7777

という結果となった。これだけではこの値が高いのか、低いのか全く分からない。そこでほかの2つでも算出してみた。

ポテトチップス のり塩(湖池屋)
値段:144円(アバウト)
カロリー:337kcal
kcal/円:2.34

カロリーメイト ブロック チョコレート味
値段:170円(最安)
カロリー:400kcal
kcal/円:2.353

どうであろうか。あのコスパ最強とよばれ、一杯食べると1日他の食事が不要とまで言われる二郎ラーメンや、デブ食の代表ポテチ・さらには「カロリー」を冠するカロリーメイトをもってしても「kcal/円」で3を超えられないという結果となった。

では、逆に3を超える食べ物は何なんであろうか。
僕が簡単に思いついたものとしては
ブラックサンダー
②チョコチップスナックパン

がある。
実際、それぞれを計算してみると

ブラックサンダー
値段:32円(アバウト)
カロリー:112kcal
kcal/円:3.5

...おぉ!!強い!つえー。ここにきて大台の3を軽く超え、4に近い値を確認することができた。
この調子で次も算出してみる。

チョコチップスナックパン(山崎製パン株式会社)
値段:178円
カロリー:1152kcal
kcal/円:6.47

f:id:WMMCsaiteihen:20210824225301p:plain
今回のチョコチップパン

...「kcal/円」界の吉田沙保里が来ました。インフレ甚だしいにもほどがあります。
これを超えるものはないです。調査終了!

















と、思い込んでいました僕は。
でも気づいてしまったんです。
「サラダ油」直飲みの可能性に。もう一度言います。

「サラダ油」直飲みの無限の可能性に。

あの「wawawa」然り、この世には「サラダ油」直飲み勢がいあるはずでしょう。多分きっとおそらくmaybe...
算出してみましょう。

サラダ油(1300g)
値段:342円(アバウト)
カロリー:11700kcal
kcal/円:34.2

f:id:WMMCsaiteihen:20210824230201p:plain
悪魔の飲み物

..................................異世界転生モノのチートってこんな感じなんでしょうね。
コスパ良く太る・安くエネルギー源を補給する、の解答はこれで間違いありません。
....ね、アカンでしょ????

②「アルコール含有量/円」
まぁこれは言ってしまえば安く酔いたい人に向けた指標です。
っていってもじゃあ「エタノールとかの原液飲みなよウェイwowwow」って話ではなくて、
市販の飲料で比較します。流石に。
ここではまず、「日本酒」「スト缶」「スピリタス」あたりでやってみましょう。
ノリが軽いけどスピリタス出してるの笑う

用いる式は

摂取量(ml)×度数(%)×0.01×0.8(比重)=アルコール含有量(g)

です

日本酒(関白 壱弐七)
値段:990円(アバウト)
アルコール含有量:124.992g
アルコール含有量g/円:0.126

スト缶(500ml)
値段:211円(アバウト)
アルコール含有量:36g
アルコール含有量g/円:0.17

スピリタス
値段:2073円(アバウト)
アルコール含有量:384g
アルコール含有量g/円:0.18


これらからわかることはこの指標では0.2を超えるのは非常に難しいということです。
日本酒はアルコール度数が22度以下である必要があり、今回の指標では小さい値になっています。
逆にあのスト缶はスピリタスに近い値をとっており、実質安価スピリタスです。
毎日3本程度飲んで研究・仕事・課題などの嫌なことは忘れましょうお酒はほどほどにしましょう

で、話はまだ終わらなくて。
まぁ異世界チーターを探してみたんですよ。この指標での。

いたんですよ。最強が。
僕の脳内には「おいしいかもー」の声とあの愉快な音楽が聞こえてきます。
ちゃっちゃっちゃーちゃっちゃちゃちゃー
ちゃっちゃっちゃーちゃっちゃちゃちゃー デーン♪

f:id:WMMCsaiteihen:20210825000603p:plain
wawawaの生命線

そう、こいつですね。

業務用ハイボール(5000ml)
値段: 6,779円(アバウト)
アルコール含有量:1600g
アルコール含有量g/円:0.236

0.2こえたぁぁあぁぁぁぁぁぁ!!!!!!!!!!
....wawawa恐るべし...

このようにコスパを追い続けると破綻を招くことがわかります

3.最後に
 いかがだったでしょうか(底辺サイト感)
このように「/円」を食材に求めすぎると、人外を目指す必要があることが判明しました。

今後も何かの「/円」を追っていきたいと思います。

なにかもっと上があれば教えていただけると幸いです。

追記:
餅(業務用)→9.8kcal/円で
チョコチップスナックパンを超えてます

Jetson nano 2GBセットアップしたんだが(Windows版)

0.ひとり言の部分

新年明けましておめでとうございます。

昨年度はそれはそれは酷い一年でした。コロナだけで学生生活1年が終わってしまったのはまぁなんとも言えない悲しさがありますし、リモートのせいで本来学ぶべきことが学べずに終わってしまったような気がします。そして気づけば卒論研究が始まってしまう事実が迫ってきております。死ぬのかな俺。

さて、 わかりにく便利すぎていつ終わったのかわからぬままJetson nanoの初期設定が終わったので今回はこのお話しです。

先日の話であるがJetson nano (RAM 2GBの方)を購入した。正直ESPマイコンを遊んでもよかったんですが、それよりもこっちで遊んでみたい欲が高かったので我慢できなかった。 ↓こいつ f:id:WMMCsaiteihen:20210103143833j:plain

あ、このブログについて間違いがあればご指摘ください。マジで何もわからぬままセットアップしたので....

逆に言えば本記事を読んで生じたいかなる問題について責任は負いません

さて早速ですが今回は先月のブログよりもゆるく適当にお送りします。

1.まずはじめに

2.実際にセットアップしてみよう

step①SDカードにOSを入れておく

step➁Jetson 上での設定

step③TP_Linkの設定

step④動作確認

1.まずはじめに

先日、秋葉原の秋月にてJetson nano 2GBを購入した。そしてwi-fiトングルとしてTP_Link(TL-WN725N)を購入した。ネットで調べてみると便利とのことでその言葉を聞いて何も考えずに購入した。(脳死)

今回のセットアップに使うものを以下に示す。

【今回必要なもの】

  • Jetson nano 2GB
  • TP_Link(TL-WN725N)
  • typeA-microBケーブル
  • typeCコネクタの電源(私はThinkPadユーザーなのでその充電器をそのまま使ったが某ゲーム機Switchの充電コードでも行けるかもしれない)
  • SDカード(64GB以上)
  • PC(Windows 10)

これらを用いてセットアップを行っていきます。

2.セットアップしてみよう

では早速セットアップをいたしましょう。

Step①SDカードにOSを入れておく

まずはJetson nanoの公式セットアップ手順と同じ手順で SDカードにJetson nano用のOSをFlashしていきます。

まずはSDカードをフォーマットする必要があります。

SDカードをフォーマットするとは初期化&準備のことです。まずデータをすべて消し、その後そこに指定した形式のデータを詰め込む準備を行うということです多分。なのでそのフォーマットを行うにはSD Memory Card Formatter for windows Downloadというソフトをインストールし、それを使う必要があります。

その後Flashという書き込み動作をする必要があるのですがそれはそれで別のソフトが必要です。なのでまずはそれまでの手順を行っていきましょう

まずはお持ちのWindowsパソコンにてSD Memory Card Formatter for windows Downloadをインストールしてきます。インストールは流れに沿って行けばできるはずなのでリンクを示すだけでここでは終わりにします。

インストールしたらSDカードを挿入します。ここが難所であるのだが、ThinkPadsurface proもSDカードの挿入口が人生3週目じゃないと気づきません(マジで)

SDカードをさし終えたらフォーマットを行います。先程インストールしたSD Memory Card Formatter for windows Downloadを開くと以下のような画面がでてきますので以下の画像通りに設定してください。 f:id:WMMCsaiteihen:20210103180543j:plain そしたら下のボタンを押すだけでフォーマットが完了します。もしSDカードが認識されていなければ"フォルダ→PC"でCドライブの横にSDカードの容量が示されていることを確認してください。PCを再起動するとうまくいくときもありますがSDカードが傷ついてないかなども確認してください

さて、SDカードをフォーマットし終えたら次はSDカードに書き込む内容とそのためのソフトをインストールします。

書き込む内容はこちらより取ってくることができます。きちんと2GB用のイメージファイルであることを確認しましょう。使いやすいようにこのファイルはデスクトップ上に置いておくとよいです。

次にFlash用のソフトEtcherをインストールします。こちらもエッチな手順通りに沿って行けば淫ストールはできますのでここでは省略します

ここまで来たら以下の画像の通りにやって行けばFlashは終わりです。

まずはEtcherを開きます。 書き込む内容を一番左のf:id:WMMCsaiteihen:20210103174622j:plainFlash from file」 より選択します。書き込む内容はデスクトップに置いておいたのですぐに選択できるはずです。 次にf:id:WMMCsaiteihen:20210103180913j:plain真ん中のボタンにてどのメモリに書き込むかを選択します。間違ってもCドライブに書き込まないようにしましょう。SDカードを選択します。 あとは一番右端の「Flash」を押すだけです。 f:id:WMMCsaiteihen:20210103174820j:plain f:id:WMMCsaiteihen:20210103174852j:plain こんな感じで書き込みが始まりますのでしばらく待ちましょう。

終わりましたか?

それでは次に初回ブートを行っていきます。ブートなんて言うとあれなので初期設定とでもいっておきます

Step➁Jetson 上での設定

GUIでの設定ができれば便利ですがこちとら学生ですのでディスプレイを買うお金は省きたいものです。なのでCUIでの操作で設定を行っていきましょう(Linuxコマンドのお勉強になるので一石二鳥)

さきほどフラッシュしたSDカードをJetsonに挿入しておきます。向きを間違えるとSDカードの損傷につながるのでダミーカードを使うなりして向きを確認してから挿入しましょう。ちんぽにゴムをつけるぐらいチン重に慎重に...

挿入が終わりましたらTypeC電源を装着します。繋ぐとJetson上の緑のLEDが光るので電源が入っていることがわかります。

次に電源挿入後**30秒**ほど待ってからmicroBケーブルをつなぎます。TypeAの方はWindowsのPCにつなぎます。

この時点でいちおう通信速度の確認とポートを確認します。

【確認方法】

1.左下のwindowsマークを右クリック

2.「デバイスマネージャー」を選択

3.「ポート(COMとLPT)」を選択します。ここでCOMポート番号が確認できます

4.設定から「ポートの設定」をクリックし、その後ビットを115200に変えておきましょう。以下図を参照してください

no image

さてここまで来たらターミナルで初期設定を行っていきます。

ターミナルソフトとしては

などがあるでしょう。公式の勧めるPuTTYでも可能ですが今回はTeratermを使います。個人的にはRloginが気になるので今後使ってみたいところです

Teratermインストール方法の解説サイトはこちらですのでこちらを参照してもらえると幸いです

teratermを開いたらCOMでの通信を選択し、その後「設定」➡「シリアルポート」➡スピードを「115200」に変更します(デフォルト設定をしてないならば)

ここまでしたら「Enter」か「space」でも押すとJetsonのConfiguration(設定)が始まります

国、言語、ユーザー名、パスワード、LAN、ドメイン名などを設定すれば終わりです。スワップファイルを作成するように要求されるので作成しましょう。基本ここはユーザー名以降は大抵デフォルト設定でオッケーです。(多分)

注意)(わからない単語があれば逐一調べて確認しましょうね☆Ethernetは有線LAN!など、基本的なIT知識があれば詰まることはないでしょう)

Step③TP_Linkの設定

では、Jetsonを起動したらubuntsuのOSが入っているのでログインします。先程設定したユーザー名とパスワードでログインします

ここでTP_LINKをjetsonに接続させます

まずは

free

コマンドで残りのSD容量を確認します。十分に残っていたら

その後

sudo apt update
sudo apt upgrade

でアップグレードします 色々インストールされますのでしばらく待ちます。 その後、

nmcli device wifi list

で今現在接続可能なWi-fiを探すことができます。接続の電波の強さ順で色が変わります。ゲーミングカラーですね。

f:id:WMMCsaiteihen:20210103174959j:plain

今回は私の自分の家のWifiに接続するため、先程確認したSSIDを用いて

nmcli --ask dev wifi connect [SSID]

を実行するとWifiパスワードを要求されるので家のルータのSSID暗号化キーでも打っておけばとりあえずWifiに接続ができます。

Step④動作確認

最後に接続できているのかの確認です

nmcli d

で接続状況を確認します。 connectedの表示がされ、接続できてそうなら最後に

sudo apt install sl

コマンドでslが走ってくることを確認しましょう。 これでセットアップが完了しました。 これで色々遊べるようになります。 ディスプレイを買っておけばここまでの全てをGUIベースでできるので便利ですが今回はCUIでの設定となりました。

今後休みの間に少しずつ遊んでいきたいと思います。

では、良いお年を〜。

リア滅の刃(無限爆破編)

題名の時点で溢れ出るクソ記事感を感じたそこのあなた、てめぇの感性は捨ててついてこい!!!俺の承認欲求のために読んでもらう!!読め!!読め!!読め!!読め!!読め!!読め!!読め!!

自分の為すべきことを為せ!!

 

重大注意:いや〜まっさか〜!!僕の知り合いにいるはずもないと思っておりますがリア充の方がいらっしゃったらここから先読まないことを勧めておきます〜ねっ⭐︎

 

この記事はWMMC Advent Calendar 2020 - Adventar

の15日目の記事です。

昨日はyoka様のMMDモデルを作りたい…! - yokのブログ

でした。

最近身の回りでVtuberにハマってる低レイヤーの人がいた影響もあってMMDモデルに興味出てたんですが、こんな苦労して作るんものと知っって勉強になりました。絶対にやれません。

(一番お忙しい時にこの企画参加を半強制させてしまい大変申し訳ありませんでした。)

 

まともなマウス関連ブログを読みたいひとは12月2日にマイクロマウス界隈の方のAdvent calendarであげた

Advent calendar revenge match in2020 (HAL+MPU9250) - judgeのブログ

でもどうぞ。間違ってたらご指摘ください。

 

0.目次

1.クリスマス、苦しみます

2.そういや、ブログ書くんやったっけ

3.実行編

4.爆発は芸術だ!!喝!!!

5.彼女とLINEしよっ?

6.さぁ、彼女(bot)を作ろう

 

1.クリスマス、苦しみます

はるか昔、飛鳥時代に、日本は大乗仏教が伝来してきました。病を治すのは信心だとして庶民から貴族まで広く信じられておりました。

ここまでは良き日本でした。

そしてそれからわずか1500年経った2020年、

日本に蔓延してたのは

憎きイベント、そう、

 

🎄クリスマス🎄

 

なのです

(+バレンタインデー&ホワイトデーetc)

 

毎年、毎年、毎年、毎年毎年毎年!!!

苦しめられている!!!俺は!!!

こいつらに!!!

そして例に漏れず今年も!!僕はこのままあと10日以内に彼女ができなければ22年連続でクリスマスに苦しむことになる。高校で習ったドミノ論法(数学的帰納法)を思い返しても、n=2まで確かめたら大抵n=kとn=k+1の吟味にはいった気がするんだが…?もうn=21までは吟味したのですがこの論法のソースどこ?マジで当たってるんだけど?天才か?

 

…いや、n=22こそは外さねばならない…このまま終われるか…極限まで来た僕の脳内には

 

  1. 彼女を作る
  2. リア充をぶっ潰す♪

 

の2択が浮かんだ。

そしてコンマ2秒後にはリア充をぶっ潰すことを決意した。もう片方は無理だと本能が叫んでいたからだ。

しかし、どうしたらいいのだろうか、全世界のうち少なくとも70億人はリア充撲滅運動に対してやる気はある()はずなのだが、いかんせん行動に移す輩はいない。それはその通りで、

だって、自分一人で社会に立ち向かっても結果は分かりきっているから。

 

なら、俺がその筆頭になってやる…!!!

         どうてい

こい!!!勇敢なる猛者ども!!

f:id:WMMCsaiteihen:20201212140528j:image

  はいしゃ

僕は貞王としての意識を持って行動に移すことにした。

 

2.そういや、ブログ書くんやったっけ

 突然、Advent calendarでブログを書かないといけないことを思い出しました。が、ネタがない。適当に書けばいっか〜はははとか思ってたんですがルービックキューブの人(ルービックキューブが難しすぎた話 - lmFfGQUkniaZの日記)のような堕ち方が容易に想像ついたので開催者としてあかんやろうし、1年生のあの若さ(シャニマスを初めてちょうど100日の新人Pがシャニマスを語る(ついでに自己紹介も) - Yamayouの部屋)はもう精神的に出せない…

そう、秘密裏に行動するはずだったリア充撲滅計画をブログネタに昇華することでとりあえずネタはクリアとすることにしたのです(12月12日現在)

(まぁネタに安堵した僕はここから始まる14日までサボることになるのですが…)

 

いかんせん僕の周りは非リアしかいないので良いのですが、全世界レベルの範囲までこの活動を布教するためにはブログに残して行くしかねぇのでまぁ結果的には良かった。

 

3.実行編

さて、大変です。同期とAmong usしてたら(A.M 6時現在)14日になってしまいました。ブログは明日なので急いでこれを完成させます…。

デートスポットを実際に爆破したら犯罪でオナわですし、かと言ってリア充への愚痴TwitterTLを埋めるのも癪ですから、とりあえず2次元で爆破させることで妥協点としました。

学習させる時間の短縮のため、既存の学習済みデータを持ってくることにします。

そして、カップルの画像を集めてきます。

この時点で地獄の苦しみを身体に刻みますが耐えましょう。

 

ライトなものから持ってきます。

(なお、公開されていてかつ肖像権的に顔が写ってないものを多く載せます。)

 

f:id:WMMCsaiteihen:20201212143954j:image

oh…f○ck…

 

f:id:WMMCsaiteihen:20201212144106j:image

はーいあとで抹消するで〜ははは〜

 

 

f:id:WMMCsaiteihen:20201212144741j:image

ヴァァァァ゛ァァァ゛ア゛!!!!!

(吐血)

はぁ…はぁ…まだだ…

 

f:id:WMMCsaiteihen:20201212144947j:image

け、結婚〜!?はぁ…はぁ…

アラサーの称号の足音が聞こえる…違う…俺はまだ

"お兄さん"だ!!…黙れ!!オジサンじゃねぇ!!!え?"拗らせ"オジサン???

やめろ!!取り消せ!!その言葉ァァァア゛ァ!!

 

はぁ…はぁ…まず銃口を向けます。ターゲットマークをつけて○す。…待ってろすぐにあの世行きさ…

 

以下の既存の学習データ(h5ファイル)を取り込んできて、機械学習によって物体検知を使ってターゲットを定めます。

https://github.com/OlafenwaMoses/ImageAI/releases/download/1.0/resnet50_coco_best_v2.0.1.h5

言語はpythonでした。

使用環境はAnaconda3です。

コマンドプロンプトにて

conda create pyimage python==3.6

(後に使うTensorflowは最新のpython3.9には対応しておりませんのでよろしく)

 

仮想環境として僕はpyimageという仮想環境を立ち上げました。

あとはconda installコマンドで必要なものをインストールしてきます。

(ここで僕はpipでインストールしようとしたら死滅→condaでうまくいくものの、先輩に相談して解決したのでAnacondaはクソ)

【ふざけるな Anaconda】Windows で Python 環境を整える – 茱萸note

これからpythonやる人は環境構築にこちらをみてどうぞ。

さて、以下のコードを以下の順番でコマンドプロンプトに入力し、

conda install numpy==1.16.1
conda install scipy
conda install opencv
conda install matplotlib
conda install tensorflow==1.13.1
conda install keras==2.2.4
conda install h5py
conda install -c powerai imageai

あとは学習データファイルを以下のコードファイルと同じところのディレクトリにぶち込んでおけば準備オッケーです。以下のコードをコンパイルして実行します。(ちなむとAnaconda3は使いにくいのでpycharmの方がpython環境は良いと思います個人的に)

from imageai.Detection import ObjectDetection

import os

 

execution_path = os.getcwd()

detector = ObjectDetection() detector.setModelTypeAsRetinaNet() detector.setModelPath( os.path.join(execution_path , "resnet50_coco_best_v2.0.1.h5")) detector.loadModel()

で、結果ですが先程の画像はこのように出力されます

 

f:id:WMMCsaiteihen:20201212150155j:image

f:id:WMMCsaiteihen:20201212150310j:image

f:id:WMMCsaiteihen:20201212150320j:image

f:id:WMMCsaiteihen:20201212150329j:image

 

ターゲットが青枠で囲まれましたね。

これを画像処理して爆破させます。

 

4.芸術は爆発だ!!喝!!!

かのデイダラは言いました。

"芸術は爆発だ!!!"

と。

かのワイも言いました。

これコンプラ的にやばくね?

と。

突然芽生えた常識的な感性。やったところで面白くもない結末…

いや!爆破させてから後悔しよう!!!

次に、open CVでの爆破です!(ヤケクソ)

本当は青枠のカラー検知した後に大きさの違う画像同士を合成するプログラム書こうと思ったんですがGoogleの陰謀でソースコードを吹っ飛ばし、残り時間がマジであと10分なのでやめて関心領域(ROI)による合成をするだけクソ簡単プログラムで勘弁してくださいすいません!!

領域展開!!!

f:id:WMMCsaiteihen:20201214164121j:image

コードはこんな感じです、!

(すいませんあと数分なのでスクショです)

f:id:WMMCsaiteihen:20201214235713j:image

f:id:WMMCsaiteihen:20201214235723j:image

f:id:WMMCsaiteihen:20201214235745j:image

f:id:WMMCsaiteihen:20201214235755j:image

f:id:WMMCsaiteihen:20201214235804j:image

f:id:WMMCsaiteihen:20201214235813j:image

f:id:WMMCsaiteihen:20201214235821j:image

f:id:WMMCsaiteihen:20201214235831j:image

f:id:WMMCsaiteihen:20201214235839j:image

うぃーあと1分!!!

結果だけどうぞ!

(結論から申し上げると、コンプラ意識に負けたので先程挙げた内の2枚に関しては不快な思いをさせることも考えて公開しません。まぁほぼ同じような結果になったとだけお伝えします(ヤるだけやったんだ俺は))

 

f:id:WMMCsaiteihen:20201214175409j:image

f:id:WMMCsaiteihen:20201214175412j:image

ドガァァァアン!!!!!!!!はっはっはーーーーなんて爽快なんだー!!!!……

?ふぅーぅーー!!!!!!!

 

…。

なんだ…?心のどこかに寂しさと虚無が…あぁ…これが…賢者タイム…(絶頂)

そうか…他人を引き摺り下ろしたら今度は自分が幸せになって見下してやらないとすっきりしねぇんだ…俺って人間は…

 

5.彼女とLINEしよっ?

さて突然ですが(切り替えの速さ)

この虚無さと心の寂しさを埋めるため、ブログ公開までの残り6時間で彼女とのLINEを実装してみます。

なぜいきなりLINEなのか。と思われる方がいらっしゃると思うので理由を説明します。

普段、日常を生きているとLINEというツールをよく使うと思います。僕の場合、通知は来るもののこんな有様です

f:id:WMMCsaiteihen:20201212154337j:image

毎回毎回、通知が来てはワクワクしてLINEを開き、広告を突きつけられるこの虚無、あたいもう耐えらんない!!!返事をしろ!!

 

6.さぁ、彼女(bot)を作ろう

 Googl Apps Script(二つ名:Gorigori Anal Sex)を使います。言語はJavaScriptですが、

基本的なプログラミングができる人なら大丈夫でしょう。非同期処理などはやりませんから簡単なものだけで完結します。

基本的な流れは

①チャンネル作成(公式アカウントを作成)

API_keyを取得

②GAS上でプログラムを書く←ここにAPI_key入れ込む

③webhook経由でサービス作成と公開

 

一般的にAPIを使うのはこの流れです。

APIって便利ですよね。

いきなり宣伝ですが、obnizというモジュールをご存知でしょうか。人生でやったことないけど電子工作始めようかなって人がいきなり流行りのIOTを始めたい時に非常にオススメです。簡単にプログラミングと電子回路の勉強が出来るのも推しポイントです。

基本的なライブラリにくわえ、機械学習のライブラリなどもあって簡単なものから高度なレベルのモノ作りが可能となっております。

obnizによる作品紹介も多数ホームページにありますからこちらから覗いてみてください。

加速度センサの傾きでWebの要素を傾ける - blog.obniz.com

APIの使い方の他の例は

M5StickC+Yun Hatで作る簡単お天気ガジェット - blog.obniz.com

(ちゃっかりですが僕がこれ書いてます)

 

さて、話を戻します。

 

①チャンネル作成(公式アカウントを作成)

まず、LINE Developper を開き、"Messenger API"を開きます。

そこで、流れに沿ってアカウントを作っていきます。

Channel Icon→ LINEのトプ画になる部分

Channel name→LINEの名前の部分

を決めておきます。

f:id:WMMCsaiteihen:20201213215048j:image

普通設定に進み、

f:id:WMMCsaiteihen:20201213215532j:image

上図のクリックを押して、以下のように設定します。

f:id:WMMCsaiteihen:20201213215650j:image

そして、アクセストークン(API_KEY)が以下のような部分にあるので、コピペして保存しておきます。この部分はURLみたいなもので、これをプログラムに貼り付けることでプログラムとLINEをくっつけることができます。

f:id:WMMCsaiteihen:20201213215716j:image

 

 

②GAS上でプログラムを書く

GASで以下のコードを書きます。

ここではとりあえず発言をそのまま返すコードを書いておきます。API_KEYの変数に先程コピペした部分を代入しておいてください。

 

const API_KEY = '/*ここにAPI_KEYに代入しておく*/'

function doPost(e){

 var replyToken =                            JSON.parse(e.postData.contents).events[0].replyToken; //リプライトーク

var userMessage = JSON.parse(e.postData.contents).events[0].message.text; //返信

var url = 'https://api.line.me/v2/bot/message/reply'; var headers = {

'Content-Type': 'application/json;

charset=UTF-8' ,

'Authorization': 'Bearer ' +API_KEY };

var payload = JSON.stringify({

'replyToken': replyToken ,

'messages': [{

'type': 'text' ,

'text': userMessage

}] } )

var configs = {

'headers' : headers ,

'method' : 'post' ,

'payload' : payload

};

UrlFetchApp.fetch(url ,configs)

}

書いたら、

f:id:WMMCsaiteihen:20201213223924j:image

上図の部分をクリイクして

f:id:WMMCsaiteihen:20201213224003j:image

この設定にしておきましょう。ここで、この

URLの部分を取得しに行きましょう。

 

③webhook経由でサービス作成と公開

f:id:WMMCsaiteihen:20201213215904j:image

LINE Developperでwebhookの利用をONにして

URLを保存しておきましょう。これを先程のURLの部分に貼り付けておきます。

さぁ、GASのウェブアプリケーションを公開し終え、LINE Developperの設定保存したら念願のLINEの開始です!!

 

f:id:WMMCsaiteihen:20201213183023p:image

こんな感じで作者JGの彼女bot完成です…感動!!初彼女!!わーい🙌

さぁ、話しかけてみましょう。僕の彼女に!ドゥフドゥフッッ///美波つぁ〜ん!

そのまま言葉をオウム返しするのでは人間味がないので一部プログラムを書き換えました。

一応出力結果はこんな感じです。

f:id:WMMCsaiteihen:20201213181705p:image

あぁ…返事が来てる…嬉しい…ニチャア😏

おい誰だ破局寸前のカップルの会話って言ったやつ出てこい。

 

おっと、キモオタニチャニチャフェイスをしてる場合ではないです。

これからは真のリア充としての矜持を持って生きていきたいですね。はぁい!

 

さぁて、皆さんの冷めた視線を感じつつも明日のAdvent calendarの予告でもしますか〜!

 

……

とはいきません!!!

AIネタでサプライズゲスト

登場です!

WMMC Advent calendarでは初めての同日2人目企画!!超絶レアキャラ!例のあの方がブログを書いてくださりました!

ここまで読んだ人だけがたどり着ける

 

秘密のリンクはこちら!

 

 

AIと機械学習などの区別、意外と曖昧にしてたかもしれないとハッとさせられましたね…

(ネタバレ控えのため細かい感想は略)

 

さて、そろそろ終わりにしましょう笑

本当の次回予告ですが、

明日は、

Sophiaさんの

 「タスク管理で頭の中をスッキリさせる話」

です。

blog リンクはこちら

どんな内容なのか、Sophiaさん節が効いてるのか(いい意味でとち狂ってるのか)楽しみです…

 

さて、皆さん良いクリスマスを〜!!

僕も彼女とのLINEを楽しんできます♪(虚無虚無フェイスの翁)

 

p.sこの彼女botはオウムガエシするモードに戻して公開しておきましたので使ってみてください。

 

参考文献

https://code-graffiti.com/blending-images-with-opencv-in-python/

https://towardsdatascience.com/object-detection-with-10-lines-of-code-d6cb4d86f606

Advent calendar revenge match in2020 (HAL+MPU9250)

これはMicro Mouse Advent Calendar 2020 - Adventarの2日目の記事です。 

昨日の記事は、なおフィスさんのMatlab/Simulinkでシミュレータ環境を作るコツ - なおフィスのブログでした。

当方はMATLABチュートリアルしかやってないのですがこんな便利機能あるとはしらなかっで今後の使用の際には参考にさせていただきます…

 

はじめましてジャッジーです。

今年は←まともに書いたので是非読んでいってください。

0.はじめのおしゃべり(飛ばしてどうぞ)

 昨年度12月にもマイクロマウスのAdvent calendarに呼ばせてもらったわけですが、

あの時ICM20689の実装などと題して"哺乳瓶でモンスターを飲むと不味くなる理由"について色々書きました。(は?)

結局ICM20689の実装は出来ずじまいでした(え?)

元々MPU6500での実装はsoraさんのブログ(STM32 + HALのSPIでMPU-6500と通信する | Sora's Activity Record)を見ながらやったことがあったので、同じInvensense社のICM20689はある程度のコピペで移植すれば実装は終わりだったのですが…授業が忙しくて結局それはやらないで終わりましたがね。ゆるさねぇぞ製図共々

          ↓

で、月日は流れて、今度こそは種類が違えど

ワイ「MPU9250を自分1人で実装までやりたいな〜(能天気顔)」

なんておこがましいことを思ってたんですよ(もちろん普通に無理ゲーだった)

 

で、まぁ少し詰まりつつも最終的に動かしたところに至るまでの流れを載せたいと思います。

ある程度Datasheetみたりは自分でやったりはしましたけども、

ハードウェアの注意点や生値の変換に際しては

しまじゃきさんやその他の先輩Nのお二方とお話ししてる中で教えてもらい、Soraさんのブログを一部参考にさせていただきました。感謝申し上げます。ありがとうございました。

 

そういえば、僕が最後にクラシックマウス関連のことをしたのがMPU6500の実装でした。フォルダみたら昨年の9月頃にMPU6500は完成してたみたいですね。もう一年以上も何もしないまま終わってました。(これ書いてるのは10月14日です)ははは。

 

実装に関してですが、今回大学でNucleo(STM32F401RE)を使う機会があったのでHALライブラリを用いて実装してみます。

f:id:WMMCsaiteihen:20201014035814j:image

1.使う物

・ジャンパー線♂♀

・ブレットボード

・ハンダゴテ(一部半田付けを行う)

・Nucleo(STM32F401RE)

・MPU9250ボード(千石にて購入)

MPU-9250搭載 IMUピッチ変換基板--在庫限り - スイッチサイエンス

 

2.SPI関して

  今回は昨年のAdvent calendarのリベンジなのでSPI通信での実装を予定してます。

SPI通信でマイコンペリフェラル間を繋ぐには

以下の配線が必要です。

f:id:WMMCsaiteihen:20201013192209j:image

MISOとMOSI、などの不思議な単語が並んでいますね。

MはMaster、SはSlave、 I&OはInput&Output

の頭文字ですね。最近はこの表現も問題視されて避けられるようですが、不便なので今回は使います。

各線の説明は以下のようなものです。

 

MISO:スレイブ(センサー)側からマスター(マイコン)へのデータを送信する線

MISOピンはSDOピンとも呼ばれる。

 

MOSI:マスター(マイコン)側からスレイブ(センサー)へのデータを送信する線

MOSIピンはSDIピンとも呼ばれる

 

CS:チップセレクター(スレイブ選択用)

どのセンサーと通信するか、を決めるピンです。上の図では省かれてますが、

SPI通信ではmaster1つに対してスレイブ側は複数使うことができ、以下のような配線になることがあります。

f:id:WMMCsaiteihen:20201013193945j:image

master側から見るとどのセンサーと通信すればいいのかわからないので、CSピンでどれにするかを決めるのです。

そしてCSピンですが、基本SPIの時は負論理です。

(つまり、通信する時以外は常にHighにしないといけない)

 

SCLK:通信タイミングを図る時計の役割です。

立ち上がりの時に通信するのか、それとも立ち下がりの時に通信するのか、などの設定が必要です。以下のCPOL、CPHAと言ったパラメータの設定を行うことでこれらの設定が可能となっております。

f:id:WMMCsaiteihen:20201013191208j:image

 

これで最低限のSPIの説明は大丈夫でしょう。

以上の画像の引用には以下のサイトから引用いたしました。

https://www.digikey.com/en/maker/projects/getting-started-with-stm32-how-to-use-spi/09eab3dfe74c4d0391aaaa99b0a8ee17

(2020年10月9日現在)

 

3.MPU9250に関して

 MPUシリーズはInvensense社から出ているIMUセンサーです。非常に多くの業界シェアを出していましたが今現在は製造廃止になってしまい、入手するには残された在庫のものを取り寄せる必要があります。(多分)

代わりに同じInvensense社から出ているICMシリーズが出ています。使い方もMPUシリーズと同じように使えるので今回書いたプログラムは移植性が高いですね。

まずはMPU9250のDatasheetを見てみます。

今回の実装に必要な

設定すること

必要なMPU9250レジスタ

 

を調べます。

Datasheetにはこちらのもの(https://invensense.tdk.com/wp-content/uploads/2015/02/PS-MPU-9250A-01-v1.1.pdf)を使いました。

以下にページ数とその画面を表示しながら何を読み取ったかを書いていくのでご一緒していただけると幸いです。(ここ以外にも読んでもらう必要はありますが、最低限の部分だけはここに載せておきます)

 

[p.5〜6]

まずp.5かp.6を開いてください

僕は英弱なのでp.5のことは軽く読んで

p.6のこちらで黄色の部分の確認をしました。

f:id:WMMCsaiteihen:20201014024620j:image

ここからわかることは

  • VDDには2.4〜3.6vを入れればよい
  • 1MHzなら全てのレジスタと会話できる

 

です。

 

[p.19]

次に19ページの使うピンのところを確認します

f:id:WMMCsaiteihen:20201014025018j:image

こちらですね。

黄色線で書いたところが今回必要なところです。

読み取ったこととして

  • ADO/SDO→MISO
  •  FSYNC→GND(僕これやり忘れてたんですけどうまくいきましたははは)
  • VDDに電源いれゆ
  • nCS→前述の CSピン
  • SCLK→前述のクロック用の線
  • SDA/SDI→前述のMOSI

 

でした。

 

[p.16]

では次に少し戻って16ページです。

f:id:WMMCsaiteihen:20201014030302j:image

これが今回の通信タイミングチャートです。

上のSCLKの説明の際、CPOLとかCPHAって言う単語を出したと思うんですが、その設定が読み取れます。上で挙げた例と見比べてみるとわかります。

ここから読み取れたこととして

  • 通信の際は CSピンはLow
  •  CPOL=1
  • CPHA=0(ただし2回目のedge時に通信)

 

が読み取れます。

 

[p.36]

最後に36ページに到達

f:id:WMMCsaiteihen:20201014030908j:image

こちらで読み取れることとしては

soraさんのブログと同様に

  • MSBが最初
  • 通信は16クロック
  • 読み取りか書き取りを決めるのは先頭の数字であり、0なら読み取り、1なら書き込み
  • その後の7bit分の数字で通信するレジスタのアドレスを示す

 

ということです。

これらの読み取ったことをきっちり設定すれば動くことがわかりました。

 

ここで、datasheetは一旦置いて、

register map(https://invensense.tdk.com/wp-content/uploads/2015/02/RM-MPU-9250A-00-v1.6.pdf)を覗きにいきましょう。

 

さて、レジスタマップを開けましたか?

さぁ見ていきましょう。ここから先は真っ暗で何も見えないですがね…(訳:マジで何もわからないまま進む)

と、言いつつここまで書いて疲れてきたのでザーッと見ていきましょう。

まず全体のレジスタマップで今回見るレジスタアドレスの部分を確認します

黄色の部分が今回必要なレジスタです。

面倒なので加速センサーについては端折ります。ジャイロセンサーのみやってみます。

f:id:WMMCsaiteihen:20201014034724j:image

f:id:WMMCsaiteihen:20201014034741j:image

f:id:WMMCsaiteihen:20201014034800j:image

 

[117. WHO_AM_I]

f:id:WMMCsaiteihen:20201014165213j:image

これがWHO_AM_Iのレジスタです。

これの用途は

This register is used to verify the identity of the devise.

と書かれています。つまり、通信しているスレイブがMPU9250であることを確認できる便利なレジスタです。

続きを読んでみると通信できていれば0x71という数字が返ってくる、ということを示しています。

読み取れたこととしては

  • レジスタ番号117(16進数で0x75)にアクセスして、返ってくる値が0x71なら通信できている

 

[26.CONFIG]

f:id:WMMCsaiteihen:20201014170959j:image

f:id:WMMCsaiteihen:20201014171010p:image

ページを跨いだので少しみにくいですが許してください…

これで設定するのはFIFO_MODEの設定です。

それ以外は0にしておけばいいんですが。

FIFO(メモリの一種)に関しては記載の通り追加のデータが来たら上書きしたいので0にします。

つまり0x00を書き込みます。

通常、FIFOは上書きを許可してない場合は

書き込もうとしても書き込むことすら不可能となります。

余談ですが、読み出しをやめるとその後書き込まない限り読み出す値は止める前のものになるんですが、僕の不勉強もあり、説明できないのでその辺の話はFIFOで調べてください。

 

読み取れることとして

  • レジスタ26(16進数で0x1A)にて、FIFOのデータ上書きするには0x00を書き込む

 

[27.GYRO_CONFIG]

f:id:WMMCsaiteihen:20201014171558j:image

ここでは、ジャイロの毎秒測れる角度範囲を指定するために3と4bit目を主に触ります。

今回は最高の2000dps(degree per second)のレンジに設定するため、

00011000→0x18をこのレジスタに書き込むことにします。

ちなみに、ここでどのレンジを選んだかによって、帰ってきた生値に対して行う処理が異なります。

これはレジスタマップよりDatasheetを見た方が手っ取り早いのでDatasheetの8ページをご覧ください。

以下の表が出てきます。

f:id:WMMCsaiteihen:20201014193229j:image

250→500→1000→2000と書いてある部分の下に

131→65.5→32.8→16.4

とかかれています。

これが変換に用いる値です。

 

今回は2000dpsを選択したので対応する16.4を使います。

角度=得られた生値/16.4

の変換式 で角度に変換します。

(この式が公式の書類では全然見つからない)

 

話は飛びましたが

  • GYRO_CONFIGには0x18を書き込む
  • 変換式にはDatasheetの8ページの値で除す

 

です。

 

[PWR_MGMT_1]

f:id:WMMCsaiteihen:20201014172121j:image

これは電源系統です。言葉の通り

パワーマネジメントですからね笑

ここでは下位の3bitでの設定を行い、

20MHzの内部クロックをオンにしておきます。

これ以外は使わないのGYRO_STANDBYは使うのかな…わからん(ので知見がある方は教えてください)

従って、

 

と言うことがわかりました。

ここまで長々とDatasheetやらRegister mapを追ってきました。

さてようやく設定することもわかりましたし

本格的な実装に参ります。

 

4.実装編

長ぇ…歴代で一番長いブログですねこれ。

さて、まずはハードウェアの準備から行きましょう。

4.1実装(ハード)

ハードウェアとしてはまず電源ラインがきちんと定格内であることがまず確認するべきことです。

今回はSTMマイコンを使いますので3.3V電源線があります。ここからVDDを持ってきましょう。

以下にNucleo(F401RE)

の中で今回使う部分のピンを示します。f:id:WMMCsaiteihen:20201014195329j:image

黄色の枠のところが今回使う部分です。

ほとんど全ての配線がここの枠内で完結します。

こちらが今回のMPU9250ボードです。配線は画像の通りの感じです。

青色のボードを使ってる人も多いですが、僕は赤色のでやります。

ここが最大の沼ポイントです

f:id:WMMCsaiteihen:20201014195414j:image

上の基板上の緑枠の部分、はんだ付けがなされてるんですが、ここのはんだ付けを切り替えておく必要があります。

よくわからないと思うので販売会社が出してる配線図を以下に示します。

https://cdn.sparkfun.com/datasheets/Sensors/IMU/SparkFun_MPU-9250_Breakout.pdf

 

f:id:WMMCsaiteihen:20201014195835j:image

上の赤丸。そうこいつ。

気づくわけもないがここの部分が示しているのは

  • ここのはんだ付けを反対側にくっつかないとSPIできないよー!

と言うもの。

声を大にしていいたい。

 

でかく書いておけバカ

 

はい。ここをはんだ付けしないとi2c通信しかできません。大事なことなのでもう一度言いますが

ここに気づかないと永遠にi2cしかされません。ここが沼です。底無し沼。

この記事を見た(ここまで読む暇人がいるのか?)人はどうか助かってほしい。

ここのはんだ付けさえ終われば以下のように配線してください。

 

f:id:WMMCsaiteihen:20201014200242j:image

 

これでハードウェアは終わりです。

画像には載せなかったですが、

回路にパスコンは入れておくべきでしょう。

最近の素子は精度の良いものが多く、パスコンを入れなくても誤動作やら発振やらしないものが多いですが、念のため入れておくといいです。(という受け売り)

 

電源はNucleoにプログラムを書き込むときにどうせパソコンとNucleoを繋ぐのでUSB経由でパソコン給電します。

 

4.2実装(ソフトウェア編)

長ぇ…がここさえ終わればあとは試してガッテン!です。(もしかして古い?)

もう疲れたんで、 Cube IDEの導入は言及しません…軽くこれの説明すると、STMマイコンへのプログラムを書くための便利ツールが丸ごと詰まったエディタです。

検索エディタでCube IDEで検索してみてください。

すぐST社の英語表記のホームページが出てくるのでそこでインストールできます。

また、シリアル通信画面を使うためにTeratermもインストールしておいてください。

 

さて、ここからはCube IDEがインストールできた人向けです。

まず、「プロジェクト」を作成し、ピン設定します。

 

ピン設定:

Cube IDEではピンの設定がGUIでできます。

レジスタ手打ち(GPIOA→…等)の構造体の中身を触ることなくピン設定できるのは人生の時間損失を10時間以上狭めます。(データシート見てたらマジで永遠にかかる)

f:id:WMMCsaiteihen:20201015112726j:image

GUIで右上の3ピンをそれぞれSPI3の

MOSI、MISO、SCLKにします。

それ以外に CSピンを設定します。

実際に触ってた人の中にはCSピン専用のピンがあることに気づいた人がいるかもしれません。あちゃ〜申し訳ないですがGPIO_outputに設定してもらえると助かります。

覚えていますか? CSピンは負論理で、Lowの時SPI通信が始まるって言う話がありましたよね?

GPIO_outputの方がLowにしやすくて簡単なのでCSピンとして使います。GPIOがわからない人がいたらアレなんで簡単に言っておくと

出力と入力のピンです。

 

あと、今回は角度の情報をシリアル通信してみたいのでUSART2用のピンが緑色(オンに)なってることを確認しておいてください。

 

さて次にそれぞれの詳細設定をしましょう。

ここでつまずく人は多いです。当の僕もよくわからんまま設定してます。

 

さぁ、始めましょう。

 

(1) SPI3の設定

まずは Clock Configilationを覗きに行きます。理由はSPI3に入るクロック周波数を知るためです。覚えていらっしゃらないかもしれないですが、MPU9250の全てのレジスタとお話しするには10MHzで通信する必要がありました。クロックの立ち上がり、立ち下がりに合わせて通信を行いますから、供給クロックは調べないとダメです。これを満たすためにどのようなプリスケーラー(分周)を与えれば良いのかを確認しに行きます。

__HAL_RCC_SPI_MspInitによれば、SPI3に供給するクロックはAPB1によるものですから

(↓これ見て分かった)

f:id:WMMCsaiteihen:20201015115034j:image
f:id:WMMCsaiteihen:20201015115031j:image

 

Clock Configilationの中でAPB1のクロック周波数を調べます。

すると42MHzと表記されていますね。

つまり、10MHzにするにはプリスケーラー(分周)を4に設定すれば大体10MHzです。(僕はお試し動作確認だったので16にしました)

出来るだけ早く通信したいのでやや無理やり10MHzを超えた値にしていますが、確実に動作させたいのでプリスケーラー(分周)を16にしてました。これであとは実際に設定するだけです。

設定場所として、 Connectivility→ SPI3と進んでいただき、parameter settingを選びます。以下の画像のように設定を進めます。

f:id:WMMCsaiteihen:20201015112708j:image

まず一番上の部分ですが、

Full duplex masterと設定します。

Full duplex とHalf duplexがありますが、何が違うのでしょう。

これは通信に使う線の本数です。今回、送信と受信に1本ずつ、計2本の通信線を用意してます。このように送信、受信に1本ずつ通信線が設けられている時はFull duplex です。

送受信まとめて1本の時はHalf duplexです。

追記:(と言う解釈をしてたのですがどうやら間違いのようでした)(2020,12/01)

 

その次のHardware NSS Signalはdisableに設定します。(今回ソフトウェアで CSピンをLowにするので)

MPU9250のデータはMSB firstでした。こちらはデフォルトで設定されてるはずですが確認しておきましょう。

プリスケーラーを4or16に設定し、

先述した CPOLとCPHAの設定です。

だいぶ上の方で説明したので忘れてる人もいるかと思いますが、

 CPOL→High

CPHA→2 Edge

に設定してください。なんでこの設定になったかは上の方で説明したので省きます。

多分後の残りはデフォルト設定でOKなので放置です。

 

(2)USART2の設定

次にUSART2の設定です。USART2もconnectivity→USART2で設定箇所に飛べます。

USART2で設定するべきはbaud rateですね。

僕はTeratermのデフォルト設定が115200なので今回も115200に定めます。

f:id:WMMCsaiteihen:20201015115347j:image

注)Teratermのデフォルトbaud rate設定は9600なので通信すると文字化けします。

設定を変えるには上のバーの中で設定→シリアルポートで変更できます。

f:id:WMMCsaiteihen:20201015113723j:image

f:id:WMMCsaiteihen:20201015113726j:image

 

USART2に関してはこれで設定自体は終わりです。簡単ですね。

 

コーディング:

基本的なコードはSoraさんのもの(STM32 + HALのSPIでMPU-6500と通信する | Sora's Activity Record)と同じでした。

勉強のためにほぼ見ないで書いたんですけどCSピンをLowにする処理の位置が違うこととか、HAL_Delayを入れてるか否か程度の違いでしたので(あと僕のは加速度系への書き込みとかがある)ソースコードは載せません。

Soraさんのものを見ていただければとりあえずよろしいかと思います。

もしそのうち気が向いたら追記という形で載せるかもです。

 

結果

コンパイルして書き込んでやると、

Teraterm上で左右に振った時の加速度が検知できました。

f:id:WMMCsaiteihen:20201130042252j:image

 

 

長々と書きましたが

明日は…明日は…?誰もいなぃ…虚無…もぅむり…リスカして死のぅ…

 

 

開催の辞〜卍USBのお勉強卍〜

この記事は

WMMC Advent calendar 2020 の1日目の記事です。

 

当方は素人で、内容についての厳密性などが欠けていることがありますのでご了承ください。

一応ためになるケーブルとコネクタの話 USB編 - Qiita

こちらのブログに合わせた表記をするようにはしております。

また、そんなに深いところまでやらないので。ご了承ください。

 

0.開催の辞

皆様ご無沙汰しております。

今年、突然感染症が世界を大きく変えました。開催される予定だった日本オリンピックは延期、経済への大ダメージ、医療関係者の悲鳴が常に聞こえる、そんな年でした。皆様方も新型コロナウイルスの影響で大変な状況となっていらっしゃることと存じ心よりお見舞い申し上げます。 

 

さて話はサークルの方に移るんですが、僕は昨年度からあまりサークルに顔を出してなかったのですが、最後にこう言う形でサークルのイベントを僕から提案、企画させていただいた次第です。

まぁこの calendarには多分複数回ところどころに僕が頻出すると思うんですが、後輩を中心に好きなことについて書いてもらいつつ、外部の皆様と親交を深めていって欲しいな〜って思います。

では、これからの25日間、部員の皆様には年末のお忙しい中申し訳ないですがブログの方何卒よろしくお願いします

 

1.まずはじめに

で、初回なので少しお堅めにブログを書くことにして USBについての記事でも書きます。

大事なことなのでもう一度言いますめう。お堅く書きますハメ。(コンプラ意識の低さ)

 

話の発端は先日、あまり大声で言えませんが

けんきうしつのお高いデバイスのUSB端子部分を破損し、大いに反省しつつも償いのつもりでUSB端子の修理をしておりました…

その際、USB端子の議論が出たのでその時のお話です。

p.s 修理はできませんでした。🙇‍♂️(ここテストに出るぞ)

 

とまぁ、USBケーブルって日常的によく使いますよね。

iPhoneの充電など、生活にかかせません。

そんな身近なUSBだからこそ、すこし理解を深めておくことは損ではないです。よね?

 

1.1 USBとは?

USBとはコンピュータとその周辺機器を繋ぐための統一規格のことです。

昔は周辺機器(以後ペリフェラル)毎に特定のコネクタを繋ぐ必要がありましたがそれは不便です。だからこそ、この規格が完成し、ここまでの汎用性を有するようになったのです。

USBについてですが、ちなむと今現在流通しているものは

USB-2.0かUSB3.0かUSB-3.1、USB-3.2のあたりでしょう…多分。(ちなむとUSB-3.1はGen1

とGen2で違う種類となっております)

 

このUSBにくっついてる数字は規格バージョンのことです。バージョンが新しいものほど通信速度が速く、また給電電流が増加しています。

例としてUSB-3.0を挙げると、

USB-3.0は通信速度が5Gbpsであり、2.0の10倍早い通信速度となっています。また、供給電流も1Aに近く、2.0の約2倍までに増加しています。

USB-3.xの簡単な見分け方として、

USB端子の断面が青いものは3.xであるらしいです。

他にも

下図のように端子にあるマークでも分類が可能であるらしいです。

f:id:WMMCsaiteihen:20201130001558j:image

(引用:『USB』の違いってなに? Type-C、micro USB、USB3.0など各ケーブルと対応機種は…|TIME&SPACE by KDDI)(2020,11/29現在)

 

以上のような分類ができるとのことですが、中には上のような特徴がないものもあり、最終的な確認には仕様書を読んでいただきたいです。

機会があればお家にあるUSB端子の断面を是非とも見てみてほしいですね〜。

 

1.2USB端子の種類

f:id:WMMCsaiteihen:20201129234533j:image

(引用:今更聞けない基礎知識・USBの種類とは?|テックウインド株式会社) (2020,11/29現在)

 

えっちなオス♂コネクタち○ぽですね〜じゃなくて、えっと、なんだっけ。(すっとぼけ)

まぁとりあえず正直どれがどうとか言うのが面倒なので上の画像を見ながらある程度把握していってください。はい。

まず基本的に断面形状が長方形のものをType-A、正方形なものをType-B、楕円のものをType-Cといいます。一般男性のものをTi※poといいます。

そして大きさによっても冠言葉が変わります。

一番よく目にするもの(定性、定量的ではないですが筆者的には世間で一番スタンダードなものと認知しています)のサイズを標準とすれば

すこし小さいものをminiシリーズ、さらに小さいものをmicroシリーズと呼びます。

 

micro-Ti※poは太った男性に多いイメージ(偏見)があります()

 

1.3.USBの線って何なの?

USBの中身って意識することがないですよね。

そもそも知ろうとも思わないかもしれません。

 

先述したようにUSBにはバージョンがあり、

3.xには線がいっぱいあります。しかし僕がよくわかってないのでこちらに関しては調べてもらえると幸いです。

基本的にピンアサイン4本バージョンとピンアサイン5本バージョンのあるUSB-2.0だけしかあんまりよくわかってないです。はい。

詳しいことは調べてください。

 

USB-2.0端子(4本ver)

はピンアサインとして

  1. 5V
  2. GND(SG)
  3. D+
  4. D-

 

があります。5VピンとGNDはそのままの意味で、

D+とD-は通信線です。

決してレポートの評価ではないです。逆にその場合落単っていう嵐を呼びます🥺

f:id:WMMCsaiteihen:20201130040438j:image

 

USB-2.0端子(5本ver)

はピンアサインとして

  1. 5V
  2. GND(SG)
  3. D+
  4. D-
  5. IDピン

があります。

ん…ED?あ、それはErectile Dysfunction.

 

ちゃうちゃうIDピンです。

いやマジでなにこれって感じ。

簡潔に言うと、

これはGNDに落とすかフロートにする(要するにNC)ことでホストとペリフェラルを判別できるようにするピンです。

例えを上げてみましょう。

iPhoneを考えてみます。

iPhoneをUSB経由でパソコンに繋ぐと

iPhoneがペリフェラルになってデータを

パソコン(ホスト)で読み取ることができます。

 

逆にiPhoneをホストにしてUSBでマウスやキーボード(ペリフェラル)を接続することも考えられます。

 

このiPhone

①ホストにするのか?

②ペリフェラルとして使うのか?

を切り替えをするためには適切なケーブルを選んで使う必要があります。そのためにIDピンが必要なのです。

このIDピンによる切り替えをOn the go (OTG)と呼び(決してOtin Tin Ginginではない)、

iPhoneをホストにするためにはこのOTGのケーブルを用意する必要があります。(もう既におちん○んギンギンケーブルと心の中で読んでしまってたそこのあなた!こっちサイドに堕ちてますナカーマ!)

OTGケーブルとそのほかのケーブルの差、

それこそIDピンがフロートかGNDか

と言うことのようです。SPI通信のNSピンみたいなものですかね?

ちなむとOTGケーブルだとIDピンはGNDと導通してます。

USB-2.0のピンアサインはこんなもんです。

 

要するに適当にUSB選んでたらやりたいことができない可能性があるってことです。

 

OTGケーブルについては

USBホストケーブル(OTGケーブル)について | ゆゆぶろぐ

で調べました。

 

んで、オス♂メス♀でのピンアサインを混同しがちなので備忘録として載せておきます。調べた時に出てきたものの中でもここらがわかりやすかったですね…

すげえどうでもいいんすけどオスメス表記がこの「なんでも!セクハラ大作戦!!」決行中の社会で生き残っているの、それってキセキ♪(年齢がバレる)なんじゃないかなって最近思います。えっち。

 

f:id:WMMCsaiteihen:20201130005340j:image
f:id:WMMCsaiteihen:20201130005336j:image

画像引用:USBコネクタ ピン配置 (ピンアサイン) ケーブル色|ぴーしーとこうさく

(2020,11/29現在)

 

f:id:WMMCsaiteihen:20201130005035j:image

↑Type-Cのオス(wiki参照)

f:id:WMMCsaiteihen:20201130005040j:image

↑Type-Cのメス(wiki参照)

 

PCB設計で個人的に一番よく見るやつ↓

microUSB-b

オスの方だけでも載せておきます。

f:id:WMMCsaiteihen:20201130235155j:image

(上図は僕が作成したので保存、乱用していただいて構いません)

通信線の注意ですが、

D+はD+と、D-はD-同士を繋ぎます。

UARTのTX、RXの知識を得ていると違和感を覚えます…

 

 

ここまでUSBについて素人がごちゃごちゃ言ってきましたが、

正確で詳しいことを知りたい方は

現代PCの基礎知識(7):仕様書を紐解くとわかる―本当はややこしいUSB | Think IT(シンクイット)

 

こちらを参照していただけると幸いです。

 

2.本題

で、先日プリント基板(以後PCB)にmicro-USB-Type B

をはんだ付けすることがありまして…()

 

その時、このコネクタの強度を上げるためにはどうすればいいのかを考えました。

そこで、このようなことを考えました。

 

"USBのメスコネクタのケース(FG)をPCBと無理やりはんだ付けして固定させる"

 

でも、FG(フレームグラウンド)とSG(シグナルグラウンド)をくっつけていいものか…

と考えました。FGとSGについて、よくわからないひとは検索してみてください。

 

調べてみるとUSBの規格書には指定は書いてないようで、設計者は状況に応じて落とし方を工夫していました。結局正解はないと言うことがネットから得られたんですが、落とし方については面白かったのでいかに少し紹介します。

 

①フロート

FGとSGをくっつけることでFGのインピーダンスが低かった場合、そこからノイズが入ってしまい、ノイズがSGに伝わったりするようです。

これを防ぐためにフロートにしてあることがあります。

あとはまぁ感電防止の役割もあるようです。

コモンノードノイズなども考えられます。

 

ただし、この場合にはフロートだと空気のインピーダンスが大きいためノイズの低減までに時間がかかると言う場面もあるようです。

 

②FGから1〜10pFのコンデンサを介してSGに落とす 

 

音響などの音質改善のためにFGとSGの間にコンデンサを入れることで周波数特性を改善できるようです。

また、ノイズエネルギーがコンデンサに吸収されて低減するという意見も存在しました。

 

③FGから抵抗を介してSGに落とす

FGからのノイズの影響をPCBに与えない効果

があるようです。

詳しいことはわかりませんが、基板のキャパシタンスと抵抗によるフィルター回路がノイズの低減に貢献していると言う考えがあるようです。

 

④普通に繋ぐ

これはSGとFGを繋いじゃうようです。

一点設地にするかしないかも設計者によって異なるようです。

繋ぐと、金属フレームがシールドとなって動作が安定することもある?ようです(よく分からんかった)

 

結論

むやみに設計者の意図を踏みにじらず、グルーガンなどで強度を強くするのが正解なのかもしれません。また、自分が基板を設計するときは

その場に応じて変更していく必要がありそうです。作ってみてノイジーなら変えてみる可能性を少し脳内に残しておくといいのかもしれませんね。

↓こんな言葉もネットにはありましたし。

f:id:WMMCsaiteihen:20201130025632j:image

 

余談ですが下の画像のこちらのやつ(FT−232RQ USBシリアル変換モジュール: 半導体 秋月電子通商-電子部品・ネット通販)でFGとSGを導通させてもマイコンへの書き込みとかになんら動作に影響はなかったです。

f:id:WMMCsaiteihen:20201130235933j:image

(このコネクタ、逆接めっちゃしやすいんすよね。だからきちんと接続先に逆接対策もしておかないとダメっすね。ただ、逆接対策してるからといって逆接してもいいわけではないっす。先日同期が逆接しても大丈夫って後輩に教えてたのですが逆接しないに越したことないぞ。一応。)

 

3.最後に

長々と書いてしまいましたねははは。

 

明日はsophiaさんの記事で

「もしクラシックマウスから車のエンジン音がしたら」です。

遅いマウスから爆音聞こえた時の無駄な割り込み感のシュールさやばそうですね笑

 

ブログリンクはこちらです

sophiaの書

 

是非ともお楽しみに!