Hello legacy codes!

Intro

When being an engineer longer than one year, having experiences to handle code written by other people is a common issue. With any luck, when handover, well-documented specifications and senior members would help you get over any challenge in the situation.

I'm Tetsu, the Akerun Android team member. Today, let's talk about the unlucky situation and how I faced (and fixed!) it at Photosynth.

Overview

  • Why need to face legacy code?
  • How to handle it?
  • Finally fixed!

Why need to face legacy code?

"Hey, the code is so dirty, let's do refactoring!" or "No, it's impossible to refactor it, making a new one is easier." These kinds of conversations are common for engineers, but why do we need to tackle it? just for code quality?

My answer, the legacy code has provided values to users already-- and maybe from now on. But the legacy code brings challenges to engineers when we want to deliver more values quickly. So we need to consider how to face it. This answer sounds common? However we must tackle it anyway. ;p

(I also recommend a video talking about the importance of having "why" questions in our job. I hope this would worth to take your time) www.ted.com

How to handle it?

Now we confirmed the reason why we need to tackle a legacy code. The next step---we have to sort out the current situation. I would like to show an example at Akerun Android:

  • We have a project to improve the Akerun app's UI/UX.
  • Having not so much time to do code refactoring.
  • No architecture policy and full of smelly code.

Hmm... I want to show an ideal case first, and escape from the real world... Here is an architecture diagram in Akerun Android we want to have. f:id:photosynth-inc:20201222102745p:plain

This looks perfect!

Usually, we choose the domain layer (user story, business logic) or frequently feature (like account register/login) first if no exception in refactoring. But in our case, UI/UX improvement is the most important task we want to deliver to users, and refactoring the domain layer is not the better way with limited time.

Now, back to the real world, we consider a “plan B”, which does not aim to refactor all things at once, but focus on refactoring the UI/UX improvement tasks only.

Finally fixed!

Here is an overview of the “plan B” (which we have actually done): f:id:photosynth-inc:20201222102812p:plain We focused on the UI/UX tasks and refactored it to multiple feature-modules and a UI-component-module without changing almost all domain & data layers. It was unsophisticated yet and was not ideal. But it became better, huh?

Outline the actions:

  • Draw a blueprint that your team want to realize
  • Check the blueprint if it fits your objective
  • Keep enough buffer for unexpected incidents

Hope this article will provide you with any ideas when facing legacy code.

Thanks for your time!

By the way, we always welcome our new colleagues!~ hrmos.co

Please join us and let's innovate peoples’ lifestyle together.

P.S. For the limited time issue, another important part is to secure additional time to improve the team's overall working efficiency.

As examples, we did in the past year:

  • Use the CircleCI tool to run unit tests.
  • Add DeployGate Gradle task to distribute binary automatically.
  • Use Danger + Klint to improve code quality without human review.
  • Make a reusable UI component to keep UI/UX’s same behavior.

This makes our work quickly/easier and we can focus on more challenging tasks.

UICollectionView vs UITableView

この記事は Akerun Advent Calendar 2020 - Qiita の21日目の記事です。

Webエンジニアのbeginer_rider - Qiitaと申します。 主にiOSアプリ開発を担当としています。

はじめ

iOS開発者の皆さんにはよくある話と思いますが、リスト画面を作るときに、UICollectionViewとUITableViewのいずれを検討することがあったと思います。 リストの要素数、セルの色や表示名を動的に変更する中でどれがよいか、悩んだ方も多いのではないでしょうか。 そんな方々に少しでも助けになればと思い、UICollectionViewとUITabeViewのそれぞれのメリデメをご紹介させていただきます。 プチ読み物的なものとしてご一読ください。 ※あくまで個人的観点でのメリデメとなりますので、気になった方がいらっしゃればご指摘いただけますと幸いです。

UIColletionViewのメリデメ

メリット

UICollectionViewLayoutを利用することで、セルのレイアウトを変更することが可能

prepareメソッドをoverrideすることで、セルのレイアウトを変更することができます。 UICollectionViewLayoutのサブクラス、UICollectionViewFlowLayoutにはitemSizesectionInsetなど、セルのUIを変更するのに役立つ様々なプロパティを備えています。 加えて、セルだけでなくHeaderFooterのレイアウトを変更することができます。

また、他にもUICollectionViewFlowLayoutだけでなく、UICollectionViewLayoutAttributesUICollectionViewLayoutInvalidationContextなどのレイアウトを調整するためのクラスが用意されています。 そのため、柔軟にレイアウトを組むことができます。(1行ごとに表示する要素を変えるなど)

アニメーションのあるセルの挿入や削除を行うことができる

performBatchUpdateクロージャの中でreloaddeleteの処理を行うことで、一律でアニメーションのアップデートを行うことができます。 例えば、5つあるリストの1つ目を削除し、1つ目に新規要素を挿入するなら、deleteinsertの処理を行うことで、実現することができます。

デメリット

セルの挿入や削除の制御に手間がかかる

performBatchUpdateクロージャの中で、制御対象とするセルに対して、IndexPathを設定する必要があります。performBatchUpdateでは処理の順番に関わらず、削除→挿入の順に処理が実行されます。この時、削除や挿入する対象のセルがなければエラーが生じてしまうため、設定するIndexPathを正しく選択しておく必要があるので、削除や挿入前後のセルの順番を把握しておく必要があります。 画面を回転させた場合、セルの再生成を行う場合においてもIndexPathを正しく洗濯しておく必要があるため、あらゆる場合で考慮しておく必要がありそうです。

UITableViewのメリデメ

メリット

シンプルなリスト画面を作成しやすい

UICollectionViewとは違い、リスト画面のみを想定して用意されているため、簡単なリスト画面を作成する際には利用しやすいです。 リストに表示したい要素にSwitchButtonToggleBarなどを複数表示するためにそれぞれのセルを作成する必要はありますが、セルを表示する順番さえ決めておけば、あとはシステムがよしなに処理してくれるので楽です。

レイアウトの更新処理はlayoutIfNeededでなんとかなる

UITableViewのセルを更新完了の際にlayoutIfNeededを呼ぶだけで更新を完了させることができ、非常に楽です。ただ、他にreloadDatalayoutSubViewsなどのセルを更新するメソッドがありますが、こちらはUITableView全体を更新してしまい、処理の遅延に繋がることがあるので、利用するには向いてないです。

デメリット

セル数の更新操作が挿入と削除のみ

ネイティブライブラリから提供されているUITableViewのセルに対する操作は挿入と削除のみとなっています。 そのため、セルの移動に関してはUITableViewDelegateとUITableViewDataSourceで定義されている下記メソッドを実装する必要があり、手間がかかります。

・UITableViewDelegate

func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle

・UITableViewDataSource

func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool

func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)

最後に

いかがでしたでしょうか。検討する際の一助となれば幸いです。 UICollectionViewとUITableViewにはそれぞれの特徴があるので、うまく使い分けてみてください! 最後までご覧くださりありがとうございました。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proの購入はこちらから akerun.com

Webエンジニアがラズパイでセンサーデータ取得してBlinkでグラフ化するまで

この記事は Akerun Advent Calendar 2020 - Qiita の19日目の記事です。

Webエンジニアのt-ikeと申します。

入社2年目、Akerun Connectの開発などをメインで行っていました。

そのあたりの話をしようかなと思ったのですが、せっかくIoTの会社にいるのだから、それっぽいことに挑戦してみよう! ということで、比較的簡単にできそうなことを考えてみました。

はじまり

唐突ですが、最近鼻詰まりがひどいんです。

まぁ息するのができないというほどではないんですが、 唯一の趣味である飲酒において、香りを楽しみきれないというのは許せんということで、悶々とする日々をすごしていました。

原因はまぁちゃんと掃除してないとかだと思うんですが(←)、判断基準になるものがあったらいいなぁと思い、調べてみることに

調査

市販のものでも、空気質を計るようなスマートホームバイスもあったのですが、

  • リアルタイムな値しかみれず、過去の情報が参照できなさそう
  • 空気質の変化の検知を柔軟にできなさそう
  • せっかくだしもうちょいIoTっぽいことしようよ

などの理由で、ラズパイ&センサーでいけないか調査。

そもそも安価で、ハウスダストを計測できるものなんてあるんか、と調べると普通にありました。

www.seeedstudio.com

どうやらラズパイで使えるらしいということで、購入決定 (恥ずかしながら人生初ラズパイ

しかしながら、この値段でメモリ8GB、4Kも対応とかすごい時代になりましたね...

データの可視化

要件として、過去のデータも参照できて、それをグラフ化したいみたいなのがあって、 知ってる範囲でやるならcloudwatchとかに雑になげこめばいいかなぁと思ったんですが、 取得したデータをスマホで簡単に見れたらいいなぁと思い、調べてみるとよさそうなものがありました。

blynk.io

簡単にまとめると

  • インターネット経由でIoTデバイスを操作できるスマホアプリ
  • Virtual Pinという機能を使うことでGPIOの入力操作や出力データ取得が可能
  • 5つまでデバイス登録無料
  • Virtual Pinで取得したデータはクラウド上で保持
  • グラフ表示も可能

ということで、ちょっと触ってみたいユーザには最適なものがあり感激

センサーデータを送る

ラズパイ動かすとか、センサー取り付けるとか、初心者な障害は多々あったけど、そこらへんは省いて、blynkにセンサーデータを遅れるようにしてみる 上記のダストセンサーのリンクでも紹介されていますが、濃度取得のソースコードをもとに実装してみる。

自分はインタプリタ言語しかまともに触れない悲しいエンジニアなので、pythonでかきました

(抜粋してるのでこのままではうごきません)

import os
import RPi.GPIO as GPIO
import time
import blynklib
from blynktimer import Timer
from dotenv import load_dotenv
import threading

load_dotenv()
BLYNK_AUTH_TOKEN = os.environ['BLYNK_AUTH_TOKEN']
# ダストセンサーの出力PIN
PIN = int(os.environ['PIN'])
VPIN_RATIO = 0
VPIN_CONCENT = 1
VPIN_UGM3 = 2

blynk = blynklib.Blynk(BLYNK_AUTH_TOKEN)
timer = Timer()

GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN, GPIO.IN)
GPIO.setwarnings(False)


@timer.register(vpin_num=0, interval=INTERVAL, run_once=False)
def get_sensor_data(vpin_num):
    th = threading.Thread(target=measure, args=(PIN,))
    th.start()


def measure(PIN):
    t0 = time.time()
    t = 0
    while True:
        # パルス幅計測
        duration = pulseIn(PIN, 0)
        # 計測時間を超えたら濃度などを計算して送信
        if ((time.time() - t0) > MEASURING_TIME):
            ratio = t/MEASURING_TIME * 100
            concentration = 1.1 * pow(ratio,3) - 3.8 * pow(ratio,2) + 520 * ratio + 0.62
            blynk.virtual_write(VPIN_RATIO, ratio)
            blynk.virtual_write(VPIN_CONCENT, concentration)
            blynk.virtual_write(VPIN_UGM3, calc_ugm(concentration))
            break


if __name__ == "__main__":
    while True:
        blynk.run()
        timer.run()

blynk.virtual_writeをつかえば、指定した番号のvpinにデータが保存されていくみたいです。

Blynkを使う

ここまでくればあとはアプリでぽちぽちすれば終わり

説明がめんd...長くなるので、結果だけのせると、こんな感じでグラフ表示が簡単にできました。

f:id:photosynth-inc:20201217213452j:plain

でも本当にUIよいので、困るところそんなに無いと思います。

考察

センサーは別途の横においてるんですが、だいたい朝起きたときから1時間くらいかけて高くなっているようにみえる

以上

結果あんまりわからずw 空気清浄機かけてみるのとみないので変わるかとか試してみたけど、あまり変化せず。

とりあえず布団干したり、シーツ洗ったりする頻度を上げるようにしようと思いました。

感想

身の回りに関するデータを時系列で可視化するっていうのはあまりやったことがなかったので、やってみると結構楽しくできてよかったです。

他にも温度とか湿度とかとって、ログとして残しておくと、特に意味はないけどニヤニヤできそうな気もするのでやってみたいですね。

あとは市販のものでもできるけど、センサーデータトリガーで家電操作したりとかもいいですね

何よりこういったことに興味もって動くことができたのはこの会社に入っていろんなエンジニアの方々と触れ合えたおかげだなぁとしみじみ思います。

ということで

株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 https://recruit.jobcan.jp/photosynth/listrecruit.jobcan.jp

これぞ、完全タッチレスエントリー

17日目の記事です。

WebエンジニアのBunです。主にiOSアプリの開発を担当しています。

ドアに貼り付けるだけでスマホICカード社員証、遠隔から施錠解錠可能な弊社のスマートロックAkerunについて、もっと楽な施錠解錠方法がないか日々考えています。

新型コロナウイルスが広がっている中、ドアすら触れたくないですね。そこで、Apple Watchと弊社の「タッチレスエントリー・ソリューション」を組み合わせて、完全タッチレスでより快適な解錠を実現してみたいと思います。

akerun.com

akerun.hateblo.jp

13日目の記事(LINE Botから施錠解錠する)も書いたので、こちらも読んでみてください。

akerun.hateblo.jp

大分前にApple Watch Series 2を購入しましたが、その時はまだWatchOSのバージョンが2か3になっていて、色々機能制限があったので、結局何も作らずにただの腕時計として使ってきました。 その後、だんだん制限が解除され、特にWatchOS 6から独立したアプリも作成できるようになったので、Apple Watchだけで解錠できるアプリを作ってみました。

