Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 1 year has passed since last update.

LEGO Mindstorms AI利用で制御学習 M5Stack

0
Last updated at Posted at 2024-11-16

image.png

image.png

2日空け また再開 足踏み状態&時間制限 

image.png

3日間 足踏み 状態

LEGO-ョ_Education_WeDo2_WirelessSDK を 参照して 再検討依頼
挫折しそうです

image.png

以下のリンクからプロトコル仕様
LEGO Wireless Protocol 3.0.00
LED制御コマンドの修正
LEDポート番号の確認
LEGOデバイスの場合、内蔵LEDのポート番号は 0x32(50)であることが多いです。現在使用しているポート番号 0x06 が正しいか確認してください。
LEGO Powered Up Wireless Protocol 参照してください。
https://lego.github.io/lego-ble-wireless-protocol-docs/index.html

多くのBLEデバイスでは、コマンドの最初のバイトはメッセージ全体の長さを表します。
例として、uint8_t connectCommand[] = {0x05, 0x00, 0x02, 0x01, 0x02}; の最初のバイト 0x05 はメッセージの長さを示しています。しかし、実際のメッセージの長さと一致しているか確認してください。
コマンドIDやパラメータが正しいか確認
デバイスのプロトコル仕様書を参照し、各コマンドのIDやパラメータが正しいか確認します。
デバイスのプロトコル仕様を確認する

なかなか 難航しています 

限られた 制限の中 o1(o1-preview)は、従来のGPTで挑戦中
Plus および Team ユーザーの場合、o1-mini のレート制限が 71 週間あたり 50 メッセージから 1 日あたり 50 メッセージになりました。( 30分 ぐらいで 制限 かかります )

LEGO-ョ Education WeDo 2.0 Communication Software Developer Kit も参考に見直し 再検討願います

o1-preview の提供にはコストがかかるため、レート制限を週 30 メッセージから週 50 メッセージに増やしました。

image.png
Plus および Team ユーザーの場合、o1-mini のレート制限が 71 週間あたり 50 メッセージから 1 日あたり 50 メッセージになりました。( 30分 ぐらいで 制限 かかります )

image.png

image.png

copilotで 導入で WeDo Smart Hub 制御する プログラム 始めました

image.png

WeDo Smart Hub 接続試験 トライ

https://afrel.co.jp/technology-info/wedo2/wedo2-software/22289/
Bluetooth MAC アドレスを&UUIDを確認
https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp&hl=ja
接続後の動作確認

ジャンク買いました 孫と遊ぼうと思います M5でも制御
image.png

image.png

image.png

M5StackにはBaseX

LEGO Mindstorms

LEGO Mindstorms 

AIと協力して、試験プログラム出来ました( おまけで猫の顔も書いてもらいました)

image.png

https://x.com/tkurume/status/1858694794404655634
https://www.youtube.com/watch?v=716aMR_dFxs
https://chatgpt.com/share/67387fc8-a3bc-8004-9e17-7617dd5e25cf
回答 コード

/*
    Description: Provide three LEGO motor drive modes and servo control.
    Press button B to switch the mode.
    Button A and C control parameter value increase and decrease.
    Motors 3 and 4 have reversed rotation directions.
    Display a large cat face in the center of the screen that changes according to the mode.
*/

#include <M5Stack.h>
#include "BaseX.h"

#define NORMAL_MODE    0
#define POSITION_MODE  1
#define SPEED_MODE     2
#define SERVO_MODE     3

BASE_X base_x          = BASE_X();
int32_t position_point = 0;
int8_t mode            = NORMAL_MODE;
uint8_t max_speed      = 20;
int8_t speed_point     = 0;
uint8_t servo1_angle   = 90;
uint8_t servo2_angle   = 90;

void setup() {
    M5.begin(true, false, true, true);
    M5.Power.begin();
    M5.Lcd.clear();               
    M5.Lcd.setTextSize(2);        
    M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);

    // モーターの初期設定
    for (uint8_t i = 1; i < 5; i++) {
        base_x.SetMode(i, NORMAL_MODE);
    }

    // サーボの初期設定
    servo1_angle = 90;
    servo2_angle = 90;
    base_x.SetServoAngle(1, servo1_angle);
    base_x.SetServoAngle(2, servo2_angle);
}

void displayButtons() {
    M5.Lcd.setTextColor(TFT_CYAN);
    M5.Lcd.setCursor(0, 210);
    M5.Lcd.println("BtnA:+  BtnB:Mode  BtnC:-");
    M5.Lcd.setTextColor(TFT_WHITE);
}

void displayMode() {
    M5.Lcd.setTextColor(TFT_WHITE);
    M5.Lcd.setCursor(0, 190); // 画面下部にモードを表示
    if (mode == NORMAL_MODE) {
        M5.Lcd.println("Mode: Normal     ");
    } else if (mode == POSITION_MODE) {
        M5.Lcd.println("Mode: Position   ");
    } else if (mode == SPEED_MODE) {
        M5.Lcd.println("Mode: Speed      ");
    } else if (mode == SERVO_MODE) {
        M5.Lcd.println("Mode: Servo      ");
    }
}

void displayCatFace() {
    // 猫の顔を描画する関数
    M5.Lcd.fillScreen(TFT_BLACK);

    // 顔の位置を上にずらすためにY座標を減少させる
    int faceCenterX = 160;
    int faceCenterY = 100; // 元の120から100に上げる
    int faceRadius = 80;

    // 顔の輪郭(円)
    M5.Lcd.fillCircle(faceCenterX, faceCenterY, faceRadius, TFT_YELLOW);

    // 耳
    int earSize = 60;    // 耳の幅
    int earHeight = 80;  // 耳の高さ
    int earXOffset = 50; // 耳の左右位置を内側に寄せる
    int earYOffset = 100; // 耳の上下位置

    // 左耳(外側)
    int leftEarX[] = {
        faceCenterX - earXOffset,                    // 頂点(上)
        faceCenterX - earXOffset - earSize / 2,      // 左下
        faceCenterX - earXOffset + earSize / 2       // 右下
    };
    int leftEarY[] = {
        faceCenterY - earYOffset,                    // 頂点(上)
        faceCenterY - earYOffset + earHeight,        // 左下
        faceCenterY - earYOffset + earHeight         // 右下
    };
    M5.Lcd.fillTriangle(leftEarX[0], leftEarY[0], leftEarX[1], leftEarY[1], leftEarX[2], leftEarY[2], TFT_YELLOW);

    // 右耳(外側)
    int rightEarX[] = {
        faceCenterX + earXOffset,                    // 頂点(上)
        faceCenterX + earXOffset - earSize / 2,      // 左下
        faceCenterX + earXOffset + earSize / 2       // 右下
    };
    int rightEarY[] = {
        faceCenterY - earYOffset,                    // 頂点(上)
        faceCenterY - earYOffset + earHeight,        // 左下
        faceCenterY - earYOffset + earHeight         // 右下
    };
    M5.Lcd.fillTriangle(rightEarX[0], rightEarY[0], rightEarX[1], rightEarY[1], rightEarX[2], rightEarY[2], TFT_YELLOW);

    // 耳の内側(ピンク色の三角形)
    // 左耳内側
    int leftInnerEarX[] = {
        leftEarX[0],                                         // 頂点(上)
        leftEarX[0] - (earSize / 4),                         // 左下
        leftEarX[0] + (earSize / 4)                          // 右下
    };
    int leftInnerEarY[] = {
        leftEarY[0] + 10,                                    // 頂点(上)
        leftEarY[0] + earHeight - 10,                        // 左下
        leftEarY[0] + earHeight - 10                         // 右下
    };
    M5.Lcd.fillTriangle(leftInnerEarX[0], leftInnerEarY[0], leftInnerEarX[1], leftInnerEarY[1], leftInnerEarX[2], leftInnerEarY[2], TFT_PINK);

    // 右耳内側
    int rightInnerEarX[] = {
        rightEarX[0],                                        // 頂点(上)
        rightEarX[0] - (earSize / 4),                        // 左下
        rightEarX[0] + (earSize / 4)                         // 右下
    };
    int rightInnerEarY[] = {
        rightEarY[0] + 10,                                   // 頂点(上)
        rightEarY[0] + earHeight - 10,                       // 左下
        rightEarY[0] + earHeight - 10                        // 右下
    };
    M5.Lcd.fillTriangle(rightInnerEarX[0], rightInnerEarY[0], rightInnerEarX[1], rightInnerEarY[1], rightInnerEarX[2], rightInnerEarY[2], TFT_PINK);

    // 目
    M5.Lcd.fillCircle(faceCenterX - 30, faceCenterY - 10, 10, TFT_BLACK); // 左目
    M5.Lcd.fillCircle(faceCenterX + 30, faceCenterY - 10, 10, TFT_BLACK); // 右目

    // 鼻
    M5.Lcd.fillTriangle(faceCenterX, faceCenterY + 10, faceCenterX - 10, faceCenterY + 30, faceCenterX + 10, faceCenterY + 30, TFT_PINK);

    // ひげ
    M5.Lcd.drawLine(faceCenterX - 20, faceCenterY + 20, faceCenterX - 60, faceCenterY + 10, TFT_BLACK); // 左上ひげ
    M5.Lcd.drawLine(faceCenterX - 20, faceCenterY + 30, faceCenterX - 60, faceCenterY + 30, TFT_BLACK); // 左中ひげ
    M5.Lcd.drawLine(faceCenterX - 20, faceCenterY + 40, faceCenterX - 60, faceCenterY + 50, TFT_BLACK); // 左下ひげ
    M5.Lcd.drawLine(faceCenterX + 20, faceCenterY + 20, faceCenterX + 60, faceCenterY + 10, TFT_BLACK); // 右上ひげ
    M5.Lcd.drawLine(faceCenterX + 20, faceCenterY + 30, faceCenterX + 60, faceCenterY + 30, TFT_BLACK); // 右中ひげ
    M5.Lcd.drawLine(faceCenterX + 20, faceCenterY + 40, faceCenterX + 60, faceCenterY + 50, TFT_BLACK); // 右下ひげ

    // モードによって表情を変える
    if (mode == NORMAL_MODE) {
        // 口(にっこり)を半円で表現
        M5.Lcd.drawCircle(faceCenterX, faceCenterY + 50, 20, TFT_BLACK); // 大きな円
        M5.Lcd.fillRect(faceCenterX - 20, faceCenterY + 50, 40, 20, TFT_YELLOW); // 上半分を消す
    } else if (mode == POSITION_MODE) {
        // 口(大笑い)を楕円で表現
        M5.Lcd.fillEllipse(faceCenterX, faceCenterY + 60, 20, 15, TFT_BLACK);
    } else if (mode == SPEED_MODE) {
        // 口(驚き)を小さな円で表現
        M5.Lcd.fillCircle(faceCenterX, faceCenterY + 50, 10, TFT_BLACK);
    } else if (mode == SERVO_MODE) {
        // ウィンク
        M5.Lcd.fillRect(faceCenterX - 40, faceCenterY - 15, 20, 10, TFT_YELLOW); // 左目を消す
        M5.Lcd.drawLine(faceCenterX - 40, faceCenterY - 10, faceCenterX - 20, faceCenterY - 10, TFT_BLACK); // 左目の線
        // 口(にっこり)
        M5.Lcd.drawCircle(faceCenterX, faceCenterY + 50, 20, TFT_BLACK); // 大きな円
        M5.Lcd.fillRect(faceCenterX - 20, faceCenterY + 50, 40, 20, TFT_YELLOW); // 上半分を消す
    }

    displayButtons();
    displayMode();
}

void NormalMode() {
    if (M5.BtnA.wasPressed() || M5.BtnC.wasPressed()) {
        if (M5.BtnA.wasPressed()) {
            for (size_t i = 1; i < 5; i++) {
                int8_t speed = 125;
                // モーター3と4の回転方向を反対にする
                if (i == 3 || i == 4) {
                    speed = -speed;
                }
                base_x.SetMotorSpeed(i, speed);
            }
        }

        if (M5.BtnC.wasPressed()) {
            for (size_t i = 1; i < 5; i++) {
                int8_t speed = -125;
                // モーター3と4の回転方向を反対にする
                if (i == 3 || i == 4) {
                    speed = -speed;
                }
                base_x.SetMotorSpeed(i, speed);
            }
        }
        displayCatFace();
    }
}

void PositionMode() {
    if (M5.BtnA.wasPressed() || M5.BtnC.wasPressed()) {
        if (M5.BtnA.wasPressed()) {
            position_point += 200;
            for (size_t i = 1; i < 5; i++) {
                int32_t pos = position_point;
                // モーター3と4の回転方向を反対にする
                if (i == 3 || i == 4) {
                    pos = -pos;
                }
                base_x.SetPositionPoint(i, pos);
            }
        }

        if (M5.BtnC.wasPressed()) {
            max_speed += 20;
            if (max_speed > 120) {
                max_speed = 20;
            }
            for (size_t i = 1; i < 5; i++) {
                base_x.SetPositionPIDMaxSpeed(i, max_speed);
            }
        }
        displayCatFace();
    }
}

void SpeedMode() {
    if (M5.BtnA.wasPressed() || M5.BtnC.wasPressed()) {
        if (M5.BtnA.wasPressed()) {
            speed_point += 2;
            for (size_t i = 1; i < 5; i++) {
                int8_t spd_point = speed_point;
                // モーター3と4の回転方向を反対にする
                if (i == 3 || i == 4) {
                    spd_point = -spd_point;
                }
                base_x.SetSpeedPoint(i, spd_point);
            }
        }

        if (M5.BtnC.wasPressed()) {
            speed_point -= 2;
            for (size_t i = 1; i < 5; i++) {
                int8_t spd_point = speed_point;
                // モーター3と4の回転方向を反対にする
                if (i == 3 || i == 4) {
                    spd_point = -spd_point;
                }
                base_x.SetSpeedPoint(i, spd_point);
            }
        }
        displayCatFace();
    }
}

void ServoMode() {
    if (M5.BtnA.wasPressed() || M5.BtnC.wasPressed()) {
        if (M5.BtnA.wasPressed()) {
            // サーボ角度を増加
            servo1_angle += 10;
            servo2_angle += 10;
            if (servo1_angle > 180) servo1_angle = 180;
            if (servo2_angle > 180) servo2_angle = 180;
            base_x.SetServoAngle(1, servo1_angle);
            base_x.SetServoAngle(2, servo2_angle);
        }

        if (M5.BtnC.wasPressed()) {
            // サーボ角度を減少
            if (servo1_angle >= 10) servo1_angle -= 10;
            else servo1_angle = 0;
            if (servo2_angle >= 10) servo2_angle -= 10;
            else servo2_angle = 0;
            base_x.SetServoAngle(1, servo1_angle);
            base_x.SetServoAngle(2, servo2_angle);
        }
        displayCatFace();
    }
}

void loop() {
    M5.update();

    // モード切り替え
    if (M5.BtnB.wasPressed()) {
        mode = (mode + 1) % 4; // 0から3までのモードを循環
        for (size_t i = 1; i < 5; i++) {
            base_x.SetMotorSpeed(i, 0);
            base_x.SetEncoderValue(i, 0);
            base_x.SetMode(i, mode);
        }
        displayCatFace();
    }

    // 現在のモードに応じた処理を実行
    if (mode == NORMAL_MODE) {
        NormalMode();
    } else if (mode == POSITION_MODE) {
        PositionMode();
    } else if (mode == SPEED_MODE) {
        SpeedMode();
    } else if (mode == SERVO_MODE) {
        ServoMode();
    }

    delay(10);
}

LEGO or M5Stack 作品集

image.png
https://youtu.be/h2LnfyVS4_4
https://youtu.be/ODmU4Jf7l6w
https://youtu.be/h6uOs0cGyko
https://youtu.be/D5gN299WGCI
https://youtu.be/qYz9lo_hV8I
https://youtu.be/2TezJLH2dQo
https://youtu.be/psEWBQj8vW4

LEGO NTX Mindstorms モーターコネクター

image.png

LEGO Mindstormsの8極8芯コネクタのピン配列
Pin 1: モーター駆動用(PWMの一部)
Pin 2: モーター駆動用(PWMのもう一方の部分)
Pin 3: グラウンド(GND)
Pin 4: 電源(+4.3V または +5V)
Pin 5: タコメータ(エンコーダ)信号 A
Pin 6: タコメータ(エンコーダ)信号 B
Pin 7: ID ピン(接続されたデバイスの識別用)
Pin 8: 通信ピン(I2Cまたはデータ通信に使われることもある)
各ピンの役割について
モーター駆動用(Pin 1 & 2): モーターの駆動にはPWM(パルス幅変調)信号が使用されます。これにより、モーターの回転速度や方向を制御することができます。
グラウンド(Pin 3): 回路の基準となる電位です。ほかの電気部品と共通に接続します。
電源(Pin 4): モーターやセンサーに電源を供給します。
タコメータ信号 A & B(Pin 5 & 6): これらはエンコーダ信号であり、モーターの回転位置や回転方向を検出するために使用されます。ロータリーエンコーダによる信号を得ることで、モーターの動きを細かく制御できます。
ID ピン(Pin 7): 接続されたデバイスの種類を特定するために使用されます。これにより、モーター、センサー、その他のデバイスを自動的に識別できます。
通信ピン(Pin 8): データ通信のためのピンであり、必要に応じてI2Cプロトコルのような方法でセンサーやモーターとやり取りすることがあります。
使用されるケーブルについて
LEGO Mindstormsは一般的に8極8芯の「RJ45」コネクターを使用しており、見た目はイーサネットケーブルのコネクターに似ています。しかし、実際の信号の割り当てや利用されるプロトコルは独自のものになっていることが多いため、市販のイーサネットケーブルをそのまま使うと正しく動作しない場合があります。LEGOの専用ケーブルを使用するか、ピン配置を確認した上で自作することが必要です。

また、これらの信号は多くのセンサーやモーターを細かく制御するために非常に重要であり、特にエンコーダ信号を活用することで精度の高い制御が可能になります。

もし、特定のピン接続の利用方法や回路の組み方についてもっと詳細が必要であれば教えてください。必要な用途に応じて、さらに細かい情報をお伝えできます。

+---------------------+
| 1 2 3 4 5 6 7 8 | <- ピン番号
+---------------------+
| PWM PWM GND +V A B ID COM | <- 信号名称
これを元にして、詳細な回路図を作成する場合には、回路設計ソフトウェア(例えばFritzing、KiCAD、Eagleなど)を使用して描画する必要があります。

もしPythonで簡易的な回路図を描画するコード例などが必要であれば、それもお手伝いできますが、どういたしましょうか?

あなた:
NXT モーター は この結線ですか
ChatGPT:
ChatGPT
LEGO Mindstorms NXTモーターの結線は、EV3モーターと似ていますが、若干の違いがあります。以下はNXTモーターの8極8芯コネクターの結線に関する情報です。

NXT モーターの8極8芯コネクターのピン配列
NXTモーターには、同じく8極8芯のRJ12タイプのコネクターが使用されています。このコネクターはEV3モーターのものと形状が似ているため、混同されがちですが、以下のようにピンの機能が設定されています。

Pin 1: モーター駆動用(PWMの一部)
Pin 2: モーター駆動用(PWMのもう一方の部分)
Pin 3: グラウンド(GND)
Pin 4: 電源(+4.3V または +5V)
Pin 5: エンコーダのA相信号(ロータリーエンコーダの1つの信号)
Pin 6: エンコーダのB相信号(ロータリーエンコーダのもう1つの信号)
Pin 7: (未使用または将来的な拡張のためのピン)
Pin 8: (未使用または将来的な拡張のためのピン)
重要なポイント
モーター駆動(Pin 1 & 2):

モーターはPWM(パルス幅変調)によって制御されます。これによりモーターの回転速度や方向を精密に制御することができます。
エンコーダ信号(Pin 5 & 6):

エンコーダ信号は、ロータリーエンコーダの出力で、これによってモーターの位置や回転速度、回転方向を検知することができます。NXTモーターにはロータリーエンコーダが内蔵されており、ロボットの精密な動作を実現するために利用されています。
電源およびGND(Pin 3 & 4):

モーターに電源を供給し、適切な動作をするための基本的な配線です。
NXTのモーターとEV3のモーターは似ていますが、EV3のモーターの方が多くの機能をサポートしており、内部エンコーダの精度も高いため、より高度な制御が可能です。また、EV3モーターにはより新しいセンサーと通信するための拡張ピンも含まれています。

違いと互換性
NXTモーターとEV3モーターは、外部的には似たコネクタを使っているため、相互に接続して利用することも可能です。ただし、エンコーダの精度やピン配置の細部に若干の違いがあるため、特に精密な動作が必要な場合には注意が必要です。

互換性:
EV3のインテリジェントブリック(ブロック)ではNXTモーターもサポートされており、同じコネクターで接続できますが、NXTブリックにEV3モーターを接続する場合、すべての機能がサポートされないことがあります。
もし具体的な接続図や制御プログラムについて興味がある場合は、詳細を教えてください。それに基づいてより具体的な説明やサポートが可能です。

あなた:
何が違いますか
ChatGPT:
ChatGPT
LEGO Mindstorms NXTモーターとEV3モーターの違いについて、具体的なハードウェア構造とコネクタの結線および機能の面で見ていきましょう。

  1. 内部エンコーダの精度
    NXTモーター:
    NXTモーターには ロータリーエンコーダ が内蔵されており、回転角度を検出できます。しかし、NXTのエンコーダは**1回転あたり360パルス(1度あたり1パルス)**の精度です。これは、NXTモーターがそれなりの精度で位置を検知できることを意味しますが、EV3ほどの精密さはありません。
    EV3モーター:
    EV3モーターにはより高精度の ロータリーエンコーダ が搭載されています。1回転あたり約720パルス(0.5度あたり1パルス) という精度で、NXTモーターの2倍の分解能を持っています。これにより、EV3モーターはより精密に位置や速度の制御が可能です。
  2. コネクタの配線とピンの役割
    NXTモーターのピン配置:

NXTモーターも8極のコネクタを持っていますが、その多くは基本的なモーター駆動とエンコーダ信号のために使用されています。実際に使用されているのは以下のピンです:
Pin 1 & 2: モーター駆動用(PWM信号)
Pin 3: GND(グラウンド)
Pin 4: 電源(+5V)
Pin 5 & 6: エンコーダのA相・B相信号(モーターの回転位置検出)
Pin 7 & 8: NXTモーターの場合、これらのピンは基本的に未使用であることが多く、将来的な拡張のために予約されていることもあります。
EV3モーターのピン配置:

EV3モーターのピン配置は似てはいますが、より高度な制御が可能になるよう追加機能が含まれています。ピンの役割は以下の通りです:
Pin 1 & 2: モーター駆動用(PWM信号)
Pin 3: GND(グラウンド)
Pin 4: 電源(+4.3Vまたは+5V)
Pin 5 & 6: より精密なエンコーダ信号(A相とB相)
Pin 7: デバイスID(接続されたデバイスを識別するためのIDピン)
Pin 8: 通信用ピン(将来的な拡張やI2C通信に使われる可能性がある)
このPin 7とPin 8が大きな違いです。EV3モーターではこれらのピンがセンサーやデバイス識別、通信のために利用されていますが、NXTでは主に未使用です。この違いにより、EV3モーターはNXTよりも多機能であり、EV3ブロックは接続されたモーターやセンサーを自動的に識別し、より複雑な動作が可能になります。

  1. モーター性能
    NXTモーター:

比較的シンプルで頑丈な作りです。NXTモーターは一般的なロボティクス用途で十分なトルクと速度を提供しますが、非常に精密な動作には適していない場合があります。
EV3モーター:

EV3モーターは改良されたトルクと速度制御が可能で、エンコーダも高精度のため、より複雑で精密なロボット動作を可能にしています。また、モーター自体の反応性も高く、複数のモーターを同期して動作させる場合にその精度の差が顕著に表れます。
4. 互換性と使い方の違い
互換性:
EV3のインテリジェントブリック(EV3ブロック)はNXTモーターをサポートしています。しかし、EV3ブロックにNXTモーターを接続すると、EV3モーターほど精密には制御できないため、特に高精度が求められるプロジェクトには不向きです。
NXTブロックもEV3モーターを接続できますが、全ての機能をサポートしていないことがあるため、モーターの精度や反応が期待通りでない可能性があります。
結論として
NXTモーターとEV3モーターの主な違いはエンコーダの精度、ピン配置の機能性、およびトルクと速度の制御です。EV3モーターはより高機能で高精度な制御を可能にし、特に精密な制御や複数モーターの同期動作が必要なプロジェクトに適しています。一方で、NXTモーターはシンプルで耐久性があり、基本的なロボティクス学習やプロジェクトには十分な性能を持っています。

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?