---
# System prepended metadata

title: 2. 構造モデル

---

# 2. 構造モデル

本プログラムでは、データ駆動を意識した。走行体はシナリオ通りに動作し、ユーザは機能実現の詳細を把握する必要が無いものとする。

## 2-1. シナリオデータの設計

ナリオを走行コマンドの列で表現する。走行コマンドは、 1. オプション 2. 走行方法 3. 終了判定 によって構成される。

1. オプション
  走行コマンドの実行前に、距離計や角度計のリセットを行う場合がある。これらは走行コマンドのオプション設定としてデータで表す。

2. 走行方法
走行方法は、走行種別とそのパラメータによって記述する。機能モデルに要求される走行方法を以下に示す。

| 走行種別           | パラメータ                                           |
| ------------------ | ---------------------------------------------------- |
| PWM 固定値         | 左右 PWM                                             |
| PID 制御           | 基本 PWM, ライン沿い (右 or 左)、PID パラメータ、目標輝度                   |
| 消す？: 固定角走行 | 基本 PWM, ライン沿い (右 or 左)、 PID パラメータ、目標機体角度 |

3. 終了判定
  走行コマンドの終了判定は、関数として記述する。経過時間・走行距離・センサ値などの外界の情報を受け取って、継続または終了を返すものとする。
  以降、このような外界の全情報を、単に『ロボット情報』と呼ぶ。

## 2-2. モジュール構成・クラス図

```plantuml
@startuml
allow_mixing
skinparam packageStyle Node

P1 -d-> P2
P1 -d--> P4
P2 -d-> P3

共通 -l[hidden]-> P1

'note right of "シナリオ制御": シナリオ制御は外界のロボット情報を走行コマンドに与え、\n走行コマンドの指令 (モーターの制御値) を外界に反映する。\n\nまた走行コマンドの実行前に、センサリセット等のオプションを反映する。

'note right of "走行コマンド": 走行コマンドは、外界のロボット情報を受け取ってモータの制御値を返す。\n走行コマンドの終了判定は、コマンド作成時に受け取ったクロージャによって行う。

package "シナリオ制御" as P1 #F5F5F5 {
    +class CommandRunner {
        - commands: Command[]
        - currentCommand: int
        - clock: Clock
        - device: Device
    }
}

package "走行コマンド" as P2 #D5E8D4 {
    +class Command {
        - isEnd: Fn~<&Snapshot> -> bool
        - runMethod: IRunMethod
        + options: Options
        + run(snapshot: &Snapshot) -> Pwm
    }
    Command -d-o IRunMethod
    Command -d-o Options

    interface IRunMethod <<Interface>> {
        + init(snapshot: &Snapshot)
        + update(snapshot: &Snapshot) -> Pwm
    }
    
    IRunMethod <|.. BrightnessPidRun
    +class BrightnessPidRun {
        - pid: Pid
        + init(snapshot: &Snapshot)
        + update(snapshot: &Snapshot) -> Pwm
    }
    
    IRunMethod <|.. AnglePidRun
    +class AnglePidRun {
        - pid: Pid
        + init(snapshot: &Snapshot)
        + update(snapshot: &Snapshot) -> Pwm
    }
    
    IRunMethod <|.. FixedPwmRun
    +class FixedPwmRun {
        - pwm: Pwm
        + init(snapshot: &Snapshot)
        + update(snapshot: &Snapshot) -> Pwm
    }
    
    +class Options {
        + resetDistance: bool
        + resetDirection: bool
    }
}

package "PID制御" as P3 #F8CECC {    
    +class Pid {
        - basePwm: Pwm
        - pidParam: PidParam
        - edge: FollowEdge
        - targetBrightness: float
        - state: PidState
        + update(dt: float, brightness: float) -> Pwm
        + reset()
    }

    Pid -d-o PidState
   
    class PidState {
        - acc: float
        - lastDiff: float
        + update(dt: float, brightness: float, param: &PidParam)
        + reset()
    }
}

package "計測・デバイス制御" as P4 #DAE8FC {
    +class Device {
        + robo: Robo
        - dir: DiretionCalculator
        - dist: DistanceCalculator
        + tick(dt: float) -> Snapshot
        + setPwm(pwm: Pwm)
        + resetDirection()
        + resetDistance()
    }
    
    Device -d-o Robo
    Device -d-o DiretionCalculator
    Device -d-o DistanceCalculator

    class Robo {
        + wheels: Monor[2]
        + color: ColorSensor
        + gyro: GyroSensor
        + sonar: SonarSensor
        + touch: TouchSensor
    }
    
    class DiretionCalculator {
        - current: float
        + tick(dt: float) -> float
        + reset()
    }
    
    class DistanceCalculator {
        - current: float
        + tick(dt: float) -> float
        + reset()
    }
}

package "共通" #F5F5F5 {
    +class Snapshot {
        + dt: float
        + pwm: Pwm
        + distance: float
        + deltaDistance: float
        + direction: float
        + deltaDirection: float
        + color: rgb_raw_t
        + brightness: float
        + gyro: float
        + sonarDistance: float
    }

    +class PidParam {
        + float p
        + float i
        + float d
    }
    
    +enum FollowEdge {
        LeftEdge
        RightEdge
    }

    +class Pwm {
        + l: int
        + r: int
    }
}

@enduml
```

## パッケージ図

ET ロボコンのパッケージ図とはちょっと違う

```plantuml
@startuml
allow_mixing
'skinparam packageStyle Node

package "" as P1 #F5F5F5 {
    class "シナリオ制御" {}
}

package "走行コマンド" as P2 #D5E8D4 {
}

package "計測・デバイス制御" as P4 #DAE8FC {
}

package "共通" #F5F5F5 {
}

@enduml
```

# パーツ

```plantuml
'skinparam style strictuml
skinparam backgroundColor transparent
   +class 走行コマンド {
        '+ 開始時オプション: 開始時オプション
        '- 走行方法: 走行方法
        - 終了判定: Fn~<&ロボット情報> -> bool
        + 更新(&ロボット情報) -> Pwm
        + 終了判定の実施(&ロボット情報) -> bool
    }
    走行コマンド "1  " *-d- "-走行方法 1" 走行方法
    走行コマンド "1" *-d- "1 +オプション" 開始時オプション

    interface 走行方法 <<Interface>> {
        + 初期化(&ロボット情報)
        + 更新(&ロボット情報) -> Pwm
    }
    
    走行方法 <|.. "輝度に対するPID制御"
    +class "輝度に対するPID制御" {
        '- pid: Pid
        + 初期化(&ロボット情報)
        + 更新(&ロボット情報) -> Pwm
    }
    
    走行方法 <|.. "モータ回転比に対するPID制御"
    +class "モータ回転比に対するPID制御" {
        '- pid: Pid
        + 初期化(&ロボット情報)
        + 更新(&ロボット情報) -> Pwm
    }
    
    走行方法 <|.. PWM固定走法
    +class PWM固定走法 {
        - pwm: Pwm
        + 初期化(&ロボット情報)
        + 更新(&ロボット情報) -> Pwm
    }
    
    +class 開始時オプション {
        + 距離計リセット: bool
        + 角度計リセット: bool
    }
```

```plantuml
'skinparam style strictuml
skinparam backgroundColor transparent
    +class ロボット情報 {
        + dt: float
        + pwm: Pwm
        + 距離: float
        + 距離偏差: float
        + 角度: float
        + 角度偏差: float
        + 色: rgb_raw_t
        + 輝度: float
    }

    +class Pwm {
        + l: int
        + r: int
    }
```

```plantuml
'skinparam style strictuml
skinparam backgroundColor transparent
    +class PID制御 {
        - 基本PWM: Pwm
        - 目標値: float
        ''- 状態: PidState
        + 更新(dt: float, 現在値: float) -> Pwm
        + リセット()
    }

    PID制御 "1 " *-d- "1 -状態" PID状態
    PID制御 "1 " *-d- "1 -設定" PID設定
    PID制御 "1 " *-d- "1 -方向" 制御方向
   
    class PID状態 {
        - 蓄積値: float
        - 前回差: float
        + 更新(dt: float, 現在値: float, 設定: &PID設定)
        + リセット()
    }

    +class PID設定 {
        + p: float
        + i: float
        + d: float
    }
    
    +enum 制御方向 <<Enuemration>> {
        +正方向
        +負方向
    }
```

```plantuml
'skinparam style strictuml
skinparam backgroundColor transparent
    +class デバイス {
        + 更新(dt: float) -> ロボット情報
        + PWMセット(pwm: Pwm)
        + 距離計リセット()
        + 方向計リセット()
    }
    
    "デバイス" "1" *-d- "+ロボット 1" ロボット
    "デバイス" "1" *-d- "+角度計 1" 角度計
    "デバイス" "1" *-d- "+距離計 1" 距離計

    class ロボット {
        + 左右モータ: Monor[2]
        + 色センサー: ColorSensor
        + ジャイロセンサ―: GyroSensor
        + 超音波センサー: SonarSensor
        + タッチセンサー: TouchSensor
        + 各種センサ値取得(&mut ロボット情報)
        + モータ角取得(l: &mut int, r: &mut int)
    }
    
    class 角度計 {
        - 現在値: float
        + 更新(dt: float) -> float
        + リセット()
    }
    
    class 距離計 {
        - 現在値: float
        + 更新(dt: float) -> float
        + リセット()
    }
```

```plantuml
'skinparam style strictuml
skinparam backgroundColor transparent
    +class コマンド実行 {
        '- コマンド列: 走行コマンド[]
        - 現コマンド: int
        - 時計: Clock
        - 現在時間: uint
        '- デバイス: デバイス
        + 更新()
    }
```

凡例

```plantuml
+class PublicClass {
    +publicField: Type
    -privateField: Type
}
```

```plantuml
-class PrivateClass {
    +publicMethod() -> Type
    -privateMethod() -> Type
}
```

```plantuml
+enum Enum <<Enuemration>> {
    +Variant
}
```

```plantuml=
+interface Interface <<Interface>> {
}
```