※最新のSeries 6を購入しようと思いましたが、今持っているSeires 2でもWatchOS 6までアップデートできたので、新たに購入せず済みました。ラッキ~

基本的にWatchOSのCMDeviceMotionから取得した姿勢データとBLEを使って実現可能なので、試してみたら、予想より簡単にできてしまいました。

WatchOSアプリのプロジェクト作成

プロジェクト新規作成から以下の「Watch App」を選択します。

適宜内容を記載し、プロジェクトを作成します。

以下のフォルダ構成フォルダ構成になります。

今回は特にUIも必要ないので、主にExtensionの方を実装していきます。 ただ、最初はMotionセンサーとBLE処理をデバッグしながら作るので、WatchKit AppのUIにテスト用ボタンなど追加してデバッグを行います。 また、毎回ビルドしてApple Watchにバイナリを転送すると結構時間がかかるので、Akerun本体とのBLE通信を確認するためのiPhoneアプリ(BLETester)も作ります。

Akerun本体とのBLE疎通確認

AkerunはPeripheralとして動作するので、Apple WatchをCentralとして動作させます。 iOS同様WatchOSからも直接BLE通信ができるので、CBCentralManagerを使って、Scan、Connect、Write(解錠コマンド書き込み)処理を実装します。 解錠用BLEコマンドは独自の暗号化処理になっているので、詳細は割愛します。

Motionデータ取得

WatchOSのCoreMotionからattitude(姿勢)、rotationRate(角速度)、gravity(重力加速度)、userAcceleration(加速度)が取れますが、今回はシンプルにattitude(姿勢)を使います。

Attitudeはpitch(ビッチ)、roll(ロール)、yaw(ヨー)の姿勢角があります。 手の動きについて何パターンか考えましたが、ドアノブを回す動きが自然かなと思ったので、pitchの変化タイミングを検知し、適切な閾値を設定して、解錠判定を行います。 ちなみにpitchは以下の定義になります。

  • 時計の3時方向を右、9時方向を左にし、左右X軸に関する回転角
  • 値の範囲は -π/2 から π/2 まで
  • 腕を上げて、画面がActiveになる時は0

具体的に、腕を上げてpitchの値が0前後(+/-0.1)になったら、判定をスタートし、腕を一瞬反時計回りに回した時、pitchの値が-π/3前後で解錠コマンドを送信するようにしています。

Apple Watchは、腕を下げると画面がDeactiveになるので、センサー情報の取得とBLE通信ができなくなります。バックグランドで実行するタスクを作れば、一定時間動作しますが、今回はDeactiveにならないように腕を反時計回りに回した後すぐ戻すことで回避しました。

画面がActiveになった場合、以下でMotionデータ取得開始します。パフォーマンスも考慮して、データ取得Intervalは1/30以下で十分だと思います。

private var motionMan = CMMotionManager()

func start() {
    if self.motionMan.isDeviceMotionAvailable {
        self.motionMan.deviceMotionUpdateInterval = 1.0 / 30.0
        self.motionMan.startDeviceMotionUpdates(to: OperationQueue.current!) { (motion, error) in
            if let m = motion {
                let data = MotionData(
                    attiPitch: m.attitude.pitch,
                    attiRoll: m.attitude.roll,
                    attiYaw: m.attitude.yaw
                )
                self.delegate.motionMamanger(self, data)
            }
        }
    }
}

func stop() {
    self.motionMan.stopDeviceMotionUpdates()
}

Motionデータが定期的に通知されるので、pitchがπ / 20以内になったら解錠判定をスタートし、その後のpitchが反時計回りにπ / 3以上回ったら、Akerunに接続し、解錠コマンドを送信します。

extension InterfaceController: MotionManagerDelegate {
    func motionMamanger(_ motionManager: MotionManager, _ data: MotionData) {
        if fabs(data.attiPitch) < Double.pi / 20 {
            self.isActive = true
        }
        
        if self.isActive {
            if data.attiPitch < -Double.pi / 3 {
                self.isActive = false
                self.akerunMan.connect(to: testUuid)
            }
        }
    }
}

動作

ちょうど出社する日があったので、Officeのドアで試してみました。ドアには電気錠/電磁錠に対応したAkerunコントローラーが設置され、半年前にタッチレスエントリーも導入しました。

普段は社員カードをかざして入退室していますが、下記のようにほぼ完全タッチレスが実現できました。

f:id:photosynth-inc:20201216111241g:plain

※動画撮るために腕を前に出していますが、手首の部分を少し上げてから回しても問題なく動作します。

まとめ

久しぶりにWatchOSを触りましたが、やっぱりIoT製品との相性も良く面白いですね。WatchOSのMotionセンサー、BLEなど基本的な機能だけで簡単にアイデアを具体化できるので、今後も色々試して見たくなります。

ただし、iOSと違ってまだまだ色々制限があるので、工夫しないといけないところもあります。

  • バックグランド処理

画面がDeactiveになって、バックグラウンドに入った時は処理が実行されません。 今回は、腕を早く回すことで何とか回避できましたが、下記の拡張セッションを使えば、完全ではないですが、バックグラウンドでの処理が実行できそうです。

f:id:photosynth-inc:20201215152347p:plain https://developer.apple.com/documentation/watchkit/using_extended_runtime_sessions

WatchOS 8以降でバックグラウンドでも簡単に処理が実行できるようになるかもしれませんが、早めにこういう制限を解除して欲しいですね。

  • NW通信

WiFiモデルの場合、結局iPhone経由でNetwork通信を行うので、独立したWatchアプリではなく、「iOS App with Watch App」でも十分かもしれません。Cellularモデルであればもっと快適になるかと思います。

取り敢えず動作するかどうか試してみただけなので、精度についてはそこまで考えていません。 以下のモーション動作を分類するActivity Classificationを使ってモデル構築し、機械学習すれば、色んな解錠ジェスチャーが実現できて、精度がもっと上がると思います。誤動作も少なくなるはずです。

f:id:photosynth-inc:20201215152435p:plain https://developer.apple.com/videos/play/wwdc2019/426/

また別の機会で試してみたいと思います。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proの購入はこちらから akerun.com

メカ設計する時に重要だと思っている思考

この記事は Akerun Advent Calendar 2020 - Qiita の16日目の記事です。

はじめまして。株式会社フォトシンスでメカ開発・設計を担当しております y_nagnag - Qiita と申します。 2020年10月からこの会社で働き始めました。 Advent Calendar書いてみるか!と息巻いてみたものの「うーん、、何書こう?」と頓挫して早数週間。。。 結果、「せっかく記事にするのであれば自分のための備忘録的なものにしよう!」と考え、メカ設計に従事する上で私なりに重要だと考えていることを書くことにしました。

メカ設計って?

メカ設計って何やってるかよく分からないと言われることがありますが、例えるならば「自分でピースをデザインしてパズルを完成させるような行為」だと思っています。

製品の外観デザインや仕様からパズルの完成像は決まってきますが、それを実現するための部品であるピースは「無」の状態から始まります。そのため、パズルを完成させるためにどんな部品が必要か/どんな部品構成をとるべきかを、性能、強度、耐久性、量産性、価格、etc.から多角的な視点で捉えて考え、1つ1つピースを作っていかないといけません。高次元なパズルゲームだと思っていただけると、少しは興味が湧くかもしれません。

この高次元なパズルゲームを解くためには「物理現象を捉える/知る」「思考実験をする」「多角的に考え最適解を求める」ことが重要だと私は考えています。以降に述べていきたいと思います。

物理現象を捉える/知る

ハードウェアの部分を設計している以上は物理現象が常に付きまとってきます。そのため、必要最低限な知識として物理現象を知っておく必要があります。ここでいう物理現象とは落下すると衝撃を受ける、熱は上に逃げていく、光は屈折したり反射したりする、といった物理学の話です。ここが分かっていないとメカの設計はできません。

実際に部品を設計すると試作して部品の出来栄えや機能の確認をするのですが、試験していく中で何かしら問題が起きることがあります。例えば、30cm落下させた時にプラスチック部品にクラックが入ってしまったとか。ここで、問題の原因を特定をしなくてはならないのですが、現物/現場/現象の3つを正確に捉える必要があります(探偵みたいですね)。理由は単純で、現物/現場/現象の3つが揃うことで初めて問題が生じるからです。

今回の例えで話すと、

現物:プラスチック部品 現場:30cm落下させる 現象:??? 結果:クラックが発生

となります。

ここでは現象に当てはまるヒントは現場にありそうですね。大体の人は現場の「落下」から、現象は「衝撃である」と結びつけます。

このように3つを正しく結びつけることができれば原因の特定につながり問題解決の糸口になります。また、問題となった物理現象は表面的にではなく、本質的な部分で捉え上位概念化して知識として頭の引き出しにしまっておきましょう。そうすることで似たような問題が起きたときに対処しやすくなり、別の製品や部品を設計する時に失敗しづらくなります。

思考実験をする

物理現象が伴ってくる以上は現物で確認する必要があります。メカ設計者の中には「とりあえず試作しよう!」ってタイプの人がいると思いますが、私はこの考えに割と否定的です。なぜなら、大抵このパターンは捉えるべき物理現象をあらかじめ把握できておらず無意味な試作になる場合が多いからです。そのため、試作をする前には質の高い思考実験を必ずするべきだと考えています。思考実験とはなんぞやって話になりますが、頭の中で実験場を展開しイメージ実験をすることです。

思考実験をする際のポイントとしては「深い思考を短時間に」です。

深い思考は前項で述べた上位概念化できている物理現象の知識量によって質が決まってくると思います。なぜなら、想像上で展開できる物理現象の引き出しが多いほど現実に則してくるからです。自身の思考実験が現実と一致するレベルまでできていると質が高いと言えるでしょう。

時間をかけてはいけない理由は一つの現象にのめり込んでしまい視野狭窄に陥りやすいからです。メカ設計は高次元のパズルゲームであるため、1次元だけにフォーカスしていては成り立たちません。常に多角的に捉えるためのポイントとして、「あえて時間をかけない」という方が正しいかもしれません。

思考実験を経て「確証が得られる」or「これ以上は分からない」レベルになった時点で実際のシミュレーションもしくは試作に踏み切って確認するようにしましょう。これによって、無駄な試作にかける時間とお金を節約できますし、何よりも確認しなくてはならないことがハッキリするので、効率的かつ効果的に試作を実施することができると思います。

また、試作確認の際に想定外の問題が起きた場合は前項で述べたことを経て知識のアップデートをしましょう。そうすることで、次回からの思考実験の質が上がっていくと思いますし、品質トラブルを起こしにくい設計ができるようなってくると思います。

多角的に考え最適解を求める

メカ設計は高次元なパズルゲームだと述べさせていただきました。高次元である以上、多角的に捉えて思考しなくてはなりません。この時に、絶対にやってはいけないという訳ではないんですが、設計した部品に対して「正解/間違い」の2値で考えてはいけないと私は思っています。理由は自由度の高さ故に唯一解は基本的に出てこないからです。

1つの次元だけで考えれば「正解/間違い」の2値で考えて良いのかもしれません。例えば、強度という面だけで考えれば十分に満足しているので正解ですと言えるかもしれません。 しかし実際には性能、耐久性、価格、など多角的に捉えていくと全てにおいて正解という訳ではないことに気がつきます。1つ1つの次元で良し悪しを持ったグラデーションのある解になっている場合が多いです。

そのため、出てきたグラデーションのある解の良し悪しは、製品が晒される環境において最適であるか否かで判断するべきだと私は考えています。 「正解を叩き出す」というよりは「あらゆる次元で通用する最適解にもっていく」という考え方で臨んでいる方が常に多角的に捉えられるので問題を起こしにくいです。上述した思考実験にも通ずる話になります。

製品が晒される環境は規格として握られてる場合が多いですが、できればお客様が使用されている現場に赴いて確認し、製品が晒される環境がどういった状況なのかを自身の中でしっかり握っておくことが大事です。

またもう一つポイントとして、多角的に考える際に「製品の未来像」や「市場問題が起きた時のバックアッププラン」も含めて考えれるとベストです。「今の流れから察するにこの製品の未来はこうかなぁ」「製品規格上満足しているけど、こんな問題起きないだろうか」という観点も含めて考えておくと、市場から出てきた要望やトラブルに対して迅速に対応できる仕掛けをあらかじめ製品に組み込んでおくことができます。

まとめ

つらつらと長く書いてしまいましたが、まとめるとこんな感じです。

  • 物理現象が伴ってくるので現物/現場/現象を真摯に捉えることが非常に重要。生じている物理現象は上位概念化し知識にして頭の引き出しにしまう。

  • 無意味な試作よりも思考実験を。そして深い思考を短時間で。時間をかけるほど視野狭窄に陥りがち。メカ設計における深い思考は、上位概念化できている物理現象の知識量で質が決まる。確証が得られる or これ以上は分からないレベルになった時点でシミュレーションもしくは試作に踏み切って確認する。

  • 正解/間違いの2値で解を求めるのではなく、多角的に考えて最適解を導き出すよう努める。多角の中には製品の未来像や市場問題が起きた際のバックアッププランも見据えて考えられるとベスト。

「あれ?3D CADの使い方は?図面の書き方は?」と思われた方もいるかと思いますが、実際にCADや図面の書き方は設計思想を表現するツールでしか無いと考えています(それ故に重要ではあるのですが今回は割愛)。

メカ設計のベースとなる部分は上記で述べたようなところになってくると考えており、私自身が実践できている/できていないが確認できるように記事としてしたためさせていただきました。

私の記事が少しでも皆さんのお役に立てれれば幸いです。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proの購入はこちらから akerun.com

選定した電気部品が買えなくなった時の話

この記事は Akerun Advent Calendar 2020 - Qiita の 15 日目の記事です。

はじめましてPsFujiです。
フォトシンスの開発部で電気回路設計を担当しています。
自分の文章を大勢の方に見ていただくのは初めてなので結構緊張しています。

弊社製品に関する事で何か面白いことを・・・と言われました。
何しろ入社2か月足らずのシニアな新入社員なのでネタに困りました。
困った結果、製品開発でよくある事について書こうと思います。

〇選定した電気部品が買えなくなった時の話


発生してほしくはないですが、狙ったかのように嫌なタイミングで発生するのが部品供給問題です。

”初ロット”

”ちょロット”

な挙句

” 総ロット”

になる


こういった製品なら問題ありません。
しかし、長期間にわたり製造する製品にとっては、非常に大きな問題となります。

部品が買えなく(入手難も)なったとの連絡を受けた後に取る主な対応は
以下の様な物になると思います。
    1)部品メーカーにお願いして最後のまとめ生産してもらう。
    2)回路やソフトの設計変更で別部品対応をする。
    3)市場にある流通在庫品を購入して対応する。
    4)聞かなかった事にして家に帰る。

今回お話するのは 3) の流通在庫品に関してです。

・製品を生産する段階になった時、ある部品が入手できないとの連絡が入りました。
開発日程を考えると今から設計変更する時間はないし、完全互換な代替品もない・・・・
となると取る方法は一つ、

"市場流通在庫品”

の購入です。


ネットで色々調べたところ市場在庫品を見つけたので聞き取り調査開始。

〇在庫確認

 私)在庫有る?

 商社)すぐに発送できるよ~

〇見積もり確認

 私)おねだんいくら?

 商社)これが見積もりだよ~

〇品質対応確認

 私)偽物だったり故障品だったりしないよね?

 商社)クレームあれば1か月以内に連絡くれれば返金対応するよ~

うん、レスポンスもなかなか早いし対応もそこそこ。
じゃあ、まずは少量入手して動作確認、問題なければ大量購入しよう と連絡をした所

〇現物確認

 私)有償でもよいから10個購入したいんだけど

 商社)じゃあ、1000USD前払いね。

・・・・・・え?


 私)見積もりと違うじゃん?

 商社)前払い必須、最低金額1000USDだから。それと自国の企業とは商売しないから

〇メールでは埒があかないので電話確認

 商社)出張中で電話取れないから!(メールで返答)


なんだか雲行き怪しくなってきたぞ・・・・・という事で色々調べていたら悪い評判たくさんできてきました
 ・金を振り込んだのに物が来ない
 ・詐欺だ
 ・ペーパーカンパニー
 ・金を振り込んで後悔した
 ・・・等 たくさん出てきました。

心配になったのと、でも部品は入手したいという事で

〇事実確認

 私)なんかネット上で悪評多いから心配になったけど、ちゃんと電子部品購入できるの?

 商社)・・・・・ごめん!在庫無いから売れない

以後、返事をもらえなくなりました。

〇教訓〇

”旨い物食わす人に油断すな”、困っている時ほど慎重に



過去には、流通在庫品のチップ部品を購入した時、日本メーカーの部品だからと安心していたら・・・
・リール内のコンデンサの容量がバラバラ
・メーカーに確認した所、リールに記載されているメーカ型番は正しいがLOT番号は存在しない番号だった。

なんて事もありましたが、それはまたの機会にでも・・・・



株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proの購入はこちらから akerun.com

クロス開発を快適に 〜バイナリと仲良くなるためのTips〜

この記事は Akerun Advent Calendar 2020 - Qiita の14日目の記事です。

ishturk - Qiitaです。

f:id:photosynth-inc:20201214104136j:plain

弊社はIoT企業なので、プログラムを書くエンジニアも、Web、スマホアプリ、マイコン、サーバー、インフラなど多岐にわたります。 これまではキャリア採用で、組込みのベーシックな知識がある人がジョインしているのですが、最近はWebからコンバートして組込みをやるエンジニアもいたり、新卒が入る予定もあったりして、組込み界隈のTipsやらをまとめようとしています。

今回は特にハードルが高いと思われがちなC言語を使ったクロス開発について。

クロス開発とは?

プログラムの開発環境と実行環境が違う開発で、特にプログラムのコンパイルが必要な場合を指します。

クロス開発の開発環境

多くの場合、 - コンパイラやリンカと便利ツールをセットにしたツールチェーン - ツールチェーンを内包した統合開発環境 で構成されます。始めるときや必要な情報をggるときは 「XXX(ターゲット) toolchain」とすると記事が沢山でます :)

バイナリと仲良くなるためのTips

参入障壁になりがちなのがここで、バイナリという言葉にアレルギー反応を起こす人も多いのでは。ポインタでつまづいた人は、バイナリとも喧嘩するでしょう。

コンパイラが生成するファイルたちについて理解する

  • .o ファイル :Cのソースをコンパイルしてできるバイナリ。1つの.c から同名の.oができると思って良い。ObjectのO。
  • .a ファイル: .o をまとめてできたファイル。SDKからライブラリとして提供される場合、ソースが提供されずに .a ファイルが提供される場合も多い。Archive のa。
  • .bin、.hex、.elfファイル:プログラムのバイナリそのもの。情報量は bin < hex << elfの関係。 .binはデータのみ。.hexは書き込みアドレス+データの方式でbinのデータをマッピングしたもの。.elfはシンボル情報などの付加情報が含まれている。
  • .mapファイル:デバッグ用の情報がまとめられているファイル。

バイナリを覗いてみる

玄人組込みエンジニアがバイナリが読めるなんていう都市伝説があります。16進数の羅列からほんとによめる猛者もいますが。。。ここはツールを使いましょう

この記事では詳細については書かないので、こんなツールがあるんだ!と知るきっかけになって貰えればと思います。

ツールについて

クロス開発では、コンパイラアーキテクチャが開発マシンと違うのでOSでインストールされているツールは使えないことが多いです。 最初に書いたツールチェーンに含まれている(はず)ので、探しましょう。コンパイルするためにパスを通したディレクトリにあります。

armのツールチェーン

f:id:photosynth-inc:20201214081824p:plain

ESP32のツールチェーン

f:id:photosynth-inc:20201214081840p:plain

nm

nm を実行すると、オブジェクトファイルのシンボル情報を確認できます

試しにESP32のhello worldをみてみましょう

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

void app_main(void)
{
    printf("Hello World");
}

f:id:photosynth-inc:20201214083015p:plain

main.c から生成した main.c.o は非常にシンプルです。

f:id:photosynth-inc:20201214083340p:plain

実行バイナリだとシステム起動などがあるので壮大になりますが、例えば main でgrep すると

f:id:photosynth-inc:20201214083454p:plain

app_main が 400d151c 番地 にマッピングされていることがわかります

odjdump

オブジェクトファイルから情報を引き出すツールです。いろいろできるのですが、逆アセンブルするときによく使います。

f:id:photosynth-inc:20201214084718p:plain

l32r は32bitのロード命令ですね。printするためにメモリに値をコピーしているのでしょう。

この方法を使えば、バイナリしか提供されていないオブジェクトファイルのアセンブラコードをみることができます。SDKの動きでハマった場合に有効です。

※ ライセンスによっては逆アセンブルが禁止されている場合もあるのでご注意を

addr2line

アドレスからソースコードの行数を表示するコマンドです。

先程の app_main が 400d151c 番地だったので、ためしにこれを逆引きしてみます。

f:id:photosynth-inc:20201214085601p:plain

app_main 関数で、9行目であることがわかりました。

これを使うユースケースは、例えば実行中にsegmentation faultが起こって、落ちたアドレスが情報として得られた場合、ソースコードのどの箇所なのかを引くことができます。

readelf

elf ファイルのヘッダ情報などをみることができます。 セクションヘッダ、プログラムヘッダなどの言葉を知ったら見てみてください。

ツールチェーン以外のツール

mapファイルを見る

コンパイラがmapファイルを吐いてくれる場合、ここにデバッグに有用な情報が沢山かかれています。 ↑でバイナリから取得した関数のマッピング情報なども実はここにすべてかかれています。

xxdコマンド、vimmerなら :%!xxd

バイナリを16進数方式 | ascii エンコードの方式で表示します。意味不明に見えますが、ここから関数名や変数名がみえたり static const の定数が探せたりします。

また、バイナリの差分を見るときはvimdiff + xxd で見ます(どや

おわり

「クロス開発コワイ」を減らす一助になれば幸いです。

この中のひとつでも知ってると「組込みやってる感」がでるので試してみてください!


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proの購入はこちらから akerun.com