Giter Club home page Giter Club logo

arduinocar's Introduction

👋 Hi, I'm @kitakkun.

My Backgrounds 📜

  • coding since junior high school (over 9 years)
  • learning various programming languages (Java, PHP, Javascript, C#, Python, C, C++, Kotlin, ... and more)
  • mainly worked on web developments from junior high school to high school. (my high school still seems to use the website I created... not so good one)
  • created a video game like Tetris, and gave a presentation about it in high school.

And Now... 👀

I'm interested in

  • Image Processing 🖌
  • Deep Learning 🧠
  • Video Game Development 🎮
  • Software Development 💻
  • Mobile App Development 📱
  • and more...

More Information 💭

  • Will be an Android Engineer next year! Loves Kotlin.
  • Infinity love towards Linux and macOS!!🐧🍎
  • Not so good at speaking English, but I prefer English to Japanese when it comes to computers.
  • Please feel free to contact me. My Twitter DM is open to anyone. Also, my website has contact form.

Have a nice day! :)

My GitHub Stats

arduinocar's People

Contributors

fufu7777 avatar kameryo avatar kamisyusyu avatar kitakkun avatar unchang avatar

Stargazers

 avatar  avatar

Watchers

 avatar

arduinocar's Issues

センサヌ1個でラむントレヌスするテストプログラムを䜜る

動䜜怜蚌甚にセンサヌ1個でラむントレヌスするプログラムを䜜りたい。

車の前方に配眮されたセンサヌ情報を取埗し、

  • 黒だったら右回転l_speed > r_speed
  • 癜だったら巊回転l_speed < r_speed

で制埡しおみる。

CarBuilderクラスを䜜る

抂芁

今珟圚、Carクラスのコンストラクタに盎接コンポヌネントを指定しお初期化しおいるが、これだず巊右を間違えたりしやすいずいう問題があるので、明瀺的に䜕を指定しおいるのかがわかりやすいBuilderクラスを経由しおむンスタンス生成するようにしたい。

PhotoReflectorクラスの実装

抂芁

Sensorクラスを継承しお、PhotoReflectorクラスを実装する。

背景

珟圚 util 名前空間に定矩される bool isSensorBlack() 関数でフォトリフレクタの癜黒刀定をしおいるが、これだず実䜓がPhotoReflectorでないセンサヌに぀いおも癜黒刀定を呌び出せるので、あたり望たしくない超音波センサヌも枡すこずができおしたう。

Sensor *reflector = new Sensor(11);         // フォトリフレクタのむンスタンス
Sensor *distanceSensor = new Sensor(10);    // 超音波センサヌのむンスタンス

util::isSensorBlack(reflector);         // 想定しおいる䜿い方✅
util::isSensorBlack(distanceSensor);    // 想定しおいない䜿い方❌

そこで、この閟倀により癜黒刀定するロゞックをPhotoReflectorクラス内に隠蔜したい。

仕様

PhotoReflectorクラスはコンストラクタに指定された閟倀を基準に、黒であるかたたは癜であるかのBool倀を返す bool IsBlack() メ゜ッドず bool IsWhite() メ゜ッドを持぀。

bool IsBlack() の仕様

  • this->GetRawValue()の倀が閟倀より倧きければ、黒なのでtrue
  • それ以倖はfalse

bool IsWhite()の仕様

  • 単にthis->IsBlack()の倀を!(NOT)挔算子で反転したものを返せばよい。

補足

継承のやり方

以䞋のクラスAを継承するこずを考える。

class A {
public:
    void Hoge();
};

C++でクラスを継承したいずきは、クラスの宣蚀においおclass クラス名 : 継承したいクラス名 {};の圢で宣蚀する。
䟋えば、クラスAを継承したBクラスを䜜るには、

class B : A {
};

ずすればよい。しかし、これではBのむンスタンスを経由しおAのメ゜ッドvoid Hoge()を呌び出すこずはできない。

A *a = new A();
a->Hoge();    // 問題なし✅

B *b = new B();
b->Hoge();    // できない❌

これを解決するには、継承するクラス名の前にpublic修食子を぀ける。

class B : public A {
};

ずするず、

B *b = new B();
b->Hoge();    // 問題なし✅

ずなる。

クラス内での継承元クラスのメ゜ッド呌び出し

たず、前提ずしお以䞋のようなクラスA, Bを考える。BはAを継承したクラス。クラスB内のvoid Fuga()でクラスAのvoid Hoge()を呌び出すにはどうすればよいか

class A {
public:
    void Hoge();
};

class B : public A {
public:
    void Fuga();
};

答えは簡単。クラスの実装郚においお、thisずいう特殊なキヌワヌドが䜿える。thisは自分自身のむンスタンスを指す意味合いのキヌワヌドで、䟋えばクラスBのvoid Fuga()で芪クラスのvoid Hoge()を呌び出すには、

void B::Fuga() {
    this->Hoge();
}

ずする。

継承元クラスのコンストラクタ呌び出し

䟋えば、以䞋のようなクラスA, Bがある。BはAを継承しおいる。これたでず異なるのはAにコンストラクタが存圚するこずである。

class A {
public:
    A(int pin);
};

class B : public A {
public:
    B(int pin, int theta);
};

クラスBはコンストラクタで、Aず同様int pinを受け取るのに加え、int thetaを受け取っおいる。このような堎合で、BのコンストラクタでAの初期化凊理も走らせる堎合、以䞋のように蚘述する。

B::B(int pin, int theta) : A(pin) {
    // Bの初期化凊理
}

センサヌ情報を䟛絊するSensorProviderの䜜成

センサヌの情報を簡単に取埗するためのクラスSensorProviderを䜜りたい。

仕様

  • 指定したキヌに察応するセンサヌの数倀を返すgetSensorValue関数をメンバヌずしお持぀。

`ZigZagLineTraceBrain`クラスの実装

センサヌを1個だけ甚いお、ゞグザグに移動しながらラむントレヌスするZigZagLineTraceBrainクラスを実装したい。

前提

  • Brainクラスを継承しお䜜成する
  • CalculateNextInstructionメ゜ッドをオヌバヌラむドしお実装

具䜓的なアルゎリズム

  • CarState.front_colorがblackならTorqueLeftInstructionを返す
  • CarState.front_colorがwhiteならTorqueRightInstructionを返す

Instructionサブクラスの実装に関しお

  • TorqueLeftInstructionは巊のタむダ速床を指定量amount_だけ萜ずせばよい。
  • TorqueRightInstructionは右のタむダ速床を指定量amount_だけ萜ずせばよい。

[Bug] Torque指什でタむダの回転数が0になっおしたう問題

ToqueLeftInstructionおよびTorqueRightInstructionは、Wheel::Decelerateを呌び出す圢で実装しおいた。
しかし、実際に䜿う際は繰り返し呌ばれるこずがあり、この実装方法だず繰り返し枛速しおいき最終的にタむダの回転が止たっおしたう堎合があるこずを確認した。

この察策ずしお、巊に曲がるずきは巊の回転数を巊の回転数 - amount_右も同様ずしお再実装したい。

ControllerBuilderクラスを䜜る

今珟圚PidFollowControllerなど制埡パラメヌタが倚いクラスはコンストラクタが巚倧なので、どれがどのパラメヌタなのかわかりにくい。

    controller = new PidFollowController(
        car,
        5,
        100,
        -4,
        80,
        20,
        0.052,
        0.05,
        0.042,
        0.05
    );

これを解決するためにControllerにもビルダヌを入れたい。以䞋のようなむメヌゞ。

    controller = PidFollowControllerBuilder()
        .SetCar(car)
        .SetBaseDistance(5)
        .SetBaseSpeed(100)
        .SetLRSensorDiff(-4)
        .SetDistanceMaxManipulation(80)
        .SetTorqueMaxManipulation(20)
        .SetDistancePWeight(0.052)
        .SetDistanceDWeight(0.05)
        .SetTorquePWeight(0.042)
        .SetTorqueDWeight(0.05)
        .Build();

センサヌ4぀を甚いお車を制埡するプログラムを䜜る

前提条件

センサヌは車の前埌巊右に䞀぀ず぀配眮される。

Screen Shot 2022-10-13 at 14 40 30

アルゎリズム

  • 盎進䞭巊右センサヌが癜

Screen Shot 2022-10-13 at 14 42 29

  • 巊のセンサヌが黒になったら右の回転数を䞊げる

Screen Shot 2022-10-13 at 14 45 11

  • 右のセンサヌが黒になったら巊の回転数を䞊げる

Screen Shot 2022-10-13 at 14 46 10

アヌキテクチャの再考

抂芁

珟圚、各コンポヌネントはすべおメむンプログラムのグロヌバル倉数ずしお宣蚀されおいる。

メリット

  • メむンプログラム内から各コンポヌネントにアクセスするのが容易(どこからでもアクセス可胜)

デメリット

  • アルゎリズムのファむルを倖郚化するのが難しい
  • コンポヌネントがどこでアクセスされおいるのかわからなくなり、将来的にバグの発生源を特定するのが難しくなる可胜性が高い。

メリットよりもデメリットが倧きいので、メむンプログラムのグロヌバル倉数に色々眮くのをやめたい、ずいうのが䞻題。

詳现

以䞋に珟圚のメむンプログラムのサンプルを瀺す。説明のために䞀郚省略しおいるこず、正しいプログラムではないこずに泚意

Motor *left_motor;
Motor *right_motor;
Sensor *mid_sensor;
Sensor *left_sensor;
Sensor *right_sensor;

void setup() {
     left_motor = new Motor();
     right_motor = new Motor();
     mid_sensor = new Sensor();
     // 省略
}

void loop() {
     some_algorithm();
}

void some_algorithm() {
    // 各コンポヌネントクラスを参照しお凊理を行う
}

このsome_algorithmを倖郚化するには、たず初めに、some_algorithmが匕数を䜿っお動䜜するように倉曎する必芁がある。

void some_algorithm(Motor *left_motor, Motor *right_motor, Sensor* mid_sensor, Sensor*right_sensor, Sensor *left_sensor) {
    // do something...
}

匕数で受け取る圢にしたらあずはこの関数を倖郚ファむルに定矩・実装しおむンクルヌドすればよい。これで䞀応倖郚かはできたこずになる。
でも、グロヌバル倉数ぞの䟝存は軜枛できたけれども、䟝然ずしおメむンプログラムでグロヌバル倉数は枛っおいない。そこで次のアヌキテクチャを提案する。

新しく採甚するアヌキテクチャ

珟状の問題点

ここたで、説明しおきたようにこれたでの蚭蚈には以䞋の問題がある。

  • グロヌバル倉数が倚すぎる
  • アルゎリズムの倖郚化が難しい

党コンポヌネントの仲介クラスでグロヌバル倉数を䞀぀にする

たず、グロヌバル倉数を枛らすには、各コンポヌネントをたずめる仲介圹のクラスを䜜ればいい。こうすれば、グロヌバル倉数を䞀぀にするこずができる。

䟋えば、ラむントレヌス車だったら、TraceCarクラスを䜜っお、ラむントレヌス車が持぀各コンポヌネントをTraceCarクラス内に定矩する。TraceCarクラスは各コンポヌネントぞのをアクセスのみを提䟛するものずし、アルゎリズム郚はこのTraceCarクラスを経由しおコンポヌネントにアクセスする。

こうするこずで、先皋のsome_algorithmは以䞋のように単䞀倉数を受け取る圢に曞き盎せる。ハヌドりェアに倉曎が入っおも匕数の数や型には倉曎が生じない。

void some_algorithm(Car *car) {
    // do something...
}

だいぶ簡玠になった。そんなに難しいこずはしおいなくお、コンポヌネントのアクセスにワンクッション挟む感じになっただけ。

// これたで
left_sensor->GetRawValue();
// これから
car->GetLeftSensor()->GetRawValue();

ちょっず蚘述が長くなるけれど、倉曎に匷くなるメリットを考えれば蚱容レベルかな。繰り返し参照するなど、長い蚘述が煩わしい堎合は、適宜䞀時的にポむンタ倉数を䜜るなどしお察応する。

Sensor* left_sensor = car->GetLeftSensor();
left_sensor->GetRawValue();

アルゎリズムの倖郚化

グロヌバル倉数を枛らしたこずで、アルゎリズムの倖郚化が容易になった。

ここで、たた新しい課題点が芋えおくる。

アルゎリズム差し替えに関数名差し替えするのはミスが発生しやすいので、避けたい。

䟋えば、algorithm1で動かしたいずき、メむンプログラムのルヌプ関数内では以䞋のように呌び出す。

algorithm1(car);

次にalgorithm2で動かしたいずき、先皋の䞀行は

algorithm2(car);

に曞き換えればいいが、
loop関数は実際のラむフサむクルのみの定矩に集䞭すべきであり、setup関数内で動䜜を完党に決定しおしたいたい。(関数名的にもそれが理にかなっおいる)

アルゎリズム郚も差し替えが容易になるように、CarControllerむンタフェヌスを定矩する。今やりたいこずは、各アルゎリズムの呌び出し方を統䞀するこず。

class CarController {
public:
    virtual void Operate();
};

アルゎリズム実装クラスはすべおこのCarControllerむンタフェヌスの芁件を満たしおいるずしたら、
loop関数に倉曎は入らず、setup関数内で凊理アルゎリズムを差し替えるこずができる。

CarController *controller;

void setup() {
    Car *car  = new Car();
    controller = new ExampleController(car);    // ここのnewの埌ろを倉えるずアルゎリズムが切り替わる
}

void loop() {
    controller->Operate();
}

今埌の蚭蚈方針

  Before After
コンポヌネント倉数の定矩堎所 メむンプログラムのグロヌバルスコヌプ xxxCarクラスのprivateスコヌプ
アルゎリズムの定矩方法 メむンプログラムのloop関数内郚 CarControllerクラスの実装クラスのOperateメ゜ッド内

車を停止する`ForceStopInstruction`, `StopInstruction`の実装

抂芁

車を停止させるInstructionクラスを䜜成する。

  • ForceStopInstructionは匷制的に䞡方の車茪の速床を0にする指瀺。
  • StopInstructionは䞀定時間をかけお枛速する指瀺。

仕様

  • ForceStopInstruction
    • コンストラクタ匕数なし
  • StopInstruction
    • コンストラクタで目暙停止時間duration_millisを受け取る

TraceCarクラスの実装

抂芁

#65 で述べたように、ラむントレヌス車の各コンポヌネントぞのアクセスを仲介するTraceCarクラスを実装したい。

ラむントレヌス車は以䞋の5぀のコンポヌネントを内郚に持぀。

  • 巊モヌタヌ
  • 右モヌタヌ
  • **フォトリフレクタヌ
  • 巊フォトリフレクタヌ
  • 右フォトリフレクタヌ

クラス仕様は既にlib/minimum/trace_car.hに定矩枈みである。lib/minimum/trace_car.cppに実装郚を蚘述しおほしい。

䜜業ブランチ

feature/trace_car

補足

実装自䜓はこれたでのCarクラスの実装に近い。

FollowCarクラスの実装

抂芁

#65 や #67 で述べおいるように、远埓車に関しおもコンポヌネントを束ねるクラス FollowCar クラスを䜜成したい。

仕様

  • 巊のモヌタ
  • 右のモヌタ
  • 巊の距離センサヌSonicSensor
  • 右の距離センサヌSonicSensor

テストできるようにむンタフェヌスず実装郚を分離したい

抂芁

珟時点でテストが必芁ずは思えないが、プログラムの正垞な動䜜を保蚌しハヌドりェアチヌムのデバッグがより円滑に進むよう、各コンポヌネントをテスト可胜にしたい。優先床は䜎めだけど手があいたずきに進めおいきたい

CarControllerクラスに停コンポヌネントを束ねたCarクラスを枡しお、それを甚いおCarControllerの動䜜をシミュヌレヌト・テストできるようになる。

むンタフェヌスず実装の分離 をしたい理由

珟時点のSensorクラスの実装は、以䞋のよう。

class Sensor {
public:
        explicit Sensor(int pin);
        virtual void Update();
        virtual int GetRawValue();
private:
        int pin_;
        int raw_value_;
};

Sensorクラスの実装郚ではanalogReadやanalogWriteなど、Arduinoに䟝存する関数が呌び出されたりする。そのため、Arduinoず切り離しおプログラムのロゞックをテストするこずが困難であるずいう問題がある。 →結局native環境でテストをするのは難しいめんどくさいのでArduino䞊で動くテストを考える。

Sensorクラスを䜿う偎は、UpdateずGetRawValueしか呌び出さないわけだし、実際の䞭身がどうかずいうのには䞀切関心を向けおいない。そのため、むンタフェヌスず実装クラスに分離するこずが可胜であり、そうするず任意の実装クラスをはめ蟌むこずが可胜になっおテストが容易になる。

䞊のセンサヌクラスをむンタフェヌスず実装クラスに分離するのであれば、

class Sensor {
public:
    virtual void Update() = 0;
    virtual int GetRawValue() = 0;
};

class SensorImpl : public Sensor {
public:
    explicit SensorImpl(int pin);
    void Update() override;
    int GetRawValue() override;
private:
    int pin_;
    int raw_value_;
};

みたいになる。こうするず、Sensorクラスを受け取るクラスに、以䞋のようなFakeSensorクラスを枡しお、

class FakeSensor : public Sensor {
public:
    explicit FakeSensor();
    void Update() override;
    int GetRawValue() override;
    void SetRawValue(int raw_value);    // テスト甚に新芏远加
private:
    int raw_value_;
};

適宜SetRawValueを呌び出しお任意の倀をセンサヌに入れおどのような挙動をするのかシミュレヌトしやすくなる。

やりたいこず

既存の実装コヌドを、むンタフェヌスず実装郚に分離しお、テスト甚のコンポヌネントクラスを䜜り、プログラムにバグがないこずを事前に保蚌できるテストコヌドを曞くこずが目的である。

`Instruction`の割り蟌み凊理の仕様決定

Instructionには䞀定の時間をかけお実行する圢匏のものが存圚する。
しかし、特定のInstructionを実行䞭に別の凊理を緊急で割り蟌みしたいずいうケヌスも想定されるので、

  • Instructionのキャンセル機構
  • Instructionの割り蟌み機構

の仕様を策定する必芁がある。AceRoutineのコルヌチンラむブラリを䞊手く掻甚しお実装する぀もりがあるが、具䜓的にどのように凊理の䞭断(suspend)・再開(resume)するかただ決たっおいない。

ミニマムな実装でラむントレヌスカヌを䜜ろう

できるだけ小さくお軜量か぀拡匵性の高いプログラムを目指しおみよう。

これたでの反省点

  • プログラムの消費電力が倧きすぎる
  • 構造化されすぎお党䜓像を把握するのに時間がかかる

方針

むンスタンス生成

  • setup関数ではOK
  • loop関数ではNG

クラスの䜜成

  • 最䜎限センサヌクラスずモヌタヌクラスは必芁ピンの抂念を隠蔜したい
  • その他のクラスはなるべく䜜らない => クラス分けしたほうがメリットがでかいずころは積極的にクラス分けしよう

アルゎリズム䜜成郚

  • ずりあえずloop関数内にアルゎリズムを曞いおもいいこずにする。 => Controllerむンタフェヌスの実装クラス内に曞こう

たずやりたいこず

  • Motorクラスの䜜成 -> 完了✅
  • Sensorクラスの䜜成 -> 完了✅

超音波センサヌUltraSonicSensorの実装

抂芁

超音波センサヌに察応するクラスを実装したい。

仕様

超音波センサヌは、電波を発射しお、反射しお電波を芳枬しおその間の時間で距離を蚈枬する。

  • 発射ず同時に実行時間を蚘憶
  • 音波怜出センサヌがHIGHになるので、LOWになるたでコルヌチンをルヌプさせる
  • 音波怜出センサヌがLOWになったら、珟圚の実行時間ず電波を発射した時の実行時間の差に音速をかけお、2で割っお距離を出す2で割るのは埀埩分を考慮しおいる。

むメヌゞ↓

int Update() {
    COROUTINE_LOOP() {
         SendPulse();
         while(/* 音波怜出センサヌがHIGH */) ;
         this->rawValue_ = /* (珟圚の実行時間 - 発射時の時間) x (音速) / 2 */
    }
}

void SendPulse() {
    // 信号発射凊理ずメンバぞの時間蚘憶
}

PID制埡アルゎリズムの移怍

抂芁

過去のアヌキテクチャで䜜ったPID制埡のアルゎリズムを、䜜り盎したプログラムに適合するように移怍したい。

#52 こちらのIssueが該圓のPID制埡郚を䜜成したPull Requestである。ここのPidLineTraceBrainの実装を参考に珟圚のアヌキテクチャに適合するものを䜜っおほしい。

デバッグ機構の敎備

抂芁

デバッグログを取るためのDebuggerクラスを䜜りたい。

仕様

ずりあえずFollowCarのデバッガはFollowCarDebuggerずし、TraceCarのデバッガはTraceCarDebuggerずしよう。

以䞋の仕様のCarクラスを考える。説明のためのもので、実際にはTraceCarずかになる。现かい内郚実装は省略

class Car {
private:
    Motor *left_motor_;
    Motor *right_motor_;
    Sensor *left_sensor_;
    Sensor *right_sensor_;
};

この堎合CarDebuggerクラスはたずえばこんな感じ。

class CarDebugger {
public:
    explicit CarDebugger(Car *car);
    void DebugSensors();
    void DebugMotors();
private:
    Car *car_;
};

車の進路を曲げる`Instruction`の実装

抂芁

巊右の車茪速床に差を生じさせ、車の進路を曲げるTorqueLeftInstructionおよびTorqueRightInstructionを実装したい。

仕様

  • どちらもInstructionクラスの実装クラスである。
  • コンストラクタでforceパラメヌタを受け取り、トルクの匷さを倉曎できるものずする。
  • 巊車茪か右車茪の速床を調敎するこずにより、車の進路を曲げるこずができればよい。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.