├── library.properties ├── .gitignore ├── .github ├── workflows │ ├── Arduino-Lint-Check.yml │ └── clang-format-check.yml └── ISSUE_TEMPLATE │ └── bug-report.yml ├── library.json ├── src ├── unit_roller_common.cpp ├── unit_roller_common.hpp ├── unit_rolleri2c.cpp ├── unit_roller485.hpp ├── unit_rollercan.cpp └── unit_rolleri2c.hpp ├── examples ├── can │ ├── sensor │ │ ├── readSht3x │ │ │ └── readSht3x.ino │ │ ├── readUltrasonic │ │ │ └── readUltrasonic.ino │ │ ├── readScd4x │ │ │ └── readScd4x.ino │ │ └── readTof │ │ │ └── readTof.ino │ ├── motor │ │ └── motor.ino │ └── slaveMotor │ │ └── slaveMotor.ino ├── rs485 │ ├── sensor │ │ ├── readSht3x │ │ │ └── readSht3x.ino │ │ ├── readUltrasonic │ │ │ └── readUltrasonic.ino │ │ ├── readTof │ │ │ └── readTof.ino │ │ └── readScd4x │ │ │ └── readScd4x.ino │ ├── motor │ │ └── motor.ino │ └── slaveMotor │ │ └── slaveMotor.ino └── i2c │ ├── encoder_calibration │ └── encoder_calibration.ino │ └── motor │ └── motor.ino ├── LICENSE ├── README.md └── .clang-format /library.properties: -------------------------------------------------------------------------------- 1 | name=M5UnitRoller 2 | version=0.0.1 3 | author=M5Stack 4 | maintainer=M5Stack 5 | sentence=Library for M5Stack M5Unit Roller 6 | paragraph=M5Stack, M5UnitRoller, See more on http://M5Stack.com 7 | category=Display 8 | url=https://github.com/m5stack/M5Unit-Roller.git 9 | architectures=esp32 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /.github/workflows/Arduino-Lint-Check.yml: -------------------------------------------------------------------------------- 1 | name: Arduino Lint Check 2 | on: 3 | push: 4 | branches: [ master ] 5 | pull_request: 6 | branches: [ master ] 7 | jobs: 8 | lint: 9 | name: Lint Check 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: arduino/arduino-lint-action@v1 14 | with: 15 | library-manager: update 16 | compliance: strict 17 | project-type: all -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "M5UnitRoller", 3 | "description": "Library for M5Stack M5Unit Roller", 4 | "keywords": "M5UnitRoller", 5 | "authors": { 6 | "name": "M5Stack", 7 | "url": "http://www.m5stack.com" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/m5stack/M5Unit-Roller.git" 12 | }, 13 | "version": "0.0.1", 14 | "frameworks": [ 15 | "arduino" 16 | ], 17 | "platforms": [ 18 | "espressif32", 19 | "native" 20 | ] 21 | 22 | } -------------------------------------------------------------------------------- /src/unit_roller_common.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | *SPDX-License-Identifier: MIT 5 | */ 6 | 7 | #include "unit_roller_common.hpp" 8 | 9 | bool mutexLocked = false; 10 | void acquireMutex() 11 | { 12 | while (mutexLocked) { 13 | delay(1); 14 | } 15 | mutexLocked = true; 16 | } 17 | 18 | void releaseMutex() 19 | { 20 | mutexLocked = false; 21 | } 22 | 23 | int32_t handleValue(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) 24 | { 25 | int32_t newNumerical = 0; 26 | // Combine bytes to form the encoder value 27 | newNumerical |= ((int32_t)byte0); // LSB 28 | newNumerical |= ((int32_t)byte1 << 8); 29 | newNumerical |= ((int32_t)byte2 << 16); 30 | newNumerical |= ((int32_t)byte3 << 24); // MSB 31 | return newNumerical; 32 | } -------------------------------------------------------------------------------- /examples/can/sensor/readSht3x/readSht3x.ino: -------------------------------------------------------------------------------- 1 | #include "unit_rollercan.hpp" 2 | #include 3 | UnitRollerCAN rollercan; // Create a UNIT_ROLLERCAN object 4 | #define motorID 0xA8 5 | #define sht3xI2cAddres 0x44 6 | uint8_t data[8] = {sht3xI2cAddres, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 7 | 8 | void setup() 9 | { 10 | M5.begin(); 11 | Serial.begin(115200); 12 | Serial.println("ESP32-Arduino-CAN"); 13 | rollercan.beginCAN(1000000, 16, 17); 14 | } 15 | 16 | void loop() 17 | { 18 | rollercan.writeMotorRawParameter(motorID, sht3xI2cAddres, 0x2c, 0, 1, 0x06); 19 | rollercan.sendData(motorID, ROLLERCAN_READ_I2C_RAW_CMD, 0, data); 20 | rollercan.receiveData(); 21 | float cTemp = ((((rollercan.readData[0] * 256.0) + rollercan.readData[1]) * 175) / 65535.0) - 45; 22 | float humidity = ((((rollercan.readData[3] * 256.0) + rollercan.readData[4]) * 100) / 65535.0); 23 | Serial.printf("cTemp : %2f \n", cTemp); 24 | Serial.printf("humidity: %2f %\n", humidity); 25 | delay(3000); 26 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 M5Stack Technology CO LTD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/can/sensor/readUltrasonic/readUltrasonic.ino: -------------------------------------------------------------------------------- 1 | #include "unit_rollercan.hpp" 2 | #include 3 | UnitRollerCAN rollercan; // Create a UNIT_ROLLERCAN object 4 | #define motorID 0xA8 5 | #define ultrasonicI2cAddress 0x57 6 | uint8_t data[8] = {ultrasonicI2cAddress, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 7 | void setup() 8 | { 9 | M5.begin(); 10 | Serial.begin(115200); 11 | Serial.println("ESP32-Arduino-CAN"); 12 | rollercan.beginCAN(1000000, 16, 17); 13 | } 14 | 15 | void loop() 16 | { 17 | rollercan.writeMotorRawParameter(motorID, ultrasonicI2cAddress, 0x01, 0, 0, 0x00); 18 | data[1] = 3; 19 | // This delay is necessary to ensure that there is enough time for the device to turn on the ranging 20 | delay(300); 21 | rollercan.sendData(motorID, ROLLERCAN_READ_I2C_RAW_CMD, 0, data); 22 | rollercan.receiveData(); 23 | float distance = 24 | ((((rollercan.readData[0] * 256.0) + rollercan.readData[1]) * 256.0) + rollercan.readData[2]) / 10000.0; 25 | if (distance > 450.0) { 26 | distance = 450.00; 27 | } 28 | Serial.printf("distance: %2f cm\n", distance); 29 | delay(5000); 30 | } 31 | -------------------------------------------------------------------------------- /examples/can/sensor/readScd4x/readScd4x.ino: -------------------------------------------------------------------------------- 1 | #include "unit_rollercan.hpp" 2 | #include 3 | UnitRollerCAN rollercan; // Create a UNIT_ROLLERCAN object 4 | #define motorID 0xA8 5 | #define scd4xI2cAddress 0x62 6 | uint8_t data[8] = {scd4xI2cAddress, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 7 | void setup() 8 | { 9 | M5.begin(); 10 | Serial.begin(115200); 11 | Serial.println("ESP32-Arduino-CAN"); 12 | rollercan.beginCAN(1000000, 16, 17); 13 | rollercan.writeMotorRawParameter(motorID, scd4xI2cAddress, 0x21, 0, 1, 0xB1); 14 | } 15 | 16 | void loop() 17 | { 18 | rollercan.writeMotorRawParameter(motorID, scd4xI2cAddress, 0xEC, 0, 1, 0x05); 19 | 20 | rollercan.writeMotorRawParameter(motorID, scd4xI2cAddress, 0x0C, 0, 0, 0x00); 21 | data[1] = 8; 22 | rollercan.sendData(motorID, ROLLERCAN_READ_I2C_RAW_CMD, 0, data); 23 | 24 | rollercan.receiveData(); 25 | float co2 = (float)(rollercan.readData[0] << 8 | rollercan.readData[1]); 26 | float temperature = -45 + 175 * (float)(rollercan.readData[3] << 8 | rollercan.readData[4]) / 65536; 27 | float humidity = 100 * (float)(rollercan.readData[6] << 8 | rollercan.readData[7]) / 65536; 28 | Serial.printf("co2 : %2f\n", co2); 29 | Serial.printf("temperature : %2f\n", temperature); 30 | Serial.printf("humidity: %2f\n", humidity); 31 | delay(5000); 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/clang-format-check.yml: -------------------------------------------------------------------------------- 1 | name: clang-format Check 2 | 3 | env: 4 | INCLUDE_REGEX: ^.*\.((((c|C)(c|pp|xx|\+\+)?$)|((h|H)h?(pp|xx|\+\+)?$))|(inl|ino|pde|proto|cu))$ 5 | 6 | on: 7 | push: 8 | paths: 9 | - '**.ino' 10 | - '**.cpp' 11 | - '**.hpp' 12 | - '**.h' 13 | - '**.c' 14 | - '**.inl' 15 | - '**clang-format-check.yml' 16 | pull_request: 17 | - '**.ino' 18 | - '**.cpp' 19 | - '**.hpp' 20 | - '**.h' 21 | - '**.c' 22 | - '**.inl' 23 | - '**clang-format-check.yml' 24 | 25 | jobs: 26 | formatting-check: 27 | name: Formatting Check 28 | runs-on: ubuntu-latest 29 | strategy: 30 | matrix: 31 | path: 32 | - check: './' # path to include 33 | exclude: '' # path to exclude 34 | #- check: 'src' 35 | # exclude: '(Fonts)' # Exclude file paths containing "Fonts" 36 | #- check: 'examples' 37 | # exclude: '' 38 | 39 | steps: 40 | - name: Checkout 41 | uses: actions/checkout@v4 42 | with: 43 | ref: ${{ github.event.pull_request.head.sha }} 44 | 45 | - name: Run clang-format style check for C/C++/Protobuf programs. 46 | uses: jidicula/clang-format-action@v4.10.2 # Using include-regex 10.x or later 47 | with: 48 | clang-format-version: '13' 49 | check-path: ${{ matrix.path['check'] }} 50 | exclude-regex: ${{ matrix.path['exclude'] }} 51 | include-regex: ${{ env.INCLUDE_REGEX }} 52 | -------------------------------------------------------------------------------- /examples/rs485/sensor/readSht3x/readSht3x.ino: -------------------------------------------------------------------------------- 1 | #include "unit_roller485.hpp" 2 | #include 3 | #include 4 | 5 | UnitRoller485 Roller485; // Create a UnitRoller485 object 6 | HardwareSerial mySerial(1); // Create a hardware serial port object 7 | #define motor485Id 0x00 8 | #define sht3xI2cAddress 0x44 9 | uint8_t readBuffer[128]; 10 | static uint8_t sht3xWrite[] = {0x2C, 0x06}; 11 | void setup() 12 | { 13 | M5.begin(); 14 | // Call the begin function and pass arguments 15 | Roller485.begin(&mySerial, 115200, SERIAL_8N1, 16, 17, -1, false, 10000UL, 112U); 16 | } 17 | 18 | void loop() 19 | { 20 | Roller485.writeI2c(motor485Id, sht3xI2cAddress, sht3xWrite, sizeof(sht3xWrite), 0); 21 | int result = Roller485.readI2c(motor485Id, sht3xI2cAddress, 0x06, readBuffer); 22 | if (result > 0) { 23 | for (size_t i = 0; i < result; i++) { 24 | Serial.print("0x"); 25 | Serial.print(readBuffer[i], HEX); 26 | Serial.print(" "); 27 | } 28 | Serial.print("\n"); 29 | float cTemp = ((((readBuffer[8] * 256.0) + readBuffer[9]) * 175) / 65535.0) - 45; 30 | // fTemp = (cTemp * 1.8) + 32; 31 | float humidity = ((((readBuffer[11] * 256.0) + readBuffer[12]) * 100) / 65535.0); 32 | Serial.printf("cTemp : %2f \n", cTemp); 33 | Serial.printf("humidity: %2f %\n", humidity); 34 | 35 | } else { 36 | // Print error code 37 | Serial.print("readI2c failed with error code: "); 38 | Serial.println(result); 39 | } 40 | delay(3000); 41 | } 42 | -------------------------------------------------------------------------------- /examples/rs485/sensor/readUltrasonic/readUltrasonic.ino: -------------------------------------------------------------------------------- 1 | #include "unit_roller485.hpp" 2 | #include 3 | #include 4 | 5 | UnitRoller485 Roller485; // Create a UnitRoller485 object 6 | HardwareSerial mySerial(1); // Create a hardware serial port object 7 | #define motor485Id 0x00 8 | #define ultrasonicI2cAddress 0x57 9 | static uint8_t ultrasonicWrite[] = {0x01, 0x01}; 10 | uint8_t readBuffer[128]; 11 | 12 | void setup() 13 | { 14 | M5.begin(); 15 | // Call the begin function and pass arguments 16 | Roller485.begin(&mySerial, 115200, SERIAL_8N1, 16, 17, -1, false, 10000UL, 112U); 17 | } 18 | 19 | void loop() 20 | { 21 | uint8_t errorWrite = 22 | Roller485.writeI2c(motor485Id, ultrasonicI2cAddress, ultrasonicWrite, sizeof(ultrasonicWrite), 1); 23 | if (errorWrite != 1) { 24 | // Print error code 25 | Serial.print("writeI2c failed with error code: "); 26 | Serial.println(errorWrite); 27 | } 28 | int result = Roller485.readI2c(motor485Id, ultrasonicI2cAddress, 0x03, readBuffer); 29 | if (result > 0) { 30 | for (size_t i = 0; i < result; i++) { 31 | Serial.print("0x"); 32 | Serial.print(readBuffer[i], HEX); 33 | Serial.print(" "); 34 | } 35 | Serial.print("\n"); 36 | float distance = ((((readBuffer[8] * 256.0) + readBuffer[9]) * 256.0) + readBuffer[10]) / 10000.0; 37 | if (distance > 450.0) { 38 | distance = 450.00; 39 | } 40 | Serial.printf("distance: %2f cm\n", distance); 41 | 42 | } else { 43 | // Print error code 44 | Serial.print("readI2c failed with error code: "); 45 | Serial.println(result); 46 | } 47 | delay(3000); 48 | } 49 | -------------------------------------------------------------------------------- /examples/can/sensor/readTof/readTof.ino: -------------------------------------------------------------------------------- 1 | #include "unit_rollercan.hpp" 2 | #include 3 | UnitRollerCAN rollercan; // Create a UNIT_ROLLERCAN object 4 | #define motorID 0xA8 5 | #define tofI2cAddress 0x29 6 | uint8_t data[8] = {tofI2cAddress, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 7 | uint16_t makeuint16(int lsb, int msb) 8 | { 9 | return ((msb & 0xFF) << 8) | (lsb & 0xFF); 10 | } 11 | void setup() 12 | { 13 | M5.begin(); 14 | Serial.begin(115200); 15 | Serial.println("ESP32-Arduino-CAN"); 16 | rollercan.beginCAN(1000000, 16, 17); 17 | } 18 | 19 | void loop() 20 | { 21 | rollercan.writeMotorRawParameter(motorID, tofI2cAddress, 0x00, 0, 1, 0x01); 22 | 23 | rollercan.writeMotorRawParameter(motorID, tofI2cAddress, 0x14, 0, 0, 0x00); 24 | data[1] = 1; 25 | rollercan.sendData(motorID, ROLLERCAN_READ_I2C_RAW_CMD, 0, data); 26 | 27 | rollercan.receiveData(); 28 | int DeviceRangeStatusInternal = ((rollercan.readData[0] & 0x78) >> 3); 29 | 30 | rollercan.writeMotorRawParameter(motorID, tofI2cAddress, 0x1A, 0, 0, 0x00); 31 | data[1] = 6; 32 | rollercan.sendData(motorID, ROLLERCAN_READ_I2C_RAW_CMD, 0, data); 33 | rollercan.receiveData(); 34 | uint16_t acnt = makeuint16(rollercan.readData[1], rollercan.readData[0]); 35 | uint16_t scnt = makeuint16(rollercan.readData[3], rollercan.readData[2]); 36 | uint16_t dist = makeuint16(rollercan.readData[5], rollercan.readData[4]); 37 | Serial.print("ambient count: "); 38 | Serial.println(acnt); 39 | Serial.print("signal count: "); 40 | Serial.println(scnt); 41 | Serial.print("distance: "); 42 | Serial.println(dist); 43 | Serial.print("status: "); 44 | Serial.println(DeviceRangeStatusInternal); 45 | delay(3000); 46 | } 47 | -------------------------------------------------------------------------------- /examples/i2c/encoder_calibration/encoder_calibration.ino: -------------------------------------------------------------------------------- 1 | /* 2 | *SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | *SPDX-License-Identifier: MIT 5 | */ 6 | #include "unit_rolleri2c.hpp" 7 | #include 8 | 9 | #define ROLLER_CALIBRATION_DELAY 10000 10 | 11 | UnitRollerI2C RollerI2C; // Create a UNIT_ROLLERI2C object 12 | 13 | uint8_t is_roller_valid = 0; 14 | uint8_t is_roller_calibrated = 0; 15 | uint32_t roller_start_delay_counter = 0; 16 | 17 | void setup() 18 | { 19 | M5.begin(); 20 | if (RollerI2C.begin(&Wire, 0x64, 21, 22, 400000)) { 21 | is_roller_valid = 1; 22 | roller_start_delay_counter = millis(); 23 | } 24 | } 25 | 26 | void loop() 27 | { 28 | if (is_roller_valid) { 29 | if (millis() - roller_start_delay_counter < ROLLER_CALIBRATION_DELAY) { 30 | printf("Calibration will start after %dS\n", 31 | (roller_start_delay_counter - (millis() - roller_start_delay_counter)) / 1000); 32 | } else { 33 | if (!is_roller_calibrated) { 34 | printf("Start encoder calibration\n"); 35 | RollerI2C.setOutput(0); 36 | delay(100); 37 | RollerI2C.startAngleCal(); 38 | delay(100); 39 | printf("Calibrationing...\n"); 40 | while (RollerI2C.getCalBusyStatus()) { 41 | printf("Calibrationing...\n"); 42 | } 43 | RollerI2C.updateAngleCal(); 44 | printf("Encoder calibration done\n"); 45 | delay(500); 46 | RollerI2C.setOutput(0); 47 | RollerI2C.setMode(ROLLER_MODE_SPEED); 48 | RollerI2C.setSpeed(240000); 49 | RollerI2C.setSpeedMaxCurrent(100000); 50 | RollerI2C.setOutput(1); 51 | is_roller_calibrated = 1; 52 | } 53 | } 54 | } else { 55 | printf("No roller485 dectected\n"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /examples/rs485/sensor/readTof/readTof.ino: -------------------------------------------------------------------------------- 1 | #include "unit_roller485.hpp" 2 | #include 3 | #include 4 | 5 | UnitRoller485 Roller485; // Create a UnitRoller485 object 6 | HardwareSerial mySerial(1); // Create a hardware serial port object 7 | #define motor485Id 0x00 8 | #define tofI2cAddress 0x29 9 | uint8_t readBuffer[128]; 10 | static uint8_t tofWrite[] = {0x00, 0x01}; 11 | void setup() 12 | { 13 | M5.begin(); 14 | // Call the begin function and pass arguments 15 | Roller485.begin(&mySerial, 115200, SERIAL_8N1, 16, 17, -1, false, 10000UL, 112U); 16 | } 17 | 18 | void loop() 19 | { 20 | uint8_t errorWrite = Roller485.writeI2c(motor485Id, tofI2cAddress, tofWrite, sizeof(tofWrite), 0); 21 | if (errorWrite != 1) { 22 | // Print error code 23 | Serial.print("writeI2c failed with error code: "); 24 | Serial.println(errorWrite); 25 | } 26 | int result = Roller485.readI2c(motor485Id, tofI2cAddress, 0x00, 0x14, 0x00, 0x0C, readBuffer); 27 | if (result > 0) { 28 | for (size_t i = 0; i < result; i++) { 29 | Serial.print("0x"); 30 | Serial.print(readBuffer[i], HEX); 31 | Serial.print(" "); 32 | } 33 | Serial.print("\n"); 34 | float acnt = ((readBuffer[14] & 0xFF) << 8) | (readBuffer[15] & 0xFF); 35 | float scnt = ((readBuffer[16] & 0xFF) << 8) | (readBuffer[17] & 0xFF); 36 | float dist = ((readBuffer[18] & 0xFF) << 8) | (readBuffer[19] & 0xFF); 37 | int DeviceRangeStatusInternal = ((readBuffer[8] & 0x78) >> 3); 38 | Serial.printf("acnt : %2f\n", acnt); 39 | Serial.printf("scnt : %2f\n", scnt); 40 | Serial.printf("dist : %2f\n", dist); 41 | Serial.printf("DeviceRangeStatusInternal: %d\n", DeviceRangeStatusInternal); 42 | 43 | } else { 44 | // Print error code 45 | Serial.print("readI2c failed with error code: "); 46 | Serial.println(result); 47 | } 48 | delay(3000); 49 | } 50 | -------------------------------------------------------------------------------- /examples/rs485/sensor/readScd4x/readScd4x.ino: -------------------------------------------------------------------------------- 1 | #include "unit_roller485.hpp" 2 | #include 3 | #include 4 | 5 | UnitRoller485 Roller485; // Create a UnitRoller485 object 6 | HardwareSerial mySerial(1); // Create a hardware serial port object 7 | #define motor485Id 0x00 8 | #define scd4xI2cAddress 0x62 9 | uint8_t readBuffer[128]; 10 | static uint8_t scd4xSetup[] = {0x21, 0xB1}; 11 | static uint8_t scd4xWrite[] = {0xEC, 0x05}; 12 | void setup() 13 | { 14 | M5.begin(); 15 | // Call the begin function and pass arguments 16 | Roller485.begin(&mySerial, 115200, SERIAL_8N1, 16, 17, -1, false, 10000UL, 112U); 17 | // Set the sensor to return data every 5 seconds 18 | uint8_t errorSetup = Roller485.writeI2c(motor485Id, scd4xI2cAddress, scd4xSetup, sizeof(scd4xSetup), 0); 19 | if (errorSetup != 1) { 20 | // Print error code 21 | Serial.print("writeI2c setup failed with error code: "); 22 | Serial.println(errorSetup); 23 | } 24 | } 25 | 26 | void loop() 27 | { 28 | uint8_t errorWrite = Roller485.writeI2c(motor485Id, scd4xI2cAddress, scd4xWrite, sizeof(scd4xWrite), 0); 29 | if (errorWrite != 1) { 30 | // Print error code 31 | Serial.print("writeI2c failed with error code: "); 32 | Serial.println(errorWrite); 33 | } 34 | int result = Roller485.readI2c(motor485Id, scd4xI2cAddress, 0x0C, readBuffer); 35 | if (result > 0) { 36 | for (size_t i = 0; i < result; i++) { 37 | Serial.print("0x"); 38 | Serial.print(readBuffer[i], HEX); 39 | Serial.print(" "); 40 | } 41 | Serial.print("\n"); 42 | float co2 = (float)((uint16_t)readBuffer[8] << 8 | readBuffer[9]); 43 | float temperature = -45 + 175 * (float)((uint16_t)readBuffer[11] << 8 | readBuffer[12]) / 65536; 44 | float humidity = 100 * (float)((uint16_t)readBuffer[14] << 8 | readBuffer[15]) / 65536; 45 | Serial.printf("co2 : %2f\n", co2); 46 | Serial.printf("temperature : %2f\n", temperature); 47 | Serial.printf("humidity: %2f\n", humidity); 48 | 49 | } else { 50 | // Print error code 51 | Serial.print("readI2c failed with error code: "); 52 | Serial.println(result); 53 | } 54 | delay(5000); 55 | } 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unit Roller Series 2 | 3 | ## Overview 4 | 5 | ### SKU: U182 U182-Lite 6 | 7 | **Roller485 Unit** is an integrated brushless DC motor motion control kit designed for efficient motion control. It supports 6-16V DC power input (via PWR485 interface) or 5V input (via Grove interface) and can automatically adjust power coefficients to ensure optimal performance. It features a built-in **FOC** closed-loop drive system, utilizing a 3504 200KV brushless motor. Without forced cooling, it can operate with a maximum continuous phase current of 0.5A and a short-term current of 1A. The driver uses a magnetic encoder for feedback and supports current, speed, and position control, ensuring precise control. 8 | Additionally, the device is equipped with a 0.66-inch **OLED** display on the back to display the device's status in real-time. It also includes an RGB indicator light and function button for easy human-computer interaction. The product's base is designed with LEGO-compatible mounting holes and M3 screw holes, making it easy to assemble and integrate. Roller485 Unit’s hardware and software are fully open-source, supporting motion control and parameter adjustment through **RS485** or **I2C** buses. It also offers SWD and SWO debugging interfaces, providing developers with greater flexibility. This product is widely used in robotic joints, motion control, industrial automation, and visual demonstration projects. 9 | 10 | ### SKU: U188 U188-Lite 11 | 12 | **RollerCAN Unit** is a brushless DC motor motion control kit with multiple integrated control functions, designed for efficient motion control. It supports 6-16V DC power input (via the CAN (XT30) interface) or 5V input (via the Grove interface) and can automatically adjust the power factor to ensure optimal performance. It features a built-in **FOC** closed-loop drive system, using a 3504 200KV brushless motor. The maximum continuous operating phase current is 0.5A without forced cooling, and 1A for short-term. The driver uses a magnetic encoder for feedback and supports current, speed, and position triple-loop control, ensuring precise control. The unit’s shaft can optionally include a **slip ring**, allowing the Grove interface on the top to remain connected with the bottom, supporting 360° rotation while expanding additional modules at the top. This ensures power and data transmission through the rotating part. 13 | 14 | Additionally, the unit is equipped with a 0.66-inch OLED display on the back, which can display the device status in real-time. It also includes an RGB indicator and function button for easy human-machine interaction. The top and base are designed with LEGO-compatible mounting holes and M3 screw holes, making it easy to build and integrate quickly. RollerCAN Unit's hardware and software are fully open-source, supporting motion control and parameter adjustment via **CAN** or **I2C** buses, and it also provides SWD and SWO debugging interfaces, offering developers greater flexibility. This product is widely used in machine joints, motion control, industrial automation, and visual demonstration projects. 15 | 16 | ## Related Link 17 | 18 | - [U182 Document & Datasheet](https://docs.m5stack.com/en/unit/Unit-Roller485) 19 | - [U188 Document & Datasheet](https://docs.m5stack.com/en/unit/Unit-RollerCAN) 20 | 21 | ## License 22 | 23 | - [MIT](LICENSE) -------------------------------------------------------------------------------- /examples/rs485/motor/motor.ino: -------------------------------------------------------------------------------- 1 | #include "unit_roller485.hpp" 2 | #include 3 | #include 4 | 5 | UnitRoller485 Roller485; // Create a UnitRoller485 object 6 | HardwareSerial mySerial(1); // Create a hardware serial port object 7 | #define motor485Id 0x00 8 | uint8_t rgbValues[3]; // Array to store R, G, B values 9 | double speedPID[3]; // Array to P I D values 10 | void setup() 11 | { 12 | M5.begin(); 13 | // Call the begin function and pass arguments 14 | Roller485.begin(&mySerial, 115200, SERIAL_8N1, 16, 17, -1, false, 10000UL, 112U); 15 | // Set the motor mode to speed 16 | Roller485.setMode(motor485Id, ROLLER_MODE_SPEED); 17 | // Set speed Speed and current 18 | Roller485.setSpeedMode(motor485Id, 2400, 1200); 19 | // Set the motor to enable 20 | Roller485.setOutput(motor485Id, true); 21 | } 22 | 23 | void loop() 24 | { 25 | int errorCode = Roller485.setMode(motor485Id, ROLLER_MODE_SPEED); 26 | if (errorCode == 1) { 27 | // Successful operation 28 | Serial.println("setMode() successful."); 29 | } else { 30 | // Print error code 31 | Serial.print("setMode() failed with error code: "); 32 | Serial.println(errorCode); 33 | } 34 | delay(1000); 35 | 36 | int32_t temperature = Roller485.getActualTemp(motor485Id); 37 | Serial.printf("temperature: %d\n", temperature); 38 | delay(1000); 39 | int32_t vin = Roller485.getActualVin(motor485Id); 40 | Serial.printf("vin: %d\n", vin); 41 | delay(1000); 42 | int32_t encoder = Roller485.getEncoder(motor485Id); 43 | Serial.printf("encoder: %d\n", encoder); 44 | delay(1000); 45 | int rgbBrightness = Roller485.getRGBBrightness(motor485Id); 46 | Serial.printf("rgbBrightness: %d\n", rgbBrightness); 47 | delay(1000); 48 | int32_t motorId = Roller485.getMotorId(motor485Id); 49 | Serial.printf("motorId: %d\n", motorId); 50 | delay(1000); 51 | int32_t speed = Roller485.getActualSpeed(motor485Id); 52 | Serial.printf("speed: %d\n", speed); 53 | delay(1000); 54 | int32_t position = Roller485.getActualPosition(motor485Id); 55 | Serial.printf("position: %d\n", position); 56 | delay(1000); 57 | int32_t current = Roller485.getActualCurrent(motor485Id); 58 | Serial.printf("current: %d\n", current); 59 | delay(1000); 60 | int8_t mode = Roller485.getMode(motor485Id); 61 | Serial.printf("mode: %d\n", mode); 62 | delay(1000); 63 | int8_t status = Roller485.getStatus(motor485Id); 64 | Serial.printf("status: %d\n", status); 65 | delay(1000); 66 | int8_t error = Roller485.getError(motor485Id); 67 | Serial.printf("error: %d\n", error); 68 | int8_t errorRGB = Roller485.getRGB(motor485Id, rgbValues); 69 | if (errorRGB != 1) { 70 | // Print error code 71 | Serial.print("getRGB failed with error code: "); 72 | Serial.println(errorRGB); 73 | } else { 74 | printf("RGB values: R=%d, G=%d, B=%d\n", rgbValues[0], rgbValues[1], rgbValues[2]); 75 | } 76 | 77 | int8_t errorSpeedPID = Roller485.getSpeedPID(motor485Id, speedPID); 78 | if (errorSpeedPID != 1) { 79 | Serial.print("getSpeedPID failed with error code: "); 80 | Serial.println(errorSpeedPID); 81 | } else { 82 | printf("speedPID values: P=%.8lf, I=%.8lf, D=%.8lf\n", speedPID[0], speedPID[1], speedPID[2]); 83 | } 84 | 85 | delay(1000); 86 | } 87 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | # Source: 2 | # https://github.com/Tinyu-Zhao/M5-Depends/blob/main/.github/ISSUE_TEMPLATE/bug-report.yml 3 | # See: 4 | # https://docs.github.com/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms 5 | 6 | name: Bug report 7 | description: Report a problem with the code in this repository. 8 | labels: 9 | - "type: bug" 10 | body: 11 | - type: markdown 12 | attributes: 13 | value: "Thank you for opening an issue on an M5Stack Arduino library repository.\n\ 14 | To improve the speed of resolution please review the following guidelines and common troubleshooting steps below before creating the issue:\n\ 15 | If you have any UIFLOW questions you can ask in the [special board](https://community.m5stack.com/category/5/uiflow), there will be many enthusiastic friends to help you.\n\ 16 | Do not use GitHub issues for troubleshooting projects and issues. Instead use the forums at https://community.m5stack.com to ask questions and troubleshoot why something isn't working as expected. In many cases the problem is a common issue that you will more quickly receive help from the forum community. GitHub issues are meant for known defects in the code. If you don't know if there is a defect in the code then start with troubleshooting on the forum first." 17 | - type: textarea 18 | id: description 19 | attributes: 20 | label: Describe the bug 21 | description: A clear and concise description of what the bug is. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: reproduce 26 | attributes: 27 | label: To reproduce 28 | description: Provide the specific set of steps we can follow to reproduce the problem. 29 | placeholder: | 30 | 1. In this environment... 31 | 2. With this config... 32 | 3. Run '...' 33 | 4. See error... 34 | validations: 35 | required: true 36 | - type: textarea 37 | id: expected 38 | attributes: 39 | label: Expected behavior 40 | description: What would you expect to happen after following those instructions? 41 | validations: 42 | required: true 43 | - type: textarea 44 | id: screenshots 45 | attributes: 46 | label: Screenshots 47 | description: If applicable, add screenshots to help explain your problem. 48 | validations: 49 | required: false 50 | - type: textarea 51 | id: information 52 | attributes: 53 | label: Environment 54 | description: | 55 | If applicable, add screenshots to help explain your problem. 56 | examples: 57 | - **OS**: Ubuntu 20.04 58 | - **IDE & IDE Version**: Arduino 1.8.19 Or Platform IO v2.5.0 59 | - **Repository Version**: 0.4.0 60 | value: | 61 | - OS: 62 | - IDE &IDE Version: 63 | - Repository Version: 64 | validations: 65 | required: false 66 | - type: textarea 67 | id: additional 68 | attributes: 69 | label: Additional context 70 | description: Add any additional information here. 71 | validations: 72 | required: false 73 | - type: checkboxes 74 | id: checklist 75 | attributes: 76 | label: Issue checklist 77 | description: Please double-check that you have done each of the following things before submitting the issue. 78 | options: 79 | - label: I searched for previous reports in [the issue tracker](https://github.com/m5stack/M5Stack/issues?q=) 80 | required: true 81 | - label: My report contains all necessary details 82 | required: true 83 | -------------------------------------------------------------------------------- /examples/i2c/motor/motor.ino: -------------------------------------------------------------------------------- 1 | #include "unit_rolleri2c.hpp" 2 | #include 3 | UnitRollerI2C RollerI2C; // Create a UNIT_ROLLERI2C object 4 | uint32_t p, i, d; // Defines a variable to store the PID value 5 | uint8_t r, g, b; 6 | void setup() 7 | { 8 | M5.begin(); 9 | RollerI2C.begin(&Wire, 0x64, 21, 22, 400000); 10 | } 11 | 12 | void loop() 13 | { 14 | // current mode 15 | RollerI2C.setMode(ROLLER_MODE_CURRENT); 16 | RollerI2C.setCurrent(120000); 17 | RollerI2C.setOutput(1); 18 | printf("current: %d\n", RollerI2C.getCurrent()); 19 | delay(100); 20 | printf("actualCurrent: %.2f\n", RollerI2C.getCurrentReadback() / 100.0f); 21 | delay(5000); 22 | 23 | // position mode 24 | RollerI2C.setOutput(0); 25 | RollerI2C.setMode(ROLLER_MODE_POSITION); 26 | RollerI2C.setPos(2000000); 27 | RollerI2C.setPosMaxCurrent(100000); 28 | RollerI2C.setOutput(1); 29 | RollerI2C.getPosPID(&p, &i, &d); 30 | printf("PosPID P: %3.8f I: %3.8f D: %3.8f\n", p / 100000.0, i / 10000000.0, d / 100000.0); 31 | delay(100); 32 | printf("pos: %d\n", RollerI2C.getPos()); 33 | delay(100); 34 | printf("posMaxCurrent: %d\n", RollerI2C.getPosMaxCurrent() / 100.0f); 35 | delay(100); 36 | printf("actualPos: %d\n", RollerI2C.getPosReadback() / 100.f); 37 | delay(5000); 38 | 39 | // speed mode 40 | RollerI2C.setOutput(0); 41 | RollerI2C.setMode(ROLLER_MODE_SPEED); 42 | RollerI2C.setSpeed(240000); 43 | RollerI2C.setSpeedMaxCurrent(100000); 44 | RollerI2C.setOutput(1); 45 | RollerI2C.getSpeedPID(&p, &i, &d); 46 | printf("SpeedPID P: %3.8f I: %3.8f D: %3.8f\n", p / 100000.0, i / 10000000.0, d / 100000.0); 47 | delay(100); 48 | printf("speed: %d\n", RollerI2C.getSpeed()); 49 | delay(100); 50 | printf("speedMaxCurrent: %d\n", RollerI2C.getSpeedMaxCurrent() / 100.0f); 51 | delay(100); 52 | printf("actualSpeed: %d\n", RollerI2C.getSpeedReadback() / 100.0f); 53 | delay(5000); 54 | 55 | // encoder mode 56 | RollerI2C.setOutput(0); 57 | RollerI2C.setMode(ROLLER_MODE_ENCODER); 58 | RollerI2C.setDialCounter(240000); 59 | RollerI2C.setOutput(1); 60 | printf("DialCounter:%d\n", RollerI2C.getDialCounter()); 61 | delay(5000); 62 | printf("temp:%d\n", RollerI2C.getTemp()); 63 | delay(100); 64 | printf("Vin:%3.2f\n", RollerI2C.getVin() / 100.0); 65 | delay(100); 66 | printf("RGBBrightness:%d\n", RollerI2C.getRGBBrightness()); 67 | delay(1000); 68 | RollerI2C.setRGBBrightness(100); 69 | delay(100); 70 | RollerI2C.setRGBMode(ROLLER_RGB_MODE_USER_DEFINED); 71 | delay(1000); 72 | RollerI2C.setRGB(TFT_WHITE); 73 | delay(1000); 74 | RollerI2C.setRGB(TFT_BLUE); 75 | delay(2000); 76 | RollerI2C.setRGB(TFT_YELLOW); 77 | delay(2000); 78 | RollerI2C.setRGB(TFT_RED); 79 | delay(2000); 80 | RollerI2C.setRGBMode(ROLLER_RGB_MODE_DEFAULT); 81 | delay(100); 82 | RollerI2C.setKeySwitchMode(1); 83 | delay(100); 84 | printf("I2CAddress:%d\n", RollerI2C.getI2CAddress()); 85 | delay(100); 86 | printf("485 BPS:%d\n", RollerI2C.getBPS()); 87 | delay(100); 88 | printf("485 motor id:%d\n", RollerI2C.getMotorID()); 89 | delay(100); 90 | printf("motor output:%d\n", RollerI2C.getOutputStatus()); 91 | delay(100); 92 | printf("SysStatus:%d\n", RollerI2C.getSysStatus()); 93 | delay(100); 94 | printf("ErrorCode:%d\n", RollerI2C.getErrorCode()); 95 | delay(100); 96 | printf("Button switching mode enable:%d\n", RollerI2C.getKeySwitchMode()); 97 | delay(100); 98 | RollerI2C.getRGB(&r, &g, &b); 99 | printf("RGB-R: 0x%02X RGB-G: 0x%02X RGB-B: 0x%02X\n", r, g, b); 100 | delay(5000); 101 | } 102 | -------------------------------------------------------------------------------- /examples/can/motor/motor.ino: -------------------------------------------------------------------------------- 1 | #include "unit_rollercan.hpp" 2 | #include 3 | UnitRollerCAN rollercan; // Create a UNIT_ROLLERCAN object 4 | const uint8_t motorID = 0xA8; 5 | 6 | uint8_t slaveRgbValues[3]; // Array to store R, G, B ,mode values 7 | void setup() 8 | { 9 | M5.begin(); 10 | 11 | Serial.begin(115200); 12 | Serial.println("Basic Demo - ESP32-Arduino-CAN"); 13 | rollercan.beginCAN(1000000, 16, 17); 14 | rollercan.setMode(motorID, ROLLER_MODE_SPEED); 15 | Serial.printf("mode:%d\r\n", rollercan.getMode(motorID)); 16 | 17 | rollercan.setSaveFlash(motorID); 18 | rollercan.setSpeedCurrent(motorID, 500); 19 | Serial.printf("SpeedCurrent:%d\r\n", rollercan.getSpeedCurrent(motorID)); 20 | 21 | rollercan.setOutput(motorID, true); 22 | Serial.printf("Output:%d\r\n", rollercan.getOutput(motorID)); 23 | 24 | rollercan.setSpeed(motorID, -500); 25 | Serial.printf("getSpeed:%d\r\n", rollercan.getSpeed(motorID)); 26 | 27 | delay(3000); 28 | rollercan.setSpeed(motorID, -2400); 29 | Serial.printf("getActualSpeed:%d\r\n", rollercan.getActualSpeed(motorID)); 30 | 31 | delay(3000); 32 | rollercan.setOutput(motorID, false); 33 | rollercan.setSpeedKp(motorID, 15 * 100000); 34 | Serial.printf("getSpeedKp:%d\r\n", rollercan.getSpeedKp(motorID)); 35 | 36 | rollercan.setSpeedKi(motorID, 100000); 37 | Serial.printf("getSpeedKi:%d\r\n", rollercan.getSpeedKi(motorID)); 38 | 39 | rollercan.setSpeedKd(motorID, 400 * 100000); 40 | Serial.printf("getSpeedKd:%d\r\n", rollercan.getSpeedKd(motorID)); 41 | 42 | delay(3000); 43 | // position 44 | rollercan.setMode(motorID, ROLLER_MODE_SPEED); 45 | rollercan.setPositionCurrent(motorID, 1200); 46 | Serial.printf("PositionCurrent:%d\r\n", rollercan.getPositionCurrent(motorID)); 47 | rollercan.setOutput(motorID, true); 48 | rollercan.setPosition(motorID, 240000); 49 | Serial.printf("getPosition:%d\r\n", rollercan.getPosition(motorID)); 50 | 51 | Serial.printf("getActualPosition:%d\r\n", rollercan.getActualPosition(motorID)); 52 | 53 | delay(3000); 54 | rollercan.setPositionKp(motorID, 15 * 100000); 55 | Serial.printf("getPositionKp:%d\r\n", rollercan.getPositionKp(motorID)); 56 | 57 | rollercan.setPositionKi(motorID, 30); 58 | Serial.printf("getPositionKi:%d\r\n", rollercan.getPositionKi(motorID)); 59 | 60 | rollercan.setPositionKd(motorID, 100 * 100000); 61 | Serial.printf("getPositionKd:%d\r\n", rollercan.getPositionKd(motorID)); 62 | 63 | delay(3000); 64 | 65 | rollercan.setMotorID(motorID, 0x64); 66 | delay(2000); 67 | rollercan.setMotorID(0x64, motorID); 68 | delay(1000); 69 | rollercan.setRGBMode(motorID, ROLLER_RGB_MODE_USER_DEFINED); 70 | Serial.printf("getRGBMode:%d\r\n", rollercan.getRGBMode(motorID)); 71 | 72 | rollercan.setRGBBrightness(motorID, 100); 73 | Serial.printf("getRGBBrightness:%d\r\n", rollercan.getRGBBrightness(motorID)); 74 | 75 | rollercan.setRGB(motorID, WHITE); 76 | delay(2000); 77 | rollercan.getRGB(motorID, slaveRgbValues); 78 | Serial.printf("RGB values: R=%d, G=%d, B=%d\n", slaveRgbValues[0], slaveRgbValues[1], slaveRgbValues[2]); 79 | 80 | rollercan.setRGB(motorID, RED); 81 | delay(2000); 82 | rollercan.setRGB(motorID, GREEN); 83 | delay(2000); 84 | rollercan.setRGB(motorID, BLUE); 85 | delay(2000); 86 | rollercan.setRGBMode(motorID, ROLLER_RGB_MODE_DEFAULT); 87 | rollercan.setMode(motorID, ROLLER_MODE_ENCODER); 88 | rollercan.setCurrent(motorID, 1200); 89 | Serial.printf("getCurrent:%d\r\n", rollercan.getCurrent(motorID)); 90 | 91 | Serial.printf("getActualCurrent:%d\r\n", rollercan.getActualCurrent(motorID)); 92 | 93 | delay(3000); 94 | rollercan.setOutput(motorID, false); 95 | delay(1000); 96 | rollercan.setMode(motorID, ROLLER_MODE_ENCODER); 97 | delay(1000); 98 | // Serial.printf("res:%d\r\n",rollercan.setEncoder(motorID,12000)); 99 | Serial.printf("res:%d\r\n", rollercan.setEncoder(motorID, 120000)); 100 | 101 | delay(1000); 102 | // Serial.printf("encoder:%d\r\n", rollercan.getEncoder(motorID)); 103 | Serial.printf("encoder:%d\r\n", rollercan.getEncoder(motorID)); 104 | 105 | Serial.printf("getActualVin:%d\r\n", rollercan.getActualVin(motorID)); 106 | 107 | Serial.printf("getActualTemp:%d\r\n", rollercan.getActualTemp(motorID)); 108 | } 109 | 110 | void loop() 111 | { 112 | delay(10000); 113 | } -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Google 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveMacros: true 7 | AlignConsecutiveAssignments: true 8 | AlignConsecutiveDeclarations: false 9 | AlignEscapedNewlines: Left 10 | AlignOperands: true 11 | AlignTrailingComments: true 12 | AllowAllArgumentsOnNextLine: true 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: Never 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortFunctionsOnASingleLine: false 18 | AllowShortLambdasOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: WithoutElse 20 | AllowShortLoopsOnASingleLine: true 21 | AlwaysBreakAfterDefinitionReturnType: None 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: true 24 | AlwaysBreakTemplateDeclarations: Yes 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BraceWrapping: 28 | AfterCaseLabel: false 29 | AfterClass: false 30 | AfterControlStatement: false 31 | AfterEnum: false 32 | AfterFunction: true 33 | AfterNamespace: false 34 | AfterObjCDeclaration: false 35 | AfterStruct: false 36 | AfterUnion: false 37 | AfterExternBlock: false 38 | BeforeCatch: false 39 | BeforeElse: false 40 | IndentBraces: false 41 | SplitEmptyFunction: true 42 | SplitEmptyRecord: true 43 | SplitEmptyNamespace: true 44 | BreakBeforeBinaryOperators: None 45 | BreakBeforeBraces: Custom 46 | BreakBeforeInheritanceComma: false 47 | BreakInheritanceList: BeforeColon 48 | BreakBeforeTernaryOperators: true 49 | BreakConstructorInitializersBeforeComma: false 50 | BreakConstructorInitializers: BeforeColon 51 | BreakAfterJavaFieldAnnotations: false 52 | BreakStringLiterals: true 53 | ColumnLimit: 120 54 | CommentPragmas: '^ IWYU pragma:' 55 | CompactNamespaces: false 56 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 57 | ConstructorInitializerIndentWidth: 4 58 | ContinuationIndentWidth: 4 59 | Cpp11BracedListStyle: true 60 | DeriveLineEnding: true 61 | DerivePointerAlignment: true 62 | DisableFormat: false 63 | ExperimentalAutoDetectBinPacking: false 64 | FixNamespaceComments: true 65 | ForEachMacros: 66 | - foreach 67 | - Q_FOREACH 68 | - BOOST_FOREACH 69 | IncludeBlocks: Regroup 70 | IncludeCategories: 71 | - Regex: '^' 72 | Priority: 2 73 | SortPriority: 0 74 | - Regex: '^<.*\.h>' 75 | Priority: 1 76 | SortPriority: 0 77 | - Regex: '^<.*' 78 | Priority: 2 79 | SortPriority: 0 80 | - Regex: '.*' 81 | Priority: 3 82 | SortPriority: 0 83 | IncludeIsMainRegex: '([-_](test|unittest))?$' 84 | IncludeIsMainSourceRegex: '' 85 | IndentCaseLabels: true 86 | IndentGotoLabels: true 87 | IndentPPDirectives: None 88 | IndentWidth: 4 89 | IndentWrappedFunctionNames: false 90 | JavaScriptQuotes: Leave 91 | JavaScriptWrapImports: true 92 | KeepEmptyLinesAtTheStartOfBlocks: false 93 | MacroBlockBegin: '' 94 | MacroBlockEnd: '' 95 | MaxEmptyLinesToKeep: 1 96 | NamespaceIndentation: None 97 | ObjCBinPackProtocolList: Never 98 | ObjCBlockIndentWidth: 2 99 | ObjCSpaceAfterProperty: false 100 | ObjCSpaceBeforeProtocolList: true 101 | PenaltyBreakAssignment: 2 102 | PenaltyBreakBeforeFirstCallParameter: 1 103 | PenaltyBreakComment: 300 104 | PenaltyBreakFirstLessLess: 120 105 | PenaltyBreakString: 1000 106 | PenaltyBreakTemplateDeclaration: 10 107 | PenaltyExcessCharacter: 1000000 108 | PenaltyReturnTypeOnItsOwnLine: 200 109 | PointerAlignment: Left 110 | RawStringFormats: 111 | - Language: Cpp 112 | Delimiters: 113 | - cc 114 | - CC 115 | - cpp 116 | - Cpp 117 | - CPP 118 | - 'c++' 119 | - 'C++' 120 | CanonicalDelimiter: '' 121 | BasedOnStyle: google 122 | - Language: TextProto 123 | Delimiters: 124 | - pb 125 | - PB 126 | - proto 127 | - PROTO 128 | EnclosingFunctions: 129 | - EqualsProto 130 | - EquivToProto 131 | - PARSE_PARTIAL_TEXT_PROTO 132 | - PARSE_TEST_PROTO 133 | - PARSE_TEXT_PROTO 134 | - ParseTextOrDie 135 | - ParseTextProtoOrDie 136 | CanonicalDelimiter: '' 137 | BasedOnStyle: google 138 | ReflowComments: true 139 | SortIncludes: false 140 | SortUsingDeclarations: true 141 | SpaceAfterCStyleCast: false 142 | SpaceAfterLogicalNot: false 143 | SpaceAfterTemplateKeyword: true 144 | SpaceBeforeAssignmentOperators: true 145 | SpaceBeforeCpp11BracedList: false 146 | SpaceBeforeCtorInitializerColon: true 147 | SpaceBeforeInheritanceColon: true 148 | SpaceBeforeParens: ControlStatements 149 | SpaceBeforeRangeBasedForLoopColon: true 150 | SpaceInEmptyBlock: false 151 | SpaceInEmptyParentheses: false 152 | SpacesBeforeTrailingComments: 2 153 | SpacesInAngles: false 154 | SpacesInConditionalStatement: false 155 | SpacesInContainerLiterals: true 156 | SpacesInCStyleCastParentheses: false 157 | SpacesInParentheses: false 158 | SpacesInSquareBrackets: false 159 | SpaceBeforeSquareBrackets: false 160 | Standard: Auto 161 | StatementMacros: 162 | - Q_UNUSED 163 | - QT_REQUIRE_VERSION 164 | TabWidth: 4 165 | UseCRLF: false 166 | UseTab: Never 167 | ... 168 | -------------------------------------------------------------------------------- /examples/rs485/slaveMotor/slaveMotor.ino: -------------------------------------------------------------------------------- 1 | #include "unit_roller485.hpp" 2 | #include 3 | #include 4 | 5 | UnitRoller485 Roller485; // Create a UnitRoller485 object 6 | HardwareSerial mySerial(1); // Create a hardware serial port object 7 | #define motor485Id 0x00 8 | #define slaveI2cAddress 0x64 9 | uint8_t slaveRgbValues[4]; // Array to store R, G, B ,mode values 10 | double slaveSpeedPID[3]; // Array to P I D values 11 | void setup() 12 | { 13 | M5.begin(); 14 | // Call the begin function and pass arguments 15 | Roller485.begin(&mySerial, 115200, SERIAL_8N1, 16, 17, -1, false, 10000UL, 112U); 16 | // Set the motor mode to speed 17 | Roller485.setMode(motor485Id, ROLLER_MODE_SPEED); 18 | // Set speed Speed and current 19 | Roller485.setSpeedMode(motor485Id, 2400, 1200); 20 | // Set the motor to enable 21 | Roller485.setOutput(motor485Id, 0x01); 22 | 23 | // Set the speed mode of the slave motor 24 | Roller485.writeMotorConfig(motor485Id, slaveI2cAddress, false, ROLLER_MODE_SPEED, true, true, false, true); 25 | Roller485.writeSpeedMode(motor485Id, slaveI2cAddress, 1000); 26 | Roller485.writeSpeedModeCurrent(motor485Id, slaveI2cAddress, 1200); 27 | // set position 28 | // Roller485.writeMotorConfig(motor485Id, slaveI2cAddress, true, 0x02, 0x00, true, true); 29 | // Roller485.writePositionMode(motor485Id, slaveI2cAddress, 500000); 30 | // Roller485.writePositionModeCurrent(motor485Id, slaveI2cAddress, 500); 31 | 32 | // set current 33 | // Roller485.writeMotorConfig(motor485Id, slaveI2cAddress, true, 0x03, 0x00, true, true); 34 | // Roller485.writeCurrentMode(motor485Id, slaveI2cAddress, 800); 35 | } 36 | 37 | void loop() 38 | { 39 | int errorCode = Roller485.setMode(motor485Id, ROLLER_MODE_SPEED); 40 | if (errorCode == 1) { 41 | // Successful operation 42 | Serial.println("setMode() successful."); 43 | } else { 44 | // Print error code 45 | Serial.print("setMode() failed with error code: "); 46 | Serial.println(errorCode); 47 | } 48 | delay(1000); 49 | 50 | int8_t output = Roller485.readOutput(motor485Id, slaveI2cAddress); 51 | Serial.printf("output: %d\n", output); 52 | delay(1000); 53 | int8_t mode = Roller485.readMode(motor485Id, slaveI2cAddress); 54 | Serial.printf("mode: %d\n", mode); 55 | delay(1000); 56 | int8_t button = Roller485.readButton(motor485Id, slaveI2cAddress); 57 | Serial.printf("button: %d\n", button); 58 | delay(1000); 59 | int8_t stallProtection = Roller485.readStallProtection(motor485Id, slaveI2cAddress); 60 | Serial.printf("stallProtection: %d\n", stallProtection); 61 | delay(1000); 62 | int8_t status = Roller485.readStatus(motor485Id, slaveI2cAddress); 63 | Serial.printf("status: %d\n", status); 64 | delay(1000); 65 | int8_t error = Roller485.readError(motor485Id, slaveI2cAddress); 66 | Serial.printf("error: %d\n", error); 67 | delay(1000); 68 | int32_t motorId = Roller485.readMotorId(motor485Id, slaveI2cAddress); 69 | Serial.printf("motorId: %d\n", motorId); 70 | delay(1000); 71 | int8_t baudRate = Roller485.readBaudRate(motor485Id, slaveI2cAddress); 72 | Serial.printf("baudRate: %d\n", baudRate); 73 | delay(1000); 74 | int8_t rgbBrightness = Roller485.readRgbBrightness(motor485Id, slaveI2cAddress); 75 | Serial.printf("rgbBrightness: %d\n", rgbBrightness); 76 | delay(1000); 77 | int8_t errorSpeedPID = Roller485.readSpeedPID(motor485Id, slaveI2cAddress, slaveSpeedPID); 78 | if (errorSpeedPID != 1) { 79 | Serial.print("getSpeedPID failed with error code: "); 80 | Serial.println(errorSpeedPID); 81 | } else { 82 | printf("speedPID values: P=%.8lf, I=%.8lf, D=%.8lf\n", slaveSpeedPID[0], slaveSpeedPID[1], slaveSpeedPID[2]); 83 | } 84 | 85 | delay(1000); 86 | 87 | int32_t current = Roller485.readCurrent(motor485Id, slaveI2cAddress); 88 | Serial.printf("current: %d\n", current); 89 | delay(1000); 90 | Roller485.writeSetRGB(motor485Id, slaveI2cAddress, 0xff, 0xff, 0xff, ROLLER_RGB_MODE_USER_DEFINED); 91 | delay(1000); 92 | int8_t errorRGB = Roller485.readRGB(motor485Id, slaveI2cAddress, slaveRgbValues); 93 | if (errorRGB != 1) { 94 | // Print error code 95 | Serial.print("getRGB failed with error code: "); 96 | Serial.println(errorRGB); 97 | } else { 98 | printf("RGB values: R=%d, G=%d, B=%d Mode:%d\n", slaveRgbValues[0], slaveRgbValues[1], slaveRgbValues[2], 99 | slaveRgbValues[3]); 100 | } 101 | Roller485.writeSetRGB(motor485Id, slaveI2cAddress, 0x00, 0x00, 0x00, ROLLER_RGB_MODE_DEFAULT); 102 | int32_t vin = Roller485.readVin(motor485Id, slaveI2cAddress); 103 | Serial.printf("vin: %d\n", vin); 104 | delay(1000); 105 | int32_t temp = Roller485.readTemp(motor485Id, slaveI2cAddress); 106 | Serial.printf("temp: %d\n", temp); 107 | delay(1000); 108 | int32_t encoder = Roller485.readEncoder(motor485Id, slaveI2cAddress); 109 | Serial.printf("encoder: %d\n", encoder); 110 | delay(1000); 111 | int version = Roller485.readVersion(motor485Id, slaveI2cAddress); 112 | Serial.printf("version: %d\n", version); 113 | delay(1000); 114 | uint8_t i2cAddress = Roller485.readI2cAddress(motor485Id, slaveI2cAddress); 115 | Serial.printf("i2cAddress: %d\n", i2cAddress); 116 | delay(1000); 117 | 118 | Roller485.writeMotorConfig(motor485Id, slaveI2cAddress, false, ROLLER_MODE_ENCODER, true, true, false, true); 119 | 120 | Roller485.writeEncoderMode(motor485Id, slaveI2cAddress, 24000); 121 | Serial.printf("readEncoder: %d\n", Roller485.readEncoder(motor485Id, slaveI2cAddress)); 122 | } -------------------------------------------------------------------------------- /src/unit_roller_common.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | *SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | *SPDX-License-Identifier: MIT 5 | */ 6 | 7 | #ifndef __UNIT_ROLLER_COMMON_H 8 | #define __UNIT_ROLLER_COMMON_H 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | // #define UNIT_ROLLER_DEBUG Serial // This macro definition can be annotated without sending and receiving data prints 15 | // Define the serial port you want to use, e.g., Serial1 or Serial2 16 | #if defined UNIT_ROLLER_DEBUG 17 | #define serialPrint(...) UNIT_ROLLER_DEBUG.print(__VA_ARGS__) 18 | #define serialPrintln(...) UNIT_ROLLER_DEBUG.println(__VA_ARGS__) 19 | #define serialPrintf(...) UNIT_ROLLER_DEBUG.printf(__VA_ARGS__) 20 | #define serialFlush() UNIT_ROLLER_DEBUG.flush() 21 | #else 22 | #endif 23 | 24 | // Enum definition for error codes 25 | typedef enum { 26 | ROLLER_WRITE_SUCCESS = 1, /**< Indicates a successful write operation. */ 27 | ROLLER_WRITE_FAILED = 0, /**< Indicates a failure during write or read operations. */ 28 | ROLLER_CRC_CHECK_FAIL = -1, /**< Indicates a failure in CRC check. */ 29 | ROLLER_SERIAL_TIMEOUT = -2, /**< Indicates a timeout in serial communication. */ 30 | ROLLER_UNEXPECTED_RESPONSE = -3, /**< Indicates an unexpected response received from the device. */ 31 | ROLLER_SERIAL_SEND_FAILURE = -4 /**< Indicates a failure in sending serial data. */ 32 | } roller_errcode_t; 33 | 34 | typedef enum { 35 | ROLLER_MODE_SPEED = 1, // Speed mode 36 | ROLLER_MODE_POSITION, // Position mode(2) 37 | ROLLER_MODE_CURRENT, // Current mode (3) 38 | ROLLER_MODE_ENCODER // Encoder mode (4) 39 | } roller_mode_t; 40 | 41 | typedef enum { 42 | // 485 43 | ROLLER_BPS_485_115200 = 0, /**< Baud rate of 115200 bps */ 44 | ROLLER_BPS_485_19200, /**< Baud rate of 19200 bps */ 45 | ROLLER_BPS_485_9600, /**< Baud rate of 9600 bps */ 46 | // CAN 47 | ROLLER_BPS_CAN_1000000 = 0, /**< Baud rate of 1000 Kbps */ 48 | ROLLER_BPS_CAN_500000, /**< Baud rate of 500 Kbps */ 49 | ROLLER_BPS_CAN_125000 /**< Baud rate of 125 Kbps */ 50 | } roller_bps_t; 51 | 52 | typedef enum { 53 | ROLLER_RGB_MODE_DEFAULT = 0, // System default mode 54 | ROLLER_RGB_MODE_USER_DEFINED // User-defined mode 55 | } roller_rgb_t; 56 | 57 | /** 58 | * @brief I2C Address of the Unit Roller device. 59 | * 60 | * This address is used to identify the Unit Roller device on the I2C bus. 61 | */ 62 | #define I2C_ADDR (0x64) 63 | 64 | /** 65 | * @brief Output Register. 66 | * 67 | * This register is used to set the output parameters for the Unit Roller. 68 | */ 69 | #define I2C_OUTPUT_REG (0x00) 70 | 71 | /** 72 | * @brief Mode Register. 73 | * 74 | * This register configures the operational mode of the Unit Roller. 75 | */ 76 | #define I2C_MODE_REG (0x01) 77 | 78 | /** 79 | * @brief Motor Position Over Range Protection: 80 | * 81 | * This register can be used to set the motor position out of range protection 82 | * mechanism. 83 | */ 84 | #define I2C_POS_RANGE_PROTECT_REG (0x0A) 85 | 86 | /** 87 | * @brief Reset Stalled Protection Register. 88 | * 89 | * This register can be used to reset the stalled protection mechanism. 90 | */ 91 | #define I2C_RESET_STALLED_PROTECT_REG (0x0B) 92 | 93 | /** 94 | * @brief System Status Register. 95 | * 96 | * This register holds the current system status of the Unit Roller. 97 | */ 98 | #define I2C_SYS_STATUS_REG (0x0C) 99 | 100 | /** 101 | * @brief Error Code Register. 102 | * 103 | * This register reports any error codes generated by the Unit Roller. 104 | */ 105 | #define I2C_ERROR_CODE_REG (0x0D) 106 | 107 | /** 108 | * @brief Key Switch Mode Register. 109 | * 110 | * This register configures the key switch mode for the Unit Roller. 111 | */ 112 | #define I2C_KEY_SWTICH_MODE_REG (0x0E) 113 | 114 | /** 115 | * @brief Stall Protection Register. 116 | * 117 | * This register enables or disables stall protection features. 118 | */ 119 | #define I2C_STALL_PROTECTION_REG (0x0F) 120 | 121 | /** 122 | * @brief Identification Register. 123 | * 124 | * This register contains the identity information of the Unit Roller. 125 | */ 126 | #define I2C_ID_REG (0x10) 127 | 128 | /** 129 | * @brief Baud Rate Setting Register. 130 | * 131 | * This register sets the baud rate for communication. 132 | */ 133 | #define I2C_BPS_REG (0x11) 134 | 135 | /** 136 | * @brief RGB Brightness Register. 137 | * 138 | * This register controls the brightness level of the RGB output. 139 | */ 140 | #define I2C_RGB_BRIGHTNESS_REG (0x12) 141 | 142 | /** 143 | * @brief Maximum Current Register. 144 | * 145 | * This register sets the maximum current limit for the motor. 146 | */ 147 | #define I2C_POS_MAX_CURRENT_REG (0x20) 148 | 149 | /** 150 | * @brief RGB Control Register. 151 | * 152 | * This register is used to control RGB features of the Unit Roller. 153 | */ 154 | #define I2C_RGB_REG (0x30) 155 | 156 | /** 157 | * @brief Voltage Input Register. 158 | * 159 | * This register reads the input voltage to the Unit Roller. 160 | */ 161 | #define I2C_VIN_REG (0x34) 162 | 163 | /** 164 | * @brief Temperature Register. 165 | * 166 | * This register provides temperature readings from the Unit Roller. 167 | */ 168 | #define I2C_TEMP_REG (0x38) 169 | 170 | /** 171 | * @brief Dial Counter Register. 172 | * 173 | * This register tracks the dial counter value. 174 | */ 175 | #define I2C_DIAL_COUNTER_REG (0x3C) 176 | 177 | /** 178 | * @brief Speed Register. 179 | * 180 | * This register controls the speed parameters of the Unit Roller. 181 | */ 182 | #define I2C_SPEED_REG (0x40) 183 | 184 | /** 185 | * @brief Speed Maximum Current Register. 186 | * 187 | * This register sets the maximum current when operating at a specified speed. 188 | */ 189 | #define I2C_SPEED_MAX_CURRENT_REG (0x50) 190 | 191 | /** 192 | * @brief Speed Readback Register. 193 | * 194 | * This register reads back the current speed of the Unit Roller. 195 | */ 196 | #define I2C_SPEED_READBACK_REG (0x60) 197 | 198 | /** 199 | * @brief Speed PID Register. 200 | * 201 | * This register contains PID settings for speed control. 202 | */ 203 | #define I2C_SPEED_PID_REG (0x70) 204 | 205 | /** 206 | * @brief Position Register. 207 | * 208 | * This register tracks the current position of the Unit Roller. 209 | */ 210 | #define I2C_POS_REG (0x80) 211 | 212 | /** 213 | * @brief Position Readback Register. 214 | * 215 | * This register allows reading back the position of the Unit Roller. 216 | */ 217 | #define I2C_POS_READBACK_REG (0x90) 218 | 219 | /** 220 | * @brief Position PID Register. 221 | * 222 | * This register contains PID settings for position control. 223 | */ 224 | #define I2C_POS_PID_REG (0xA0) 225 | 226 | /** 227 | * @brief Current Register. 228 | * 229 | * This register tracks the current flowing through the motor. 230 | */ 231 | #define I2C_CURRENT_REG (0xB0) 232 | 233 | /** 234 | * @brief Current Readback Register. 235 | * 236 | * This register allows reading back the current value. 237 | */ 238 | #define I2C_CURRENT_READBACK_REG (0xC0) 239 | 240 | /** 241 | * @brief Save to Flash Register. 242 | * 243 | * This register is used to save settings or data to the flash memory of the Unit Roller. 244 | */ 245 | #define I2C_SAVE_FLASH_REG (0xF0) 246 | 247 | /** 248 | * @brief Firmware Version Register. 249 | * 250 | * This register provides the firmware version information of the Unit Roller. 251 | */ 252 | #define I2C_FIRMWARE_VERSION_REG (0xFE) 253 | 254 | /** 255 | * @brief I2C Address Register. 256 | * 257 | * This register contains the I2C address of the device, allowing for identification 258 | * on the I2C bus. 259 | */ 260 | #define I2C_ADDRESS_REG (0xFF) 261 | 262 | /** 263 | * @brief Start Angle Calibration Register. 264 | * 265 | * This is an internal factory register that is used to initiate the calibration process for the magnetic encoder. 266 | */ 267 | #define START_ANGLE_CAL_REG (0xF1) 268 | 269 | /** 270 | * @brief Update Angle Calibration Register. 271 | * 272 | * This is an internal factory register used to update the calibration value of the magnetic encoder. 273 | */ 274 | #define UPDATE_ANGLE_CAL_REG (0xF2) 275 | 276 | /** 277 | * @brief Get Angle Calibration Status Register. 278 | * 279 | * This is an internal factory register used to retrieve the calibration status of the magnetic encoder. 280 | */ 281 | #define GET_ANGLE_BUSY_REG (0xF3) 282 | 283 | extern bool mutexLocked; 284 | 285 | void acquireMutex(); 286 | void releaseMutex(); 287 | int32_t handleValue(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3); 288 | 289 | #endif 290 | -------------------------------------------------------------------------------- /examples/can/slaveMotor/slaveMotor.ino: -------------------------------------------------------------------------------- 1 | #include "unit_rollercan.hpp" 2 | #include 3 | UnitRollerCAN rollercan; // Create a UNIT_ROLLERCAN object 4 | #define motorID 0xA8 5 | #define slaveI2cAddress 0x64 6 | uint8_t slaveRgbValues[3]; // Array to store R, G, B ,mode values 7 | 8 | void setup() 9 | { 10 | M5.begin(); 11 | Serial.begin(115200); 12 | Serial.println("ESP32-Arduino-CAN"); 13 | rollercan.beginCAN(1000000, 16, 17); 14 | rollercan.setMode(motorID, ROLLER_MODE_SPEED); 15 | rollercan.setSpeed(motorID, 1200); 16 | rollercan.setSpeedCurrent(motorID, 1200); 17 | rollercan.setOutput(motorID, false); 18 | delay(1000); 19 | rollercan.writeMode(motorID, slaveI2cAddress, ROLLER_MODE_ENCODER); 20 | rollercan.writeEncoder(motorID, slaveI2cAddress, 24000); 21 | Serial.printf("read encoder:%d\r\n", rollercan.readEncoder(motorID, slaveI2cAddress)); 22 | delay(3000); 23 | rollercan.writeOutput(motorID, slaveI2cAddress, true); 24 | rollercan.writeRemoveProtection(motorID, slaveI2cAddress, false); 25 | rollercan.writeMode(motorID, slaveI2cAddress, ROLLER_MODE_SPEED); 26 | rollercan.writeSaveFlash(motorID, slaveI2cAddress, true); 27 | delay(1000); 28 | 29 | rollercan.writeSpeed(motorID, slaveI2cAddress, -2400); 30 | rollercan.writeSpeedCurrent(motorID, slaveI2cAddress, 1200); 31 | Serial.printf("readActualSpeed:%d\r\n", rollercan.readActualSpeed(motorID, slaveI2cAddress)); 32 | Serial.printf("readSpeed:%d\r\n", rollercan.readSpeed(motorID, slaveI2cAddress)); 33 | Serial.printf("readSpeedCurrent:%d\r\n", rollercan.readSpeedCurrent(motorID, slaveI2cAddress)); 34 | 35 | delay(3000); 36 | rollercan.writeOutput(motorID, slaveI2cAddress, false); 37 | rollercan.writeSpeedKp(motorID, slaveI2cAddress, 15 * 100000); 38 | Serial.printf("readSpeedKp:%d\r\n", rollercan.readSpeedKp(motorID, slaveI2cAddress)); 39 | 40 | rollercan.writeSpeedKi(motorID, slaveI2cAddress, 100000); 41 | Serial.printf("readSpeedKi:%d\r\n", rollercan.readSpeedKi(motorID, slaveI2cAddress)); 42 | 43 | rollercan.writeSpeedKd(motorID, slaveI2cAddress, 400 * 100000); 44 | Serial.printf("readSpeedKd:%d\r\n", rollercan.readSpeedKd(motorID, slaveI2cAddress)); 45 | 46 | delay(3000); 47 | 48 | rollercan.writeMode(motorID, slaveI2cAddress, ROLLER_MODE_SPEED); 49 | rollercan.writePosition(motorID, slaveI2cAddress, 240000); 50 | rollercan.writePositionCurrent(motorID, slaveI2cAddress, 1200); 51 | rollercan.writeOutput(motorID, slaveI2cAddress, true); 52 | Serial.printf("readActualPosition:%d\r\n", rollercan.readActualPosition(motorID, slaveI2cAddress)); 53 | 54 | Serial.printf("readPosition:%d\r\n", rollercan.readPosition(motorID, slaveI2cAddress)); 55 | 56 | Serial.printf("readPositionCurrent:%d\r\n", rollercan.readPositionCurrent(motorID, slaveI2cAddress)); 57 | 58 | delay(3000); 59 | rollercan.writeOutput(motorID, slaveI2cAddress, false); 60 | rollercan.writePositionKp(motorID, slaveI2cAddress, 15 * 100000); 61 | Serial.printf("readPositionKp:%d\r\n", rollercan.readPositionKp(motorID, slaveI2cAddress)); 62 | 63 | rollercan.writePositionKi(motorID, slaveI2cAddress, 30); 64 | Serial.printf("readPositionKi:%d\r\n", rollercan.readPositionKi(motorID, slaveI2cAddress)); 65 | 66 | rollercan.writePositionKd(motorID, slaveI2cAddress, 100 * 100000); 67 | Serial.printf("readPositionKd:%d\r\n", rollercan.readSpeedKd(motorID, slaveI2cAddress)); 68 | 69 | delay(3000); 70 | rollercan.writeMode(motorID, slaveI2cAddress, ROLLER_MODE_ENCODER); 71 | rollercan.writeCurrent(motorID, slaveI2cAddress, 2400); 72 | rollercan.writeOutput(motorID, slaveI2cAddress, true); 73 | Serial.printf("readCurrent:%d\r\n", rollercan.readCurrent(motorID, slaveI2cAddress)); 74 | 75 | Serial.printf("readActualCurrent:%d\r\n", rollercan.readActualCurrent(motorID, slaveI2cAddress)); 76 | 77 | delay(3000); 78 | rollercan.writeOutput(motorID, slaveI2cAddress, false); 79 | rollercan.writeRGBMode(motorID, slaveI2cAddress, ROLLER_RGB_MODE_USER_DEFINED); 80 | Serial.printf("readRGBMode:%d\r\n", rollercan.readRGBMode(motorID, slaveI2cAddress)); 81 | 82 | rollercan.writeRGBBrightness(motorID, slaveI2cAddress, 100); 83 | Serial.printf("readRGBBrightness:%d\r\n", rollercan.readRGBBrightness(motorID, slaveI2cAddress)); 84 | 85 | rollercan.writeRGB(motorID, slaveI2cAddress, WHITE); 86 | delay(2000); 87 | rollercan.readRGB(motorID, slaveI2cAddress, slaveRgbValues); 88 | Serial.printf("RGB values: R=%d, G=%d, B=%d\n", slaveRgbValues[0], slaveRgbValues[1], slaveRgbValues[2]); 89 | 90 | rollercan.writeRGB(motorID, slaveI2cAddress, RED); 91 | delay(2000); 92 | rollercan.writeRGB(motorID, slaveI2cAddress, GREEN); 93 | delay(2000); 94 | rollercan.writeRGB(motorID, slaveI2cAddress, BLUE); 95 | delay(2000); 96 | rollercan.writeRGBMode(motorID, slaveI2cAddress, ROLLER_RGB_MODE_USER_DEFINED); 97 | Serial.printf("readActualVin:%d\r\n", rollercan.readActualVin(motorID, slaveI2cAddress)); 98 | 99 | Serial.printf("readActualTemp:%d\r\n", rollercan.readActualTemp(motorID, slaveI2cAddress)); 100 | 101 | // raw 102 | rollercan.writeResetStallProtect(motorID, slaveI2cAddress, true); 103 | rollercan.writeRawMode(motorID, slaveI2cAddress, ROLLER_MODE_ENCODER); 104 | rollercan.writeRawEncoder(motorID, slaveI2cAddress, 24000); 105 | Serial.printf("read encoder:%d\r\n", rollercan.readRawEncoder(motorID, slaveI2cAddress)); 106 | 107 | delay(3000); 108 | rollercan.writeRawOutput(motorID, slaveI2cAddress, true); 109 | rollercan.writeRawMode(motorID, slaveI2cAddress, ROLLER_MODE_SPEED); 110 | rollercan.writeRawFlash(motorID, slaveI2cAddress, true); 111 | delay(1000); 112 | rollercan.writeRawSpeed(motorID, slaveI2cAddress, -2400); 113 | rollercan.writeRawSpeedCurrent(motorID, slaveI2cAddress, 1200); 114 | Serial.printf("readRawActualSpeed:%d\r\n", rollercan.readRawActualSpeed(motorID, slaveI2cAddress)); 115 | 116 | Serial.printf("readRawSpeed:%d\r\n", rollercan.readRawSpeed(motorID, slaveI2cAddress)); 117 | 118 | Serial.printf("readRawSpeedCurrent:%d\r\n", rollercan.readRawSpeedCurrent(motorID, slaveI2cAddress)); 119 | 120 | delay(3000); 121 | 122 | delay(3000); 123 | rollercan.writeRawOutput(motorID, slaveI2cAddress, false); 124 | rollercan.writeRawSpeedKp(motorID, slaveI2cAddress, 15 * 100000); 125 | Serial.printf("readRawSpeedKp:%d\r\n", rollercan.readRawSpeedKp(motorID, slaveI2cAddress)); 126 | 127 | rollercan.writeRawSpeedKi(motorID, slaveI2cAddress, 100000); 128 | Serial.printf("readSpeedKi:%d\r\n", rollercan.readRawSpeedKi(motorID, slaveI2cAddress)); 129 | 130 | rollercan.writeRawSpeedKd(motorID, slaveI2cAddress, 400 * 100000); 131 | Serial.printf("readSpeedKd:%d\r\n", rollercan.readRawSpeedKd(motorID, slaveI2cAddress)); 132 | 133 | delay(3000); 134 | 135 | rollercan.writeRawMode(motorID, slaveI2cAddress, ROLLER_MODE_SPEED); 136 | rollercan.writeRawPosition(motorID, slaveI2cAddress, 240000); 137 | rollercan.writeRawPositionCurrent(motorID, slaveI2cAddress, 1200); 138 | rollercan.writeRawOutput(motorID, slaveI2cAddress, true); 139 | Serial.printf("readRawActualPosition:%d\r\n", rollercan.readRawActualPosition(motorID, slaveI2cAddress)); 140 | 141 | Serial.printf("readRawPosition:%d\r\n", rollercan.readRawPosition(motorID, slaveI2cAddress)); 142 | 143 | Serial.printf("readRawPositionCurrent:%d\r\n", rollercan.readRawPositionCurrent(motorID, slaveI2cAddress)); 144 | 145 | delay(3000); 146 | rollercan.writeRawOutput(motorID, slaveI2cAddress, false); 147 | rollercan.writeRawPositionKp(motorID, slaveI2cAddress, 15 * 100000); 148 | Serial.printf("readRawPositionKp:%d\r\n", rollercan.readRawPositionKp(motorID, slaveI2cAddress)); 149 | 150 | rollercan.writeRawPositionKi(motorID, slaveI2cAddress, 30); 151 | Serial.printf("readRawPositionKi:%d\r\n", rollercan.readRawPositionKi(motorID, slaveI2cAddress)); 152 | 153 | rollercan.writeRawPositionKd(motorID, slaveI2cAddress, 100 * 100000); 154 | Serial.printf("readPositionKd:%d\r\n", rollercan.readRawSpeedKd(motorID, slaveI2cAddress)); 155 | 156 | delay(3000); 157 | rollercan.writeRawMode(motorID, slaveI2cAddress, ROLLER_MODE_ENCODER); 158 | rollercan.writeRawCurrent(motorID, slaveI2cAddress, 2400); 159 | rollercan.writeRawOutput(motorID, slaveI2cAddress, true); 160 | Serial.printf("readRawCurrent:%d\r\n", rollercan.readRawCurrent(motorID, slaveI2cAddress)); 161 | 162 | Serial.printf("readRawActualCurrent:%d\r\n", rollercan.readRawActualCurrent(motorID, slaveI2cAddress)); 163 | 164 | delay(3000); 165 | rollercan.writeRawOutput(motorID, slaveI2cAddress, false); 166 | rollercan.writeRawRGBMode(motorID, slaveI2cAddress, ROLLER_RGB_MODE_USER_DEFINED); 167 | delay(1000); 168 | Serial.printf("readRawRGBMode:%d\r\n", rollercan.readRawRGBMode(motorID, slaveI2cAddress)); 169 | 170 | rollercan.writeRawRGBBrightness(motorID, slaveI2cAddress, 100); 171 | Serial.printf("readRawRGBBrightness:%d\r\n", rollercan.readRawRGBBrightness(motorID, slaveI2cAddress)); 172 | 173 | rollercan.writeRawRGB(motorID, slaveI2cAddress, WHITE); 174 | delay(2000); 175 | rollercan.readRawRGB(motorID, slaveI2cAddress, slaveRgbValues); 176 | Serial.printf("RGB values: R=%d, G=%d, B=%d\n", slaveRgbValues[0], slaveRgbValues[1], slaveRgbValues[2]); 177 | 178 | rollercan.writeRawRGB(motorID, slaveI2cAddress, RED); 179 | delay(2000); 180 | Serial.printf("readRawRGBMode:%d\r\n", rollercan.readRawRGBMode(motorID, slaveI2cAddress)); 181 | rollercan.writeRawRGB(motorID, slaveI2cAddress, GREEN); 182 | delay(2000); 183 | rollercan.writeRawRGB(motorID, slaveI2cAddress, BLUE); 184 | delay(2000); 185 | rollercan.writeRawRGBMode(motorID, slaveI2cAddress, ROLLER_RGB_MODE_DEFAULT); 186 | Serial.printf("readActualVin:%d\r\n", rollercan.readRawActualVin(motorID, slaveI2cAddress)); 187 | Serial.printf("readActualTemp:%d\r\n", rollercan.readRawActualTemp(motorID, slaveI2cAddress)); 188 | Serial.printf("FirmwareVersion:%d\r\n", rollercan.readRawFirmwareVersion(motorID, slaveI2cAddress)); 189 | rollercan.writeRawI2CAddress(motorID, slaveI2cAddress, 0x23); 190 | delay(2000); 191 | rollercan.writeRawI2CAddress(motorID, 0x23, slaveI2cAddress); 192 | Serial.printf("I2CAddress:%d\r\n", rollercan.readRawI2CAddress(motorID, slaveI2cAddress)); 193 | 194 | rollercan.writeStallProtect(motorID, slaveI2cAddress, true); 195 | Serial.printf("readStallProtect:%d\r\n", rollercan.readStallProtect(motorID, slaveI2cAddress)); 196 | 197 | rollercan.writeButton(motorID, slaveI2cAddress, true); 198 | Serial.printf("readButton:%d\r\n", rollercan.readButton(motorID, slaveI2cAddress)); 199 | 200 | Serial.printf("readErrorCode:%d\r\n", rollercan.readErrorCode(motorID, slaveI2cAddress)); 201 | 202 | Serial.printf("readSysStatus:%d\r\n", rollercan.readSysStatus(motorID, slaveI2cAddress)); 203 | rollercan.writeMotorID(motorID, slaveI2cAddress, 15); 204 | delay(1000); 205 | Serial.printf("readMotorID:%d\r\n", rollercan.readMotorID(motorID, slaveI2cAddress)); 206 | 207 | rollercan.writeBPS(motorID, slaveI2cAddress, ROLLER_BPS_CAN_500000); 208 | Serial.printf("readBPS:%d\r\n", rollercan.readBPS(motorID, slaveI2cAddress)); 209 | rollercan.writeRawFlash(motorID, slaveI2cAddress, true); 210 | } 211 | 212 | void loop() 213 | { 214 | delay(1000); 215 | } -------------------------------------------------------------------------------- /src/unit_rolleri2c.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | *SPDX-License-Identifier: MIT 5 | */ 6 | 7 | #include "unit_rolleri2c.hpp" 8 | 9 | void UnitRollerI2C::writeBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, uint8_t length) 10 | { 11 | _wire->beginTransmission(addr); 12 | _wire->write(reg); 13 | for (int i = 0; i < length; i++) { 14 | _wire->write(*(buffer + i)); 15 | } 16 | _wire->endTransmission(); 17 | #if defined UNIT_ROLLER_DEBUG 18 | Serial.print("Writing to I2C address: 0x"); 19 | Serial.print(addr, HEX); 20 | Serial.print(", Register: 0x"); 21 | Serial.print(reg, HEX); 22 | Serial.print(", Data: "); 23 | for (int i = 0; i < length; i++) { 24 | Serial.print("0x"); 25 | Serial.print(*(buffer + i), HEX); 26 | if (i < length - 1) { 27 | Serial.print(", "); // Print comma except for the last element 28 | } 29 | } 30 | Serial.println(); // New line after printing all data 31 | #else 32 | #endif 33 | } 34 | 35 | void UnitRollerI2C::readBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, uint8_t length) 36 | { 37 | uint8_t index = 0; 38 | _wire->beginTransmission(addr); 39 | _wire->write(reg); 40 | _wire->endTransmission(false); 41 | _wire->requestFrom(addr, length); 42 | for (int i = 0; i < length; i++) { 43 | buffer[index++] = _wire->read(); 44 | } 45 | #if defined UNIT_ROLLER_DEBUG 46 | Serial.print("Reading from I2C address: 0x"); 47 | Serial.print(addr, HEX); 48 | Serial.print(", Register: 0x"); 49 | Serial.print(reg, HEX); 50 | Serial.print(", Length: "); 51 | Serial.println(length); 52 | for (int i = 0; i < length; i++) { 53 | Serial.print("0x"); 54 | Serial.print(buffer[i], HEX); 55 | if (i < length - 1) { 56 | Serial.print(", "); // Print comma except for the last element 57 | } 58 | } 59 | 60 | Serial.println(); // New line after printing all received data 61 | #endif 62 | } 63 | 64 | void UnitRollerI2C::floatToBytes(float s, uint8_t *d) 65 | { 66 | union { 67 | float value; 68 | uint8_t bytes[4]; 69 | } float_union_t; 70 | float_union_t.value = s; 71 | memcpy(d, float_union_t.bytes, 4); 72 | } 73 | 74 | float UnitRollerI2C::bytesToFloat(uint8_t *s) 75 | { 76 | union { 77 | float value; 78 | uint8_t bytes[4]; 79 | } bytes_union_t; 80 | memcpy(bytes_union_t.bytes, s, 4); 81 | return bytes_union_t.value; 82 | } 83 | 84 | bool UnitRollerI2C::begin(TwoWire *wire, uint8_t addr, uint8_t sda, uint8_t scl, uint32_t speed) 85 | { 86 | _wire = wire; 87 | _addr = addr; 88 | _sda = sda; 89 | _scl = scl; 90 | _speed = speed; 91 | _wire->begin(_sda, _scl); 92 | _wire->setClock(_speed); 93 | delay(10); 94 | _wire->beginTransmission(_addr); 95 | uint8_t error = _wire->endTransmission(); 96 | if (error == 0) { 97 | return true; 98 | } else { 99 | return false; 100 | } 101 | } 102 | 103 | void UnitRollerI2C::setMode(roller_mode_t mode) 104 | { 105 | uint8_t reg = I2C_MODE_REG; 106 | writeBytes(_addr, reg, (uint8_t *)&mode, 1); 107 | } 108 | 109 | void UnitRollerI2C::setOutput(uint8_t en) 110 | { 111 | uint8_t reg = I2C_OUTPUT_REG; 112 | writeBytes(_addr, reg, (uint8_t *)&en, 1); 113 | } 114 | 115 | void UnitRollerI2C::setSpeed(int32_t speed) 116 | { 117 | uint8_t reg = I2C_SPEED_REG; 118 | writeBytes(_addr, reg, (uint8_t *)&speed, 4); 119 | } 120 | 121 | void UnitRollerI2C::setSpeedMaxCurrent(int32_t current) 122 | { 123 | uint8_t reg = I2C_SPEED_MAX_CURRENT_REG; 124 | writeBytes(_addr, reg, (uint8_t *)¤t, 4); 125 | } 126 | 127 | void UnitRollerI2C::setSpeedPID(uint32_t p, uint32_t i, uint32_t d) 128 | { 129 | uint8_t data[12] = {0}; 130 | uint8_t reg = I2C_SPEED_PID_REG; 131 | 132 | memcpy(data, (uint8_t *)&p, 4); 133 | memcpy(data + 4, (uint8_t *)&i, 4); 134 | memcpy(data + 8, (uint8_t *)&d, 4); 135 | writeBytes(_addr, reg, data, 12); 136 | } 137 | 138 | void UnitRollerI2C::setPos(int32_t pos) 139 | { 140 | uint8_t reg = I2C_POS_REG; 141 | writeBytes(_addr, reg, (uint8_t *)&pos, 4); 142 | } 143 | 144 | void UnitRollerI2C::setPosMaxCurrent(int32_t current) 145 | { 146 | uint8_t reg = I2C_POS_MAX_CURRENT_REG; 147 | writeBytes(_addr, reg, (uint8_t *)¤t, 4); 148 | } 149 | 150 | void UnitRollerI2C::setPosPID(uint32_t p, uint32_t i, uint32_t d) 151 | { 152 | uint8_t data[12] = {0}; 153 | uint8_t reg = I2C_POS_PID_REG; 154 | 155 | memcpy(data, (uint8_t *)&p, 4); 156 | memcpy(data + 4, (uint8_t *)&i, 4); 157 | memcpy(data + 8, (uint8_t *)&d, 4); 158 | writeBytes(_addr, reg, data, 12); 159 | } 160 | 161 | void UnitRollerI2C::setCurrent(int32_t current) 162 | { 163 | uint8_t reg = I2C_CURRENT_REG; 164 | writeBytes(_addr, reg, (uint8_t *)¤t, 4); 165 | } 166 | 167 | void UnitRollerI2C::setDialCounter(int32_t counter) 168 | { 169 | uint8_t reg = I2C_DIAL_COUNTER_REG; 170 | writeBytes(_addr, reg, (uint8_t *)&counter, 4); 171 | } 172 | 173 | void UnitRollerI2C::setRGBMode(roller_rgb_t mode) 174 | { 175 | uint8_t reg = I2C_RGB_REG + 3; 176 | writeBytes(_addr, reg, (uint8_t *)&mode, 1); 177 | } 178 | 179 | void UnitRollerI2C::setRGB(int32_t color) 180 | { 181 | uint8_t reg = I2C_RGB_REG; 182 | uint8_t r = (color >> 11) & 0x1F; // R (5 bits) 183 | uint8_t g = (color >> 5) & 0x3F; // G (6 bits) 184 | uint8_t b = color & 0x1F; // B (5 bits) 185 | r = (r * 255) / 31; // Expand to 255 186 | g = (g * 255) / 63; // Expand to 255 187 | b = (b * 255) / 31; // Expand to 255 188 | uint8_t bgr[3] = {b, g, r}; 189 | writeBytes(_addr, reg, bgr, 3); 190 | } 191 | 192 | void UnitRollerI2C::setRGBBrightness(uint8_t brightness) 193 | { 194 | uint8_t reg = I2C_RGB_BRIGHTNESS_REG; 195 | writeBytes(_addr, reg, (uint8_t *)&brightness, 1); 196 | } 197 | 198 | void UnitRollerI2C::setMotorID(uint8_t id) 199 | { 200 | uint8_t reg = I2C_ID_REG; 201 | writeBytes(_addr, reg, (uint8_t *)&id, 1); 202 | } 203 | 204 | void UnitRollerI2C::setBPS(roller_bps_t bps) 205 | { 206 | uint8_t reg = I2C_BPS_REG; 207 | writeBytes(_addr, reg, (uint8_t *)&bps, 1); 208 | } 209 | 210 | void UnitRollerI2C::saveConfigToFlash(void) 211 | { 212 | uint8_t data = 1; 213 | uint8_t reg = I2C_SAVE_FLASH_REG; 214 | writeBytes(_addr, reg, (uint8_t *)&data, 1); 215 | } 216 | 217 | void UnitRollerI2C::posRangeProtect(uint8_t en) 218 | { 219 | uint8_t reg = I2C_POS_RANGE_PROTECT_REG; 220 | writeBytes(_addr, reg, (uint8_t *)&en, 1); 221 | } 222 | 223 | void UnitRollerI2C::resetStalledProtect(void) 224 | { 225 | uint8_t data = 1; 226 | uint8_t reg = I2C_RESET_STALLED_PROTECT_REG; 227 | writeBytes(_addr, reg, (uint8_t *)&data, 1); 228 | } 229 | 230 | void UnitRollerI2C::setKeySwitchMode(uint8_t en) 231 | { 232 | uint8_t reg = I2C_KEY_SWTICH_MODE_REG; 233 | writeBytes(_addr, reg, (uint8_t *)&en, 1); 234 | } 235 | 236 | void UnitRollerI2C::setStallProtection(uint8_t en) 237 | { 238 | uint8_t reg = I2C_STALL_PROTECTION_REG; 239 | writeBytes(_addr, reg, (uint8_t *)&en, 1); 240 | } 241 | 242 | uint8_t UnitRollerI2C::setI2CAddress(uint8_t addr) 243 | { 244 | uint8_t data[2] = {0}; 245 | data[0] = I2C_ADDRESS_REG; 246 | _wire->beginTransmission(_addr); 247 | _wire->write(data[0]); 248 | _wire->write(addr); 249 | _wire->endTransmission(); 250 | _addr = addr; 251 | return _addr; 252 | } 253 | 254 | void UnitRollerI2C::startAngleCal(void) 255 | { 256 | uint8_t temp = 1; 257 | uint8_t reg = START_ANGLE_CAL_REG; 258 | writeBytes(_addr, reg, (uint8_t *)&temp, 1); 259 | } 260 | 261 | void UnitRollerI2C::updateAngleCal(void) 262 | { 263 | uint8_t temp = 1; 264 | uint8_t reg = UPDATE_ANGLE_CAL_REG; 265 | writeBytes(_addr, reg, (uint8_t *)&temp, 1); 266 | } 267 | 268 | uint8_t UnitRollerI2C::getCalBusyStatus(void) 269 | { 270 | uint8_t temp = 0; 271 | uint8_t reg = GET_ANGLE_BUSY_REG; 272 | readBytes(_addr, reg, (uint8_t *)&temp, 1); 273 | 274 | return temp; 275 | } 276 | 277 | void UnitRollerI2C::getSpeedPID(uint32_t *p, uint32_t *i, uint32_t *d) 278 | { 279 | uint8_t data[12]; 280 | readBytes(_addr, I2C_SPEED_PID_REG, (uint8_t *)&data, 12); 281 | memcpy(p, (uint8_t *)&data[0], 4); 282 | memcpy(i, (uint8_t *)&data[4], 4); 283 | memcpy(d, (uint8_t *)&data[8], 4); 284 | } 285 | 286 | void UnitRollerI2C::getPosPID(uint32_t *p, uint32_t *i, uint32_t *d) 287 | { 288 | uint8_t data[12]; 289 | readBytes(_addr, I2C_POS_PID_REG, (uint8_t *)&data, 12); 290 | memcpy(p, (uint8_t *)&data[0], 4); 291 | memcpy(i, (uint8_t *)&data[4], 4); 292 | memcpy(d, (uint8_t *)&data[8], 4); 293 | } 294 | 295 | void UnitRollerI2C::getRGB(uint8_t *r, uint8_t *g, uint8_t *b) 296 | { 297 | uint8_t data[3]; 298 | uint8_t reg = I2C_RGB_REG; 299 | readBytes(_addr, reg, (uint8_t *)&data, 3); 300 | memcpy(r, (uint8_t *)&data[2], 1); 301 | memcpy(g, (uint8_t *)&data[1], 1); 302 | memcpy(b, (uint8_t *)&data[0], 1); 303 | } 304 | 305 | int32_t UnitRollerI2C::getSpeed(void) 306 | { 307 | int32_t data = 0; 308 | uint8_t reg = I2C_SPEED_REG; 309 | readBytes(_addr, reg, (uint8_t *)&data, 4); 310 | return data; 311 | } 312 | 313 | int32_t UnitRollerI2C::getSpeedMaxCurrent(void) 314 | { 315 | int32_t data = 0; 316 | uint8_t reg = I2C_SPEED_MAX_CURRENT_REG; 317 | readBytes(_addr, reg, (uint8_t *)&data, 4); 318 | return data; 319 | } 320 | 321 | int32_t UnitRollerI2C::getSpeedReadback(void) 322 | { 323 | int32_t data = 0; 324 | uint8_t reg = I2C_SPEED_READBACK_REG; 325 | readBytes(_addr, reg, (uint8_t *)&data, 4); 326 | return data; 327 | } 328 | 329 | int32_t UnitRollerI2C::getPos(void) 330 | { 331 | int32_t data = 0; 332 | uint8_t reg = I2C_POS_REG; 333 | readBytes(_addr, reg, (uint8_t *)&data, 4); 334 | return data; 335 | } 336 | 337 | int32_t UnitRollerI2C::getPosMaxCurrent(void) 338 | { 339 | int32_t data = 0; 340 | uint8_t reg = I2C_POS_MAX_CURRENT_REG; 341 | readBytes(_addr, reg, (uint8_t *)&data, 4); 342 | return data; 343 | } 344 | 345 | int32_t UnitRollerI2C::getPosReadback(void) 346 | { 347 | int32_t data = 0; 348 | uint8_t reg = I2C_POS_READBACK_REG; 349 | readBytes(_addr, reg, (uint8_t *)&data, 4); 350 | return data; 351 | } 352 | 353 | int32_t UnitRollerI2C::getCurrent(void) 354 | { 355 | int32_t data = 0; 356 | uint8_t reg = I2C_CURRENT_REG; 357 | readBytes(_addr, reg, (uint8_t *)&data, 4); 358 | return data; 359 | } 360 | 361 | int32_t UnitRollerI2C::getCurrentReadback(void) 362 | { 363 | int32_t data = 0; 364 | uint8_t reg = I2C_CURRENT_READBACK_REG; 365 | readBytes(_addr, reg, (uint8_t *)&data, 4); 366 | return data; 367 | } 368 | 369 | int32_t UnitRollerI2C::getDialCounter(void) 370 | { 371 | int32_t data = 0; 372 | uint8_t reg = I2C_DIAL_COUNTER_REG; 373 | readBytes(_addr, reg, (uint8_t *)&data, 4); 374 | 375 | return data; 376 | } 377 | 378 | int32_t UnitRollerI2C::getVin(void) 379 | { 380 | int32_t data = 0; 381 | uint8_t reg = I2C_VIN_REG; 382 | readBytes(_addr, reg, (uint8_t *)&data, 4); 383 | 384 | return data; 385 | } 386 | 387 | int32_t UnitRollerI2C::getTemp(void) 388 | { 389 | int32_t data = 0; 390 | uint8_t reg = I2C_TEMP_REG; 391 | readBytes(_addr, reg, (uint8_t *)&data, 4); 392 | 393 | return data; 394 | } 395 | 396 | uint8_t UnitRollerI2C::getSysStatus(void) 397 | { 398 | uint8_t data = 0; 399 | uint8_t reg = I2C_SYS_STATUS_REG; 400 | readBytes(_addr, reg, (uint8_t *)&data, 1); 401 | 402 | return data; 403 | } 404 | 405 | uint8_t UnitRollerI2C::getErrorCode(void) 406 | { 407 | uint8_t data = 0; 408 | uint8_t reg = I2C_ERROR_CODE_REG; 409 | readBytes(_addr, reg, (uint8_t *)&data, 1); 410 | 411 | return data; 412 | } 413 | 414 | uint8_t UnitRollerI2C::getPosRangeProtect(void) 415 | { 416 | uint8_t data = 0; 417 | uint8_t reg = I2C_POS_RANGE_PROTECT_REG; 418 | readBytes(_addr, reg, (uint8_t *)&data, 1); 419 | return data; 420 | } 421 | 422 | uint8_t UnitRollerI2C::getStallProtection(void) 423 | { 424 | uint8_t data = 0; 425 | uint8_t reg = I2C_STALL_PROTECTION_REG; 426 | readBytes(_addr, reg, (uint8_t *)&data, 1); 427 | 428 | return data; 429 | } 430 | 431 | uint8_t UnitRollerI2C::getKeySwitchMode(void) 432 | { 433 | uint8_t data = 0; 434 | uint8_t reg = I2C_KEY_SWTICH_MODE_REG; 435 | readBytes(_addr, reg, (uint8_t *)&data, 1); 436 | return data; 437 | } 438 | uint8_t UnitRollerI2C::getOutputStatus(void) 439 | { 440 | uint8_t data = 0; 441 | uint8_t reg = I2C_OUTPUT_REG; 442 | readBytes(_addr, reg, (uint8_t *)&data, 1); 443 | return data; 444 | } 445 | 446 | uint8_t UnitRollerI2C::getMotorMode(void) 447 | { 448 | uint8_t data = 0; 449 | uint8_t reg = I2C_MODE_REG; 450 | readBytes(_addr, reg, (uint8_t *)&data, 1); 451 | return data; 452 | } 453 | 454 | uint8_t UnitRollerI2C::getMotorID(void) 455 | { 456 | uint8_t data = 0; 457 | uint8_t reg = I2C_ID_REG; 458 | readBytes(_addr, reg, (uint8_t *)&data, 1); 459 | return data; 460 | } 461 | 462 | uint8_t UnitRollerI2C::getBPS(void) 463 | { 464 | uint8_t data = 0; 465 | uint8_t reg = I2C_BPS_REG; 466 | readBytes(_addr, reg, (uint8_t *)&data, 1); 467 | return data; 468 | } 469 | 470 | uint8_t UnitRollerI2C::getRGBBrightness(void) 471 | { 472 | uint8_t data = 0; 473 | uint8_t reg = I2C_RGB_BRIGHTNESS_REG; 474 | readBytes(_addr, reg, (uint8_t *)&data, 1); 475 | return data; 476 | } 477 | 478 | uint8_t UnitRollerI2C::getRGBMode(void) 479 | { 480 | uint8_t data = 0; 481 | uint8_t reg = I2C_RGB_REG + 3; 482 | readBytes(_addr, reg, (uint8_t *)&data, 1); 483 | return data; 484 | } 485 | 486 | uint8_t UnitRollerI2C::getFirmwareVersion(void) 487 | { 488 | _wire->beginTransmission(_addr); 489 | _wire->write(I2C_FIRMWARE_VERSION_REG); 490 | _wire->endTransmission(false); 491 | 492 | uint8_t RegValue; 493 | _wire->requestFrom(_addr, 1); 494 | RegValue = Wire.read(); 495 | return RegValue; 496 | } 497 | 498 | uint8_t UnitRollerI2C::getI2CAddress(void) 499 | { 500 | uint8_t data[2] = {0}; 501 | 502 | data[0] = I2C_ADDRESS_REG; 503 | _wire->beginTransmission(_addr); 504 | _wire->write(data[0]); 505 | _wire->endTransmission(false); 506 | uint8_t RegValue; 507 | _wire->requestFrom(_addr, 1); 508 | RegValue = Wire.read(); 509 | return RegValue; 510 | } 511 | -------------------------------------------------------------------------------- /src/unit_roller485.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | *SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | *SPDX-License-Identifier: MIT 5 | */ 6 | 7 | #ifndef __UNIT_ROLLER485_H 8 | #define __UNIT_ROLLER485_H 9 | 10 | #include "Arduino.h" 11 | #include "unit_roller_common.hpp" 12 | 13 | /** 14 | * @brief Command to set output parameters of the Unit Roller. 15 | */ 16 | #define ROLLER485_SET_OUTPUT_CMD (0x00) 17 | 18 | /** 19 | * @brief Command to set the mode of the Unit Roller. 20 | */ 21 | #define ROLLER485_SET_MODE_CMD (0x01) 22 | 23 | /** 24 | * @brief Command to remove protection features from the Unit Roller. 25 | */ 26 | #define ROLLER485_REMOVE_PROTECTION_CMD (0x06) 27 | 28 | /** 29 | * @brief Command to save settings or data to flash memory. 30 | */ 31 | #define ROLLER485_SAVE_FLASH_CMD (0x07) 32 | 33 | /** 34 | * @brief Command to interact with the encoder. 35 | */ 36 | #define ROLLER485_ENCODER_CMD (0x08) 37 | 38 | /** 39 | * @brief Command to handle button interactions. 40 | */ 41 | #define ROLLER485_BUTTON_CMD (0x09) 42 | 43 | /** 44 | * @brief Command to set RGB parameters. 45 | */ 46 | #define ROLLER485_SET_RGB_CMD (0x0A) 47 | 48 | /** 49 | * @brief Command to set the baud rate for communication. 50 | */ 51 | #define ROLLER485_BAUD_RATE_CMD (0x0B) 52 | 53 | /** 54 | * @brief Command to set the motor ID. 55 | */ 56 | #define ROLLER485_SET_MOTOR_ID_CMD (0x0C) 57 | 58 | /** 59 | * @brief Command to enable jam protection features. 60 | */ 61 | #define ROLLER485_JAM_PROTECTION_CMD (0x0D) 62 | 63 | /** 64 | * @brief command is used to set the speed in speed mode. 65 | */ 66 | #define ROLLER485_SPEED_MODE_CMD (0x20) 67 | 68 | /** 69 | * @brief command is used to set the speed PID in speed mode. 70 | */ 71 | #define ROLLER485_SPEED_PID_CMD (0x21) 72 | 73 | /** 74 | * @brief command is used to set the opsition in opsition mode. 75 | */ 76 | #define ROLLER485_POSITION_MODE_CMD (0x22) 77 | 78 | /** 79 | * @brief command is used to set the opsition PID in speed mode. 80 | */ 81 | #define ROLLER485_POSITION_PID_CMD (0x23) 82 | 83 | /** 84 | * @brief command is used to set the current in current mode. 85 | */ 86 | #define ROLLER485_CURRENT_MODE_CMD (0x24) 87 | 88 | /** 89 | * @brief Command to read back parameter group 0. 90 | */ 91 | #define ROLLER485_READ_BACK0_CMD (0x40) 92 | 93 | /** 94 | * @brief Command to read back parameter group 1. 95 | */ 96 | #define ROLLER485_READ_BACK1_CMD (0x41) 97 | 98 | /** 99 | * @brief Command to read back parameter group 2. 100 | */ 101 | #define ROLLER485_READ_BACK2_CMD (0x42) 102 | 103 | /** 104 | * @brief Command to read back parameter group 3. 105 | */ 106 | #define ROLLER485_READ_BACK3_CMD (0x43) 107 | 108 | /** 109 | * @brief Command to read I2C data from address 1. 110 | */ 111 | #define ROLLER485_READ_I2C_DATA1_CMD (0x60) 112 | 113 | /** 114 | * @brief Command to read I2C data from address 2. 115 | */ 116 | #define ROLLER485_READ_I2C_DATA2_CMD (0x62) 117 | 118 | /** 119 | * @brief Command to write I2C data to address 1. 120 | */ 121 | #define ROLLER485_WRITE_I2C_DATA1_CMD (0x61) 122 | 123 | /** 124 | * @brief Command to write I2C data to address 1. 125 | */ 126 | #define ROLLER485_WRITE_I2C_DATA2_CMD (0x63) 127 | 128 | /** 129 | * @brief Length of I2C data being transferred. 130 | * 131 | * This constant defines the standard length for I2C data transactions. 132 | */ 133 | #define ROLLER485_I2C_DATA_LEN (0x10) 134 | 135 | class UnitRoller485 { 136 | public: 137 | HardwareSerial *serialPort; 138 | 139 | /** 140 | * @brief Initializes the hardware serial communication interface. 141 | * 142 | * This function sets up the serial communication for the UnitRoller485 class, 143 | * configuring parameters such as baud rate, pin assignments, signal inversion, 144 | * and timeouts. It is essential to call this function before attempting to = 145 | * communicate using the serial interface. 146 | * 147 | * @param serial Pointer to a HardwareSerial object used for the serial communication. 148 | * @param baud The baud rate for serial communication (e.g., 9600, 115200). 149 | * @param config Configuration parameter for serial settings (default: SERIAL_8N1). 150 | * This specifies data bits, parity, and stop bits. 151 | * @param rxPin The GPIO pin number designated for receiving data (default: -1 for auto). 152 | * @param txPin The GPIO pin number designated for transmitting data (default: -1 for auto). 153 | * @param dirPin The GPIO pin number used for direction control in RS-485 mode 154 | * (default: -1 indicates no direction control). 155 | * @param invert A boolean value indicating whether to invert the signal (true for RS-485 156 | * communication, which may require signal inversion). 157 | * @param timeout_ms The read timeout duration in milliseconds; specifies how long 158 | * to wait for incoming data before timing out (default: 10000 ms). 159 | * @param rxfifo_full_thrhd The threshold for the received FIFO buffer full condition; 160 | * when the buffer reaches this size, an overflow warning may be triggered (default: 112). 161 | */ 162 | void begin(HardwareSerial *serial, unsigned long baud, uint32_t config = SERIAL_8N1, int8_t rxPin = -1, 163 | int8_t txPin = -1, int8_t dirPin = -1, bool invert = false, unsigned long timeout_ms = 10000UL, 164 | uint8_t rxfifo_full_thrhd = 112UL); 165 | 166 | /** 167 | * @brief sends data 168 | * 169 | * Send data through a serial port in the UnitRoller485 class. 170 | * 171 | * @param data points to a character pointer to send data 172 | * @param length Length of the data to be sent 173 | * 174 | * @return true if the data is sent statefully. Otherwise return false 175 | */ 176 | bool sendData(const char *data, size_t length); 177 | 178 | /** 179 | * @brief reads data 180 | * 181 | * Reads data from a serial port in class UnitRoller485 and applies a timeout during the read. 182 | * Read data is first stored in an internal buffer, and then specific header information (such as "AA 55") is 183 | * removed. 184 | * 185 | * @return Number of bytes read statefully (excluding removed headers) 186 | */ 187 | size_t readData(); 188 | 189 | /** 190 | * @brief calculates 8-bit CRC 191 | * 192 | * Calculates and returns an 8-bit CRC value based on the given data array and length. 193 | * 194 | * @param data Data array pointer that contains the data to calculate CRC 195 | * @param len Length of the data array 196 | * 197 | * @return Calculated 8-bit CRC value 198 | */ 199 | uint8_t crc8(uint8_t *data, uint8_t len); 200 | 201 | /** 202 | * @brief Set motor enable or off 203 | * @param id Motor equipment id Value range:0~255 204 | * @param motorEn motor enable or off 205 | * @return The result or error code of the response validation 206 | */ 207 | int8_t setOutput(uint8_t id, bool motorEn); 208 | 209 | /** 210 | * @brief Set motor mode 211 | * @param id Motor equipment id Value range:0~255 212 | * @param mode Mode setting 1: Speed Mode 2: Position Mode 3: Current 213 | * Mode 4. Encoder Mode 214 | * @return The result or error code of the response validation 215 | */ 216 | int8_t setMode(uint8_t id, roller_mode_t mode); 217 | 218 | /** 219 | * @brief Set Remove protection 220 | * @param id Motor equipment id Value range:0~255 221 | * @param protectionEn Release Jam protection: Send 1 to unprotect 222 | * @return The result or error code of the response validation 223 | */ 224 | int8_t setRemoveProtection(uint8_t id, bool protectionEn); 225 | 226 | /** 227 | * @brief Save to flash 228 | * @param id Motor equipment id Value range:0~255 229 | * @param saveFlashEn Save to flash: Send 1 save parameters to flash 230 | * @return The result or error code of the response validation 231 | */ 232 | int8_t setSaveFlash(uint8_t id, bool saveFlashEn); 233 | 234 | /** 235 | * @brief Set encoder value 236 | * @param id Motor equipment id Value range:0~255 237 | * @param encoder Encoder value(int32_t) 238 | * @return The result or error code of the response validation 239 | */ 240 | int8_t setEncoder(uint8_t id, int32_t encoder); 241 | 242 | /** 243 | * @brief Set button switching mode enable 244 | * @param id Motor equipment id Value range:0~255 245 | * @param buttonEn 0: Off; 1: Press and hold for 5S to switch modes in running 246 | * mode. 247 | * @return The result or error code of the response validation 248 | */ 249 | int8_t setButton(uint8_t id, bool buttonEn); 250 | 251 | /** 252 | * @brief Set RGB (RGB Mode and RGB Brightness can be save to flash) 253 | * @param id Motor equipment id Value range:0~255 254 | * @param rgbR Value range:0~255 255 | * @param rgbG Value range:0~255 256 | * @param rgbB Value range:0~255 257 | * @param rgbBrightness Value range:0~100 258 | * @param rgbMode Mode: 0, Sys-default 1,user-define Default 259 | * value:0 260 | * @return The result or error code of the response validation 261 | */ 262 | int8_t setRGB(uint8_t id, uint8_t rgbR, uint8_t rgbG, uint8_t rgbB, uint8_t rgbBrightness, roller_rgb_t rgbMode); 263 | 264 | /** 265 | * @brief Set baud rate (can be save to flash) 266 | * @param id Motor equipment id Value range:0~255 267 | * @param baudRate BPS: 0,115200bps; 1, 19200bps; 2, 9600bps; Default 268 | * value:0 269 | * @return The result or error code of the response validation 270 | */ 271 | int8_t setBaudRate(uint8_t id, roller_bps_t baudRate); 272 | 273 | /** 274 | * @brief Set motor id (can be save to flash) 275 | * @param id Motor equipment id Value range:0~255 276 | * @param motorId Value range:0~255 277 | * @return The result or error code of the response validation 278 | */ 279 | int8_t setMotorId(uint8_t id, uint8_t motorId); 280 | 281 | /** 282 | * @brief Set motor jam protection 283 | * @param id Motor equipment id Value range:0~255 284 | * @param protectionEn Motor Jam Protection: 0,Disable; 1, Enable 285 | * @return The result or error code of the response validation 286 | */ 287 | int8_t setJamProtection(uint8_t id, bool protectionEn); 288 | 289 | /** 290 | * @brief Set speed mode configur ation 291 | * @param id Motor equipment id Value range:0~255 292 | * @param speed Speed Value:-21000000 ~21000000 293 | * @param current current Value:-1200 ~1200 294 | * @return The result or error code of the response validation 295 | */ 296 | int32_t setSpeedMode(uint8_t id, int32_t speed, int32_t current); 297 | 298 | /** 299 | * @brief Set the speed mode PID configuration 300 | * @param id Motor equipment id Value range:0~255 301 | * @param speedP For example: mottor P=0.004, speedP setting 302 | * value=0.004*100000=400, 303 | * @param speedI For example: mottor I=0.002, speedI setting 304 | * value=0.002*10000000=20000, 305 | * @param speedD For example: mottor D=16.00, speedD setting 306 | * value=16.00*100000=1600000, 307 | * @return The result or error code of the response validation 308 | */ 309 | int32_t setSpeedPID(uint8_t id, uint32_t speedP, uint32_t speedI, uint32_t speedD); 310 | 311 | /** 312 | * @brief Set position mode configur ation 313 | * @param id Motor equipment id Value range:0~255 314 | * @param position Speed Value:-21000000 ~21000000 315 | * @param current current Value:-1200 ~1200 316 | * @return The result or error code of the response validation 317 | */ 318 | int32_t setPositionMode(uint8_t id, int32_t position, int32_t current); 319 | 320 | /** 321 | * @brief Set the position mode PID configuration 322 | * @param id Motor equipment id Value range:0~255 323 | * @param positionP For example: mottor P=0.004, positionP setting 324 | * value=0.004*100000=400, 325 | * @param positionI For example: mottor I=0.002, positionI setting 326 | * value=0.002*10000000=20000, 327 | * @param positionD For example: mottor D=16.00, positionD setting 328 | * value=16.00*100000=1600000, 329 | * @return The result or error code of the response validation 330 | */ 331 | int32_t setPositionPID(uint8_t id, uint32_t positionP, uint32_t positionI, uint32_t positionD); 332 | 333 | /** 334 | * @brief Set current mode configur ation 335 | * @param id Motor equipment id Value range:0~255 336 | * @param current current Value:-1200 ~1200 337 | * @return The result or error code of the response validation 338 | */ 339 | int32_t setCurrentMode(uint8_t id, int32_t current); 340 | 341 | /** 342 | * @brief Get motor speed 343 | * @param id Motor equipment id Value range:0~255 344 | * @return The result or error code of the response validation 345 | */ 346 | int32_t getActualSpeed(uint8_t id); 347 | 348 | /** 349 | * @brief Get motor position 350 | * @param id Motor equipment id Value range:0~255 351 | * @return The result or error code of the response validation 352 | */ 353 | int32_t getActualPosition(uint8_t id); 354 | 355 | /** 356 | * @brief Get motor current 357 | * @param id Motor equipment id Value range:0~255 358 | * @return The result or error code of the response validation 359 | */ 360 | int32_t getActualCurrent(uint8_t id); 361 | 362 | /** 363 | * @brief Get motor encoder 364 | * @param id Motor equipment id Value range:0~255 365 | * @return The result or error code of the response validation 366 | */ 367 | int32_t getEncoder(uint8_t id); 368 | /** 369 | * @brief Get motor vin 370 | * @param id Motor equipment id Value range:0~255 371 | * @return The result or error code of the response validation 372 | */ 373 | int32_t getActualVin(uint8_t id); 374 | 375 | /** 376 | * @brief Get motor temperature 377 | * @param id Motor equipment id Value range:0~255 378 | * @return The result or error code of the response validation 379 | */ 380 | int32_t getActualTemp(uint8_t id); 381 | 382 | /** 383 | * @brief Get motor id 384 | * @param id Motor equipment id Value range:0~255 385 | * @return The result or error code of the response validation 386 | */ 387 | int32_t getMotorId(uint8_t id); 388 | 389 | /** 390 | * @brief Get motor speed PID 391 | * @param id Motor equipment id Value range:0~255 392 | * @return The result or error code of the response validation 393 | */ 394 | int8_t getSpeedPID(uint8_t id, double *speedPID); 395 | 396 | /** 397 | * @brief Get motor position PID 398 | * @param id Motor equipment id Value range:0~255 399 | * @return The result or error code of the response validation 400 | */ 401 | int8_t getPositionPID(uint8_t id, double *positionPID); 402 | 403 | /** 404 | * @brief Get motor RGB mode 405 | * @param id Motor equipment id Value range:0~255 406 | */ 407 | int8_t getRGB(uint8_t id, uint8_t *rgbValues); 408 | 409 | /** 410 | * @brief Get motor mode 411 | * @param id Motor equipment id Value range:0~255 412 | * @return The result or error code of the response validation 413 | */ 414 | int8_t getMode(uint8_t id); 415 | 416 | /** 417 | * @brief Get motor status 418 | * @param id Motor equipment id Value range:0~255 419 | * @return The result or error code of the response validation 420 | */ 421 | int8_t getStatus(uint8_t id); 422 | 423 | /** 424 | * @brief Get motor error 425 | * @param id Motor equipment id Value range:0~255 426 | * @return The result or error code of the response validation 427 | */ 428 | int8_t getError(uint8_t id); 429 | 430 | /** 431 | * @brief Get motor RGB mode 432 | * @param id Motor equipment id Value range:0~255 433 | * @return The result or error code of the response validation 434 | */ 435 | int8_t getRGBMode(uint8_t id); 436 | 437 | /** 438 | * @brief Get motor RGB rgbBrightness 439 | * @param id Motor equipment id Value range:0~255 440 | * @return The result or error code of the response validation 441 | */ 442 | int8_t getRGBBrightness(uint8_t id); 443 | 444 | /** 445 | * @brief Get motor baudrate 446 | * @param id Motor equipment id Value range:0~255 447 | * @return The result or error code of the response validation 448 | */ 449 | int8_t getBaudRate(uint8_t id); 450 | 451 | /** 452 | * @brief Get motor button 453 | * @param id Motor equipment id Value range:0~255 454 | * @return The result or error code of the response validation 455 | */ 456 | int8_t getButton(uint8_t id); 457 | // 485->i2c 458 | 459 | /** 460 | * @brief reads I2C device data 461 | * 462 | * Reads data from the I2C device with the specified ID, address, and data length, and stores the read data into the 463 | * given read buffer. 464 | * 465 | * @param id ID of the I2C device 466 | * @param address Indicates the address of the I2C device 467 | * @param dataLen Length of data to be read 468 | * @param readBuffer Buffer used to store the read data 469 | * 470 | * @return The number of bytes read statefully, and an error code if an error occurs 471 | */ 472 | int8_t readI2c(uint8_t id, uint8_t address, uint8_t dataLen, uint8_t *readBuffer); 473 | 474 | /** 475 | * @brief reads data from the I2C device 476 | * 477 | * Reads data from the I2C device with the specified ID, address, address length, register address, and data length, 478 | * and stores the read data into the given read buffer. 479 | * 480 | * @param id ID of the I2C device 481 | * @param address Base address of the I2C device 482 | * @param addressLen The length of the address (usually 1 or 2, depending on the register address structure of the 483 | * I2C device) 484 | * @param regByte0 High byte of register address (if addressLen is 2, otherwise ignored) 485 | * @param regByte1 Low byte of register address 486 | * @param dataLen Length of data to be read 487 | * @param readBuffer Buffer used to store the read data 488 | * 489 | * @return The number of bytes read statefully, and an error code if an error occurs 490 | */ 491 | int8_t readI2c(uint8_t id, uint8_t address, uint8_t addressLen, uint8_t regByte0, uint8_t regByte1, uint8_t dataLen, 492 | uint8_t *readBuffer); 493 | 494 | /** 495 | * @brief reads the motor speed PID from the I2C device 496 | * @param id Motor equipment id Value range:0~255 497 | * @param address Address of the I2C device Value range:0~127 498 | * @param speedPID Pointer to type double to store the read speedPID parameter 499 | * 500 | * @return Indicates the operation status code. 1 is returned if the operation succeeds. Otherwise, an error code is 501 | * returned 502 | */ 503 | int8_t readSpeedPID(uint8_t id, uint8_t address, double *speedPID); 504 | 505 | /** 506 | * @brief reads the motor postion PID from the I2C device 507 | * @param id Motor equipment id Value range:0~255 508 | * @param address Address of the I2C device Value range:0~127 509 | * @param positionPID Pointer to type double to store the read postionPID parameter 510 | * 511 | * @return Indicates the operation status code. 1 is returned if the operation succeeds. Otherwise, an error code is 512 | * returned 513 | */ 514 | int8_t readPositionPID(uint8_t id, uint8_t address, double *positionPID); 515 | 516 | /** 517 | * @brief reads the motor rgb from the I2C device 518 | * @param id Motor equipment id Value range:0~255 519 | * @param address Address of the I2C device Value range:0~127 520 | * @param rgbValues Pointer to type double to store the read rgbValues parameter 521 | * 522 | * @return Indicates the operation status code. 1 is returned if the operation succeeds. Otherwise, an error code is 523 | * returned 524 | */ 525 | int8_t readRGB(uint8_t id, uint8_t address, uint8_t *rgbValues); 526 | 527 | /** 528 | * @brief reads the output from the I2C device 529 | * 530 | * Read the output value from the I2C device with the specified ID and address (possibly a motor configuration 531 | * register). 532 | * 533 | * @param id Motor equipment id Value range:0~255 534 | * @param address Address of the I2C device Value range:0~127 535 | * 536 | * @return Read the output value and return an error code if an error occurs 537 | */ 538 | int8_t readOutput(uint8_t id, uint8_t address); 539 | 540 | /** 541 | * @brief reads the mode from the I2C device 542 | * @param id Motor equipment id Value range:0~255 543 | * @param address Address of the I2C device Value range:0~127 544 | * @return Read the mode value and return an error code if an error occurs 545 | */ 546 | int8_t readMode(uint8_t id, uint8_t address); 547 | 548 | /** 549 | * @brief reads the status from the I2C device 550 | * @param id Motor equipment id Value range:0~255 551 | * @param address Address of the I2C device Value range:0~127 552 | * @return Read the status value and return an error code if an error occurs 553 | */ 554 | int8_t readStatus(uint8_t id, uint8_t address); 555 | 556 | /** 557 | * @brief reads the error from the I2C device 558 | * @param id Motor equipment id Value range:0~255 559 | * @param address Address of the I2C device Value range:0~127 560 | * @return Read the error value and return an error code if an error occurs 561 | */ 562 | int8_t readError(uint8_t id, uint8_t address); 563 | 564 | /** 565 | * @brief reads the button from the I2C device 566 | * @param id Motor equipment id Value range:0~255 567 | * @param address Address of the I2C device Value range:0~127 568 | * @return Read the button value and return an error code if an error occurs 569 | */ 570 | int8_t readButton(uint8_t id, uint8_t address); 571 | 572 | /** 573 | * @brief reads the motor position over range protection from the I2C device 574 | * @param id Motor equipment id Value range:0~255 575 | * @param address Address of the I2C device Value range:0~127 576 | * @return Read the motor position over range protection value and return an error code if an error occurs 577 | */ 578 | int8_t readRangeProtection(uint8_t id, uint8_t address); 579 | 580 | /** 581 | * @brief reads the stall protection from the I2C device 582 | * @param id Motor equipment id Value range:0~255 583 | * @param address Address of the I2C device Value range:0~127 584 | * @return Read the stall protection value and return an error code if an error occurs 585 | */ 586 | int8_t readStallProtection(uint8_t id, uint8_t address); 587 | 588 | /** 589 | * @brief reads the motor baud rate from the I2C device 590 | * @param id Motor equipment id Value range:0~255 591 | * @param address Address of the I2C device Value range:0~127 592 | * @return Read the baud rate value and return an error code if an error occurs 593 | */ 594 | int8_t readBaudRate(uint8_t id, uint8_t address); 595 | 596 | /** 597 | * @brief reads the motor rgbbrightness from the I2C device 598 | * @param id Motor equipment id Value range:0~255 599 | * @param address Address of the I2C device Value range:0~127 600 | * @return Read the rgbbrightness value and return an error code if an error occurs 601 | */ 602 | int8_t readRgbBrightness(uint8_t id, uint8_t address); 603 | 604 | /** 605 | * @brief reads the motor version from the I2C device 606 | * @param id Motor equipment id Value range:0~255 607 | * @param address Address of the I2C device Value range:0~127 608 | * @return Read the version value and return an error code if an error occurs 609 | */ 610 | int8_t readVersion(uint8_t id, uint8_t address); 611 | 612 | /** 613 | * @brief reads the motor i2caAddress from the I2C device 614 | * @param id Motor equipment id Value range:0~255 615 | * @param address Address of the I2C device Value range:0~127 616 | * @return Read the i2caAddress value and return an error code if an error occurs 617 | */ 618 | int8_t readI2cAddress(uint8_t id, uint8_t address); 619 | 620 | /** 621 | * @brief reads the motor id from the I2C device 622 | * @param id Motor equipment id Value range:0~255 623 | * @param address Address of the I2C device Value range:0~127 624 | * @return Read the id value and return an error code if an error occurs 625 | */ 626 | int8_t readMotorId(uint8_t id, uint8_t address); 627 | 628 | /** 629 | * @brief reads the motor speed from the I2C device 630 | * @param id Motor equipment id Value range:0~255 631 | * @param address Address of the I2C device Value range:0~127 632 | * @return Read the speed value and return an error code if an error occurs 633 | */ 634 | int32_t readSpeed(uint8_t id, uint8_t address); 635 | 636 | /** 637 | * @brief reads the motor speed current from the I2C device 638 | * @param id Motor equipment id Value range:0~255 639 | * @param address Address of the I2C device Value range:0~127 640 | * @return Read the speed current value and return an error code if an error occurs 641 | */ 642 | int32_t readSpeedCurrent(uint8_t id, uint8_t address); 643 | 644 | /** 645 | * @brief reads the motor speed from the I2C device 646 | * @param id Motor equipment id Value range:0~255 647 | * @param address Address of the I2C device Value range:0~127 648 | * @return Read the actual speed readback value and return an error code if an error occurs 649 | */ 650 | int32_t readSpeedReadback(uint8_t id, uint8_t address); 651 | 652 | /** 653 | * @brief reads the motor position from the I2C device 654 | * @param id Motor equipment id Value range:0~255 655 | * @param address Address of the I2C device Value range:0~127 656 | * @return Read the postion value and return an error code if an error occurs 657 | */ 658 | int32_t readPosition(uint8_t id, uint8_t address); 659 | 660 | /** 661 | * @brief reads the motor position current from the I2C device 662 | * @param id Motor equipment id Value range:0~255 663 | * @param address Address of the I2C device Value range:0~127 664 | * @return Read the position current value and return an error code if an error occurs 665 | */ 666 | int32_t readPositionCurrent(uint8_t id, uint8_t address); 667 | 668 | /** 669 | * @brief reads the motor position from the I2C device 670 | * @param id Motor equipment id Value range:0~255 671 | * @param address Address of the I2C device Value range:0~127 672 | * @return Read the actual postion readback value and return an error code if an error occurs 673 | */ 674 | int32_t readPositionReadback(uint8_t id, uint8_t address); 675 | 676 | /** 677 | * @brief reads the motor current from the I2C device 678 | * @param id Motor equipment id Value range:0~255 679 | * @param address Address of the I2C device Value range:0~127 680 | * @return Read the current value and return an error code if an error occurs 681 | */ 682 | int32_t readCurrent(uint8_t id, uint8_t address); 683 | 684 | /** 685 | * @brief reads the motor current from the I2C device 686 | * @param id Motor equipment id Value range:0~255 687 | * @param address Address of the I2C device Value range:0~127 688 | * @return Read the actual current readback value and return an error code if an error occurs 689 | */ 690 | int32_t readCurrentReadback(uint8_t id, uint8_t address); 691 | 692 | /** 693 | * @brief reads the motor encoder from the I2C device 694 | * @param id Motor equipment id Value range:0~255 695 | * @param address Address of the I2C device Value range:0~127 696 | * @return Read the encoder value and return an error code if an error occurs 697 | */ 698 | int32_t readEncoder(uint8_t id, uint8_t address); 699 | 700 | /** 701 | * @brief reads the motor vin from the I2C device 702 | * @param id Motor equipment id Value range:0~255 703 | * @param address Address of the I2C device Value range:0~127 704 | * @return Read the vin value and return an error code if an error occurs 705 | */ 706 | int32_t readVin(uint8_t id, uint8_t address); 707 | 708 | /** 709 | * @brief reads the motor temp from the I2C device 710 | * @param id Motor equipment id Value range:0~255 711 | * @param address Address of the I2C device Value range:0~127 712 | * @return Read the temp value and return an error code if an error occurs 713 | */ 714 | int32_t readTemp(uint8_t id, uint8_t address); 715 | 716 | /** 717 | * @brief wirte i2c 718 | * @param id Motor equipment id Value range:0~255 719 | * @param address Device address 720 | * @param data Write data 721 | * @param dataLen Write data len 722 | * @param stopBit Stop bit Usually false 723 | */ 724 | int8_t writeI2c(uint8_t id, uint8_t address, uint8_t *data, uint8_t dataLen, bool stopBit); 725 | 726 | /** 727 | * @brief wirte i2c 728 | * @param id Motor equipment id Value range:0~255 729 | * @param address Device address 730 | * @param addressLen Device address i2c reg address len: 0, 1 byte address; 1, 2 bytes address 731 | * i2c reg address: 732 | * 1. i2c reg address len = 0, i2c reg address = i2c reg address bytes0 733 | * 2. i2c reg address len = 1, i2creg address = i2c reg address bytes0 + (i2c reg address bytes1 * 255) 734 | * @param regByte0 Register byte 735 | * @param regByte1 Register byte 736 | * @param data Write data 737 | * @param dataLen Write data len 738 | */ 739 | int8_t writeI2c(uint8_t id, uint8_t address, uint8_t addressLen, uint8_t regByte0, uint8_t regByte1, uint8_t *data, 740 | uint8_t dataLen); 741 | 742 | /** 743 | * @brief write MotorConfig 744 | * @param id Motor equipment id Value range:0~255 745 | * @param address Device address 746 | * @param motorEn motor enable or off 747 | * @param mode Mode setting 1: Speed Mode 2: Position Mode 3: Current 748 | * Mode 4. Encoder Mode 749 | * @param rangeProtection Motor Position Over Range Protection: 0,Disable; 1, Enable 750 | * @param removeProtection Release Jam protection: Send 1 to unprotect 751 | * @param buttonEn 0: Off; 1: Press and hold for 5S to switch modes in running 752 | * mode. 753 | * @param stallProtection Motor Stall Protection:: 0,Disable; 1, Enable 754 | * @return The result or error code of the response validation 755 | */ 756 | int8_t writeMotorConfig(uint8_t id, uint8_t address, bool motorEn, roller_mode_t mode, bool rangeProtection, 757 | bool removeProtection, bool buttonEn, bool stallProtection); 758 | 759 | /** 760 | * @brief write_disposition 761 | * @param id Motor equipment id Value range:0~255 762 | * @param address Device address Value range:0~127 763 | * @param motorId Value range:0~255 764 | * @param baudRate BPS: 0,115200bps; 1, 19200bps; 2, 9600bps;Default value:0 765 | * @param rgbBrightness Value range:0~100 766 | * @return The result or error code of the response validation 767 | */ 768 | int8_t writeDisposition(uint8_t id, uint8_t address, uint8_t motorId, roller_bps_t baudRate, uint8_t rgbBrightness); 769 | 770 | /** 771 | * @brief write_speedMode 772 | * @param id Motor equipment id Value range:0~255 773 | * @param address Device address Value range:0~127 774 | * @param speed Speed Value:-21000000 ~21000000 775 | * @return The result or error code of the response validation 776 | */ 777 | int8_t writeSpeedMode(uint8_t id, uint8_t address, int32_t speed); 778 | 779 | /** 780 | * @brief write speedMode current 781 | * @param id Motor equipment id Value range:0~255 782 | * @param address Device address Value range:0~127 783 | * @param current current Value:-1200 ~1200 784 | * @return The result or error code of the response validation 785 | */ 786 | int8_t writeSpeedModeCurrent(uint8_t id, uint8_t address, int32_t current); 787 | 788 | /** 789 | * @brief write speedMode PID 790 | * @param id Motor equipment id Value range:0~255 791 | * @param address Device address Value range:0~127 792 | * @param speedP For example: mottor P=0.004, speedP setting 793 | * value=0.004*100000=400, 794 | * @param speedI For example: mottor I=0.002, speedI setting 795 | * value=0.002*10000000=20000, 796 | * @param speedD For example: mottor D=16.00, speedD setting 797 | * value=16.00*100000=1600000, 798 | * @return The result or error code of the response validation 799 | */ 800 | int8_t writeSpeedModePID(uint8_t id, uint8_t address, uint32_t speedP, uint32_t speedI, uint32_t speedD); 801 | 802 | /** 803 | * @brief write positionMode 804 | * @param id Motor equipment id Value range:0~255 805 | * @param address Device address Value range:0~127 806 | * @param position position Value:-21000000 ~21000000 807 | * @return The result or error code of the response validation 808 | */ 809 | int8_t writePositionMode(uint8_t id, uint8_t address, int32_t position); 810 | 811 | /** 812 | * @brief write positionMode current 813 | * @param address Device address Value range:0~127 814 | * @param id Motor equipment id Value range:0~255 815 | * @param current current Value:-1200 ~1200 816 | * @return The result or error code of the response validation 817 | */ 818 | int8_t writePositionModeCurrent(uint8_t id, uint8_t address, int32_t current); 819 | 820 | /** 821 | * @brief write positionMode PID 822 | * @param id Motor equipment id Value range:0~255 823 | * @param address Device address Value range:0~127 824 | * @param positionP For example: mottor P=0.004, position_P setting 825 | * value=0.004*100000=400, 826 | * @param positionI For example: mottor I=0.002, position_I setting 827 | * value=0.002*10000000=20000, 828 | * @param positionD For example: mottor D=16.00, position_D setting 829 | * value=16.00*100000=1600000, 830 | * @return The result or error code of the response validation 831 | */ 832 | int8_t writePositionModePID(uint8_t id, uint8_t address, uint32_t positionP, uint32_t positionI, 833 | uint32_t positionD); 834 | 835 | /** 836 | * @brief write currentMode 837 | * @param id Motor equipment id Value range:0~255 838 | * @param address Device address Value range:0~127 839 | * @param current current Value:-1200 ~1200 840 | * @return The result or error code of the response validation 841 | */ 842 | int8_t writeCurrentMode(uint8_t id, uint8_t address, int32_t current); 843 | 844 | /** 845 | * @brief write setRGB 846 | * @param id Motor equipment id Value range:0~255 847 | * @param address Device address Value range:0~127 848 | * @param rgbR Value range:0~255 849 | * @param rgbG Value range:0~255 850 | * @param rgbB Value range:0~255 851 | * @param rgbModeRGB Mode: 0, Sys-default 1, User-define Default 852 | * value:0 853 | * @return The result or error code of the response validation 854 | */ 855 | int8_t writeSetRGB(uint8_t id, uint8_t address, uint8_t rgbR, uint8_t rgbG, uint8_t rgbB, roller_rgb_t rgbMode); 856 | 857 | /** 858 | * @brief write encoder 859 | * @param id Motor equipment id Value range:0~255 860 | * @param address Device address Value range:0~127 861 | * @param encoder encoder uint32_t 862 | * @return The result or error code of the response validation 863 | */ 864 | int8_t writeEncoderMode(uint8_t id, uint8_t address, int32_t encoder); 865 | 866 | /** 867 | * @brief write i2c id 868 | * @param id Motor equipment id Value range:0~255 869 | * @param address Device address Value range:1~127 870 | * @param saveFlashEn Save to flash: Send 1 save parameters to flash 871 | * @param newAddress new address Value range:1~127 872 | * @return The result or error code of the response validation 873 | */ 874 | int8_t writeI2cId(uint8_t id, uint8_t address, bool saveFlashEn, uint8_t newAddress); 875 | 876 | private: 877 | bool mutexLocked; 878 | int8_t dirPin; 879 | static const size_t BUFFER_SIZE = 128; 880 | char buffer[BUFFER_SIZE]; 881 | uint8_t motorData[15] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 882 | uint8_t Readback[4] = {0x00, 0x00, 0x00, 0x00}; 883 | // 485->i2c 884 | uint8_t readI2cNum1[5] = {0x00, 0x00, 0x00, 0x00, 0x00}; 885 | uint8_t readI2cNum2[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 886 | uint8_t writeI2cNum[25] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 887 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 888 | 889 | /** 890 | * @brief verifies UART response data 891 | * 892 | Verify received UART response data and check that its CRC checksum matches expectations. 893 | * If needed, the first byte of the response and (if validation is enabled) protocol-specific bytes are also checked. 894 | * 895 | * @param responseBuffer Buffer of response data 896 | * @param responseSize Size of response data (in bytes) 897 | * @param expectedResponse the first byte of the expected response 898 | * @param verifyResponse Whether additional response validation is enabled (e.g. I2C write/read operations) 899 | * 900 | * @return returns WRITE_stateif the validation succeeds, otherwise returns the corresponding error code 901 | */ 902 | int8_t verifyResponse(const char *responseBuffer, size_t responseSize, uint8_t expectedResponse, 903 | bool verifyResponse); 904 | 905 | /** 906 | * @brief verifies that data is sent and received concurrently 907 | * 908 | * This function is responsible for sending the given data and waiting for the received response. If validation is 909 | * enabled, the response data is also validated. 910 | * 911 | * @param data Pointer to the data to be sent 912 | * @param length Length of the data 913 | * @param verify Whether response verification is enabled 914 | * 915 | * @return The result or error code of the response validation 916 | * -SERIAL_SEND_FAILURE: data fails to be sent 917 | * -SERIAL_TIMEOUT: A timeout occurs while waiting for a response 918 | * - Other values: The result of verifying the response (if the verification was stateful) 919 | */ 920 | int8_t verifyData(uint8_t *data, size_t length, bool verify); 921 | }; 922 | 923 | #endif 924 | -------------------------------------------------------------------------------- /src/unit_rollercan.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | *SPDX-License-Identifier: MIT 5 | */ 6 | 7 | #include "unit_rollercan.hpp" 8 | 9 | static twai_message_t ping_message = { 10 | .identifier = ROLLERCAN_MASTER, .data_length_code = 8, .data = {0, 0, 0, 0, 0, 0, 0, 0}}; 11 | 12 | void UnitRollerCAN::beginCAN(unsigned long baud, int8_t rxPin, int8_t txPin) 13 | { 14 | static twai_timing_config_t t_config; 15 | txNum = txPin; 16 | rxNum = rxPin; 17 | gpio_num_t tx = static_cast(txPin); 18 | gpio_num_t rx = static_cast(rxPin); 19 | switch (baud) { 20 | case 125000: 21 | t_config = TWAI_TIMING_CONFIG_125KBITS(); 22 | break; 23 | case 500000: 24 | t_config = TWAI_TIMING_CONFIG_500KBITS(); 25 | break; 26 | case 1000000: 27 | t_config = TWAI_TIMING_CONFIG_1MBITS(); 28 | break; 29 | default: 30 | t_config = TWAI_TIMING_CONFIG_1MBITS(); 31 | break; 32 | } 33 | 34 | twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(tx, rx, TWAI_MODE_NORMAL); 35 | // static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS(); 36 | static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); 37 | ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config)); 38 | ESP_ERROR_CHECK(twai_start()); 39 | } 40 | 41 | int8_t UnitRollerCAN::setRemoveProtection(uint8_t id, bool en) 42 | { 43 | acquireMutex(); 44 | memset(canData, 0, sizeof(canData)); 45 | uint8_t cmd_id; 46 | if (en) { 47 | cmd_id = ROLLERCAN_PROTECTION_ON; 48 | } else { 49 | cmd_id = ROLLERCAN_PROTECTION_OFF; 50 | } 51 | if (!sendData(id, cmd_id, 0, canData)) { 52 | releaseMutex(); 53 | return ROLLER_WRITE_FAILED; 54 | } 55 | int8_t result = receiveData(); 56 | releaseMutex(); 57 | return result; 58 | } 59 | 60 | int8_t UnitRollerCAN::setUnprotect(uint8_t id) 61 | { 62 | acquireMutex(); 63 | memset(canData, 0, sizeof(canData)); 64 | if (!sendData(id, ROLLERCAN_UNPROTECT, 0, canData)) { 65 | releaseMutex(); 66 | return ROLLER_WRITE_FAILED; 67 | } 68 | int8_t result = receiveData(); 69 | releaseMutex(); 70 | return result; 71 | } 72 | 73 | int8_t UnitRollerCAN::setSaveFlash(uint8_t id) 74 | { 75 | acquireMutex(); 76 | memset(canData, 0, sizeof(canData)); 77 | if (!sendData(id, ROLLERCAN_FLASH, 0, canData)) { 78 | releaseMutex(); 79 | return ROLLER_WRITE_FAILED; 80 | } 81 | int8_t result = receiveData(); 82 | releaseMutex(); 83 | return result; 84 | } 85 | 86 | int8_t UnitRollerCAN::setBPS(uint8_t id, roller_bps_t bps) 87 | { 88 | acquireMutex(); 89 | memset(canData, 0, sizeof(canData)); 90 | if (!sendData(id, ROLLERCAN_BAUDRATE, bps, canData)) { 91 | releaseMutex(); 92 | return ROLLER_WRITE_FAILED; 93 | } 94 | int8_t result = receiveData(); 95 | ESP_ERROR_CHECK(twai_stop()); 96 | ESP_ERROR_CHECK(twai_driver_uninstall()); 97 | // Map the new baud rate to the timing config 98 | switch (bps) { 99 | case 0: 100 | beginCAN(1000000, rxNum, txNum); 101 | break; 102 | case 1: 103 | beginCAN(500000, rxNum, txNum); 104 | break; 105 | case 2: 106 | beginCAN(125000, rxNum, txNum); 107 | break; 108 | default: 109 | beginCAN(1000000, rxNum, txNum); 110 | break; 111 | } 112 | releaseMutex(); 113 | return result; 114 | } 115 | 116 | int8_t UnitRollerCAN::setOutput(uint8_t id, bool en) 117 | { 118 | acquireMutex(); 119 | memset(canData, 0, sizeof(canData)); 120 | uint8_t cmd_id; 121 | if (en) { 122 | cmd_id = ROLLERCAN_ON; 123 | } else { 124 | cmd_id = ROLLERCAN_OFF; 125 | } 126 | if (!sendData(id, cmd_id, 0, canData)) { 127 | releaseMutex(); 128 | return ROLLER_WRITE_FAILED; 129 | } 130 | receiveData(); 131 | releaseMutex(); 132 | if (en != getOutput(id)) { 133 | return ROLLER_WRITE_FAILED; 134 | } 135 | return ROLLER_WRITE_SUCCESS; 136 | } 137 | 138 | int8_t UnitRollerCAN::getOutput(uint8_t id) 139 | { 140 | return getMotorParameter(id, ROLLERCAN_SWITCH); 141 | } 142 | 143 | int8_t UnitRollerCAN::setMode(uint8_t id, roller_mode_t mode) 144 | { 145 | acquireMutex(); 146 | memset(canData, 0, sizeof(canData)); 147 | canData[0] = (ROLLERCAN_MODE & 0xFF); 148 | canData[1] = (ROLLERCAN_MODE >> 8) & 0xFF; 149 | canData[4] = mode; 150 | if (!sendData(id, ROLLERCAN_WRITE_CMD, 0, canData)) { 151 | releaseMutex(); 152 | return ROLLER_WRITE_FAILED; 153 | } 154 | receiveData(); 155 | releaseMutex(); 156 | if (mode != getMode(id)) { 157 | return ROLLER_WRITE_FAILED; 158 | } 159 | return ROLLER_WRITE_SUCCESS; 160 | } 161 | 162 | int8_t UnitRollerCAN::getMode(uint8_t id) 163 | { 164 | return getMotorParameter(id, ROLLERCAN_MODE); 165 | } 166 | 167 | int8_t UnitRollerCAN::getSysStatus(uint8_t id) 168 | { 169 | acquireMutex(); 170 | memset(canData, 0, sizeof(canData)); 171 | 172 | if (!sendData(id, ROLLERCAN_STATUS_CMD, 0, canData)) { 173 | releaseMutex(); 174 | return ROLLER_WRITE_FAILED; 175 | } 176 | int8_t result = receiveData(); 177 | if (result) { 178 | releaseMutex(); 179 | return recv_status; 180 | } 181 | releaseMutex(); 182 | return result; 183 | } 184 | 185 | int8_t UnitRollerCAN::getError(uint8_t id) 186 | { 187 | acquireMutex(); 188 | memset(canData, 0, sizeof(canData)); 189 | if (!sendData(id, ROLLERCAN_STATUS_CMD, 0, canData)) { 190 | releaseMutex(); 191 | return ROLLER_WRITE_FAILED; 192 | } 193 | int8_t result = receiveData(); 194 | if (result) { 195 | releaseMutex(); 196 | return recv_faultInfo; 197 | } 198 | releaseMutex(); 199 | return result; 200 | } 201 | 202 | int8_t UnitRollerCAN::setMotorID(uint8_t id, uint8_t newId) 203 | { 204 | acquireMutex(); 205 | memset(canData, 0, sizeof(canData)); 206 | if (!sendData(id, ROLLERCAN_CMD_ID, newId, canData)) { 207 | releaseMutex(); 208 | return ROLLER_WRITE_FAILED; 209 | } 210 | receiveData(); 211 | releaseMutex(); 212 | return ROLLER_WRITE_SUCCESS; 213 | } 214 | 215 | int8_t UnitRollerCAN::setRGBMode(uint8_t id, roller_rgb_t mode) 216 | { 217 | int8_t result = setMotorParameter(id, ROLLERCAN_RGB_MODE, mode); 218 | if (!result) { 219 | return result; 220 | } 221 | if (mode != getRGBMode(id)) { 222 | return ROLLER_WRITE_FAILED; 223 | } 224 | return ROLLER_WRITE_SUCCESS; 225 | } 226 | 227 | int8_t UnitRollerCAN::setRGB(uint8_t id, int32_t color) 228 | { 229 | acquireMutex(); 230 | uint8_t rgbValues[3]; 231 | memset(canData, 0, sizeof(canData)); 232 | rgbValues[0] = (color >> 11) & 0x1F; // R (5 bits) 233 | rgbValues[1] = (color >> 5) & 0x3F; // G (6 bits) 234 | rgbValues[2] = color & 0x1F; // B (5 bits) 235 | canData[0] = (ROLLERCAN_RGB_COLOR & 0xFF); 236 | canData[1] = (ROLLERCAN_RGB_COLOR >> 8) & 0xFF; 237 | canData[4] = (rgbValues[2] * 255) / 31; // Expand to 255 238 | canData[5] = (rgbValues[1] * 255) / 63; // Expand to 255 239 | canData[6] = (rgbValues[0] * 255) / 31; // Expand to 255 240 | if (!sendData(id, ROLLERCAN_WRITE_CMD, 0, canData)) { 241 | releaseMutex(); 242 | return ROLLER_WRITE_FAILED; 243 | } 244 | receiveData(); 245 | releaseMutex(); 246 | getRGB(id, rgbValues); 247 | int32_t rgbInt = ((rgbValues[0] << 16) | (rgbValues[1] << 8) | rgbValues[2]); 248 | if (color != rgbInt) { 249 | releaseMutex(); 250 | return ROLLER_WRITE_FAILED; 251 | } 252 | releaseMutex(); 253 | return ROLLER_WRITE_SUCCESS; 254 | } 255 | 256 | int8_t UnitRollerCAN::setRGBBrightness(uint8_t id, uint8_t brightness) 257 | { 258 | int8_t result = setMotorParameter(id, ROLLERCAN_RGB_BRIGHTNESS, brightness); 259 | if (!result) { 260 | return result; 261 | } 262 | if (brightness != getRGBBrightness(id)) { 263 | return ROLLER_WRITE_FAILED; 264 | } 265 | return ROLLER_WRITE_SUCCESS; 266 | } 267 | 268 | int8_t UnitRollerCAN::setSpeed(uint8_t id, int32_t speed) 269 | { 270 | static const int32_t min = -21000000; 271 | static const int32_t max = 21000000; 272 | speed = constrain(speed, min, max); 273 | int8_t result = setMotorParameter(id, ROLLERCAN_SPEED, speed * 100); 274 | if (!result) { 275 | return result; 276 | } 277 | if (speed != getSpeed(id)) { 278 | return ROLLER_WRITE_FAILED; 279 | } 280 | return ROLLER_WRITE_SUCCESS; 281 | } 282 | 283 | int32_t UnitRollerCAN::getSpeed(uint8_t id) 284 | { 285 | return getMotorParameter(id, ROLLERCAN_SPEED) / 100.0f; 286 | } 287 | 288 | int8_t UnitRollerCAN::setSpeedCurrent(uint8_t id, int32_t speedCurrent) 289 | { 290 | static const int32_t min = -1200; 291 | static const int32_t max = 1200; 292 | speedCurrent = constrain(speedCurrent, min, max); 293 | int8_t result = setMotorParameter(id, ROLLERCAN_SPEED_CURRENT, speedCurrent * 100); 294 | if (!result) { 295 | return result; 296 | } 297 | if (speedCurrent != getSpeedCurrent(id)) { 298 | return ROLLER_WRITE_FAILED; 299 | } 300 | return ROLLER_WRITE_SUCCESS; 301 | } 302 | 303 | int32_t UnitRollerCAN::getSpeedCurrent(uint8_t id) 304 | { 305 | return getMotorParameter(id, ROLLERCAN_SPEED_CURRENT) / 100.0f; 306 | } 307 | 308 | int8_t UnitRollerCAN::setSpeedKp(uint8_t id, uint32_t speedKp) 309 | { 310 | int8_t result = setMotorPID(id, ROLLERCAN_SPEED_KP, speedKp); 311 | if (!result) { 312 | return result; 313 | } 314 | if (speedKp != getSpeedKp(id)) { 315 | return ROLLER_WRITE_FAILED; 316 | } 317 | return ROLLER_WRITE_SUCCESS; 318 | } 319 | 320 | uint32_t UnitRollerCAN::getSpeedKp(uint8_t id) 321 | { 322 | return getMotorParameter(id, ROLLERCAN_SPEED_KP); 323 | } 324 | 325 | int8_t UnitRollerCAN::setSpeedKi(uint8_t id, uint32_t speedKi) 326 | { 327 | int8_t result = setMotorPID(id, ROLLERCAN_SPEED_KI, speedKi); 328 | if (!result) { 329 | return result; 330 | } 331 | if (speedKi != getSpeedKi(id)) { 332 | return ROLLER_WRITE_FAILED; 333 | } 334 | return ROLLER_WRITE_SUCCESS; 335 | } 336 | 337 | uint32_t UnitRollerCAN::getSpeedKi(uint8_t id) 338 | { 339 | return getMotorParameter(id, ROLLERCAN_SPEED_KI); 340 | } 341 | 342 | int8_t UnitRollerCAN::setSpeedKd(uint8_t id, uint32_t speedKd) 343 | { 344 | int8_t result = setMotorPID(id, ROLLERCAN_SPEED_KD, speedKd); 345 | if (!result) { 346 | return result; 347 | } 348 | if (speedKd != getSpeedKd(id)) { 349 | return ROLLER_WRITE_FAILED; 350 | } 351 | return ROLLER_WRITE_SUCCESS; 352 | } 353 | 354 | uint32_t UnitRollerCAN::getSpeedKd(uint8_t id) 355 | { 356 | return getMotorParameter(id, ROLLERCAN_SPEED_KD); 357 | } 358 | 359 | int8_t UnitRollerCAN::setPosition(uint8_t id, int32_t position) 360 | { 361 | static const int32_t min = -21000000; 362 | static const int32_t max = 21000000; 363 | position = constrain(position, min, max); 364 | int8_t result = setMotorParameter(id, ROLLERCAN_POSITION, position * 100); 365 | if (!result) { 366 | return result; 367 | } 368 | if (position != getPosition(id)) { 369 | return ROLLER_WRITE_FAILED; 370 | } 371 | return ROLLER_WRITE_SUCCESS; 372 | } 373 | 374 | int32_t UnitRollerCAN::getPosition(uint8_t id) 375 | { 376 | return getMotorParameter(id, ROLLERCAN_POSITION) / 100.0f; 377 | } 378 | 379 | int8_t UnitRollerCAN::setPositionCurrent(uint8_t id, int32_t positionCurrent) 380 | { 381 | static const int32_t min = -1200; 382 | static const int32_t max = 1200; 383 | positionCurrent = constrain(positionCurrent, min, max); 384 | int8_t result = setMotorParameter(id, ROLLERCAN_POSITION_CURRENT, positionCurrent * 100); 385 | if (!result) { 386 | return result; 387 | } 388 | if (positionCurrent != getPositionCurrent(id)) { 389 | return ROLLER_WRITE_FAILED; 390 | } 391 | return ROLLER_WRITE_SUCCESS; 392 | } 393 | 394 | int32_t UnitRollerCAN::getPositionCurrent(uint8_t id) 395 | { 396 | return getMotorParameter(id, ROLLERCAN_POSITION_CURRENT) / 100.0f; 397 | } 398 | 399 | int8_t UnitRollerCAN::setPositionKp(uint8_t id, uint32_t opsitionKp) 400 | { 401 | int8_t result = setMotorPID(id, ROLLERCAN_POSITION_KP, opsitionKp); 402 | if (!result) { 403 | return result; 404 | } 405 | if (opsitionKp != getPositionKp(id)) { 406 | return ROLLER_WRITE_FAILED; 407 | } 408 | return ROLLER_WRITE_SUCCESS; 409 | } 410 | 411 | uint32_t UnitRollerCAN::getPositionKp(uint8_t id) 412 | { 413 | return getMotorParameter(id, ROLLERCAN_POSITION_KP); 414 | } 415 | 416 | int8_t UnitRollerCAN::setPositionKi(uint8_t id, uint32_t positionKi) 417 | { 418 | int8_t result = setMotorPID(id, ROLLERCAN_POSITION_KI, positionKi); 419 | if (!result) { 420 | return result; 421 | } 422 | if (positionKi != getPositionKi(id)) { 423 | return ROLLER_WRITE_FAILED; 424 | } 425 | return ROLLER_WRITE_SUCCESS; 426 | } 427 | 428 | uint32_t UnitRollerCAN::getPositionKi(uint8_t id) 429 | { 430 | return getMotorParameter(id, ROLLERCAN_POSITION_KI); 431 | } 432 | 433 | int8_t UnitRollerCAN::setPositionKd(uint8_t id, uint32_t positionKd) 434 | { 435 | int8_t result = setMotorPID(id, ROLLERCAN_POSITION_KD, positionKd); 436 | if (!result) { 437 | return result; 438 | } 439 | if (positionKd != getPositionKd(id)) { 440 | return ROLLER_WRITE_FAILED; 441 | } 442 | return ROLLER_WRITE_SUCCESS; 443 | } 444 | 445 | uint32_t UnitRollerCAN::getPositionKd(uint8_t id) 446 | { 447 | return getMotorParameter(id, ROLLERCAN_POSITION_KD); 448 | } 449 | 450 | int8_t UnitRollerCAN::setCurrent(uint8_t id, int32_t current) 451 | { 452 | static const int32_t min = -1200; 453 | static const int32_t max = 1200; 454 | current = constrain(current, min, max); 455 | int8_t result = setMotorParameter(id, ROLLERCAN_CURRENT, current * 100); 456 | if (!result) { 457 | return result; 458 | } 459 | if (current != getCurrent(id)) { 460 | return ROLLER_WRITE_FAILED; 461 | } 462 | return ROLLER_WRITE_SUCCESS; 463 | } 464 | 465 | int32_t UnitRollerCAN::getCurrent(uint8_t id) 466 | { 467 | return getMotorParameter(id, ROLLERCAN_CURRENT) / 100.0f; 468 | } 469 | 470 | int8_t UnitRollerCAN::setEncoder(uint8_t id, int32_t encoder) 471 | { 472 | static const int32_t min = -21000000; 473 | static const int32_t max = 21000000; 474 | encoder = constrain(encoder, min, max); 475 | int8_t result = setMotorParameter(id, ROLLERCAN_ENCODER, encoder); 476 | if (!result) { 477 | return result; 478 | } 479 | if (encoder != getEncoder(id)) { 480 | return ROLLER_WRITE_FAILED; 481 | } 482 | return ROLLER_WRITE_SUCCESS; 483 | } 484 | 485 | int32_t UnitRollerCAN::getEncoder(uint8_t id) 486 | { 487 | return getMotorParameter(id, ROLLERCAN_ENCODER); 488 | } 489 | 490 | int32_t UnitRollerCAN::getActualSpeed(uint8_t id) 491 | { 492 | return getMotorParameter(id, ROLLERCAN_ACTUAL_SPEED) / 100.0f; 493 | } 494 | 495 | int32_t UnitRollerCAN::getActualPosition(uint8_t id) 496 | { 497 | return getMotorParameter(id, ROLLERCAN_ACTUAL_POSITION) / 100.0f; 498 | } 499 | 500 | int32_t UnitRollerCAN::getActualCurrent(uint8_t id) 501 | { 502 | return getMotorParameter(id, ROLLERCAN_ACTUAL_CURRENT) / 100.0f; 503 | } 504 | 505 | int32_t UnitRollerCAN::getActualVin(uint8_t id) 506 | { 507 | return getMotorParameter(id, ROLLERCAN_VIN) / 100.0f; 508 | } 509 | 510 | int32_t UnitRollerCAN::getActualTemp(uint8_t id) 511 | { 512 | return getMotorParameter(id, ROLLERCAN_TEMP); 513 | } 514 | 515 | int8_t UnitRollerCAN::getRGBMode(uint8_t id) 516 | { 517 | return getMotorParameter(id, ROLLERCAN_RGB_MODE); 518 | } 519 | 520 | int8_t UnitRollerCAN::getRGB(uint8_t id, uint8_t *rgbValues) 521 | { 522 | int32_t returnValue = getMotorParameter(id, ROLLERCAN_RGB_COLOR); 523 | rgbValues[0] = readData[6]; // R value 524 | rgbValues[1] = readData[5]; // G value 525 | rgbValues[2] = readData[4]; // B value 526 | return returnValue; 527 | } 528 | 529 | int8_t UnitRollerCAN::getRGBBrightness(uint8_t id) 530 | { 531 | return getMotorParameter(id, ROLLERCAN_RGB_BRIGHTNESS); 532 | } 533 | 534 | int8_t UnitRollerCAN::writeRemoveProtection(uint8_t id, uint8_t addr, bool en) 535 | { 536 | return writeMotorParameter(id, addr, ROLLERCAN_PROTECTION, en); 537 | } 538 | 539 | int8_t UnitRollerCAN::writeSaveFlash(uint8_t id, uint8_t addr, bool en) 540 | { 541 | return writeMotorParameter(id, addr, ROLLERCAN_SAVE_FLASH, en); 542 | } 543 | 544 | int8_t UnitRollerCAN::writeOutput(uint8_t id, uint8_t addr, bool en) 545 | { 546 | int8_t result = writeMotorParameter(id, addr, ROLLERCAN_SWITCH, en); 547 | if (!result) { 548 | return result; 549 | } 550 | if (en != readOutput(id, addr)) { 551 | return ROLLER_WRITE_FAILED; 552 | } 553 | return ROLLER_WRITE_SUCCESS; 554 | } 555 | 556 | int8_t UnitRollerCAN::readOutput(uint8_t id, uint8_t addr) 557 | { 558 | return readMotorParameter(id, addr, ROLLERCAN_SWITCH); 559 | } 560 | 561 | int8_t UnitRollerCAN::writeMode(uint8_t id, uint8_t addr, roller_mode_t mode) 562 | { 563 | int8_t result = writeMotorParameter(id, addr, ROLLERCAN_MODE, mode); 564 | if (!result) { 565 | return result; 566 | } 567 | if (mode != readMode(id, addr)) { 568 | return ROLLER_WRITE_FAILED; 569 | } 570 | return ROLLER_WRITE_SUCCESS; 571 | } 572 | 573 | int8_t UnitRollerCAN::readMode(uint8_t id, uint8_t addr) 574 | { 575 | return readMotorParameter(id, addr, ROLLERCAN_MODE); 576 | } 577 | 578 | int8_t UnitRollerCAN::writeSpeed(uint8_t id, uint8_t addr, int32_t speed) 579 | { 580 | int8_t result = writeMotorParameter(id, addr, ROLLERCAN_SPEED, speed * 100); 581 | if (!result) { 582 | return result; 583 | } 584 | if (speed != readSpeed(id, addr)) { 585 | return ROLLER_WRITE_FAILED; 586 | } 587 | return ROLLER_WRITE_SUCCESS; 588 | } 589 | 590 | int32_t UnitRollerCAN::readSpeed(uint8_t id, uint8_t addr) 591 | { 592 | return readMotorParameter(id, addr, ROLLERCAN_SPEED) / 100.0f; 593 | } 594 | 595 | int8_t UnitRollerCAN::writeSpeedCurrent(uint8_t id, uint8_t addr, int32_t speedCurrent) 596 | { 597 | static const int32_t min = -1200; 598 | static const int32_t max = 1200; 599 | speedCurrent = constrain(speedCurrent, min, max); 600 | int8_t result = writeMotorParameter(id, addr, ROLLERCAN_SPEED_CURRENT, speedCurrent * 100); 601 | if (!result) { 602 | return result; 603 | } 604 | if (speedCurrent != readSpeedCurrent(id, addr)) { 605 | return ROLLER_WRITE_FAILED; 606 | } 607 | return ROLLER_WRITE_SUCCESS; 608 | } 609 | 610 | int32_t UnitRollerCAN::readSpeedCurrent(uint8_t id, uint8_t addr) 611 | { 612 | return readMotorParameter(id, addr, ROLLERCAN_SPEED_CURRENT); 613 | } 614 | 615 | int8_t UnitRollerCAN::writeSpeedKp(uint8_t id, uint8_t addr, uint32_t speedKp) 616 | { 617 | int8_t result = writeMotorPID(id, addr, ROLLERCAN_SPEED_KP, speedKp); 618 | if (!result) { 619 | return result; 620 | } 621 | if (speedKp != readSpeedKp(id, addr)) { 622 | return ROLLER_WRITE_FAILED; 623 | } 624 | return ROLLER_WRITE_SUCCESS; 625 | } 626 | 627 | uint32_t UnitRollerCAN::readSpeedKp(uint8_t id, uint8_t addr) 628 | { 629 | return readMotorParameter(id, addr, ROLLERCAN_SPEED_KP); 630 | } 631 | 632 | int8_t UnitRollerCAN::writeSpeedKi(uint8_t id, uint8_t addr, uint32_t speedKi) 633 | { 634 | int8_t result = writeMotorPID(id, addr, ROLLERCAN_SPEED_KI, speedKi); 635 | if (!result) { 636 | return result; 637 | } 638 | if (speedKi != readSpeedKi(id, addr)) { 639 | return ROLLER_WRITE_FAILED; 640 | } 641 | return ROLLER_WRITE_SUCCESS; 642 | } 643 | 644 | uint32_t UnitRollerCAN::readSpeedKi(uint8_t id, uint8_t addr) 645 | { 646 | return readMotorParameter(id, addr, ROLLERCAN_SPEED_KI); 647 | } 648 | 649 | int8_t UnitRollerCAN::writeSpeedKd(uint8_t id, uint8_t addr, uint32_t speedKd) 650 | { 651 | int8_t result = writeMotorPID(id, addr, ROLLERCAN_SPEED_KD, speedKd); 652 | if (!result) { 653 | return result; 654 | } 655 | if (speedKd != readSpeedKd(id, addr)) { 656 | return ROLLER_WRITE_FAILED; 657 | } 658 | return ROLLER_WRITE_SUCCESS; 659 | } 660 | 661 | uint32_t UnitRollerCAN::readSpeedKd(uint8_t id, uint8_t addr) 662 | { 663 | return readMotorParameter(id, addr, ROLLERCAN_SPEED_KD); 664 | } 665 | 666 | int8_t UnitRollerCAN::writePosition(uint8_t id, uint8_t addr, int32_t position) 667 | { 668 | int8_t result = writeMotorParameter(id, addr, ROLLERCAN_POSITION, position * 100); 669 | if (!result) { 670 | return result; 671 | } 672 | if (position != readPosition(id, addr)) { 673 | return ROLLER_WRITE_FAILED; 674 | } 675 | return ROLLER_WRITE_SUCCESS; 676 | } 677 | 678 | int32_t UnitRollerCAN::readPosition(uint8_t id, uint8_t addr) 679 | { 680 | return readMotorParameter(id, addr, ROLLERCAN_POSITION) / 100.0f; 681 | } 682 | 683 | int8_t UnitRollerCAN::writePositionCurrent(uint8_t id, uint8_t addr, int32_t positionCurrent) 684 | { 685 | static const int32_t min = -1200; 686 | static const int32_t max = 1200; 687 | positionCurrent = constrain(positionCurrent, min, max); 688 | int8_t result = writeMotorParameter(id, addr, ROLLERCAN_POSITION_CURRENT, positionCurrent * 100); 689 | if (!result) { 690 | return result; 691 | } 692 | if (positionCurrent != readPositionCurrent(id, addr)) { 693 | return ROLLER_WRITE_FAILED; 694 | } 695 | return ROLLER_WRITE_SUCCESS; 696 | } 697 | 698 | int32_t UnitRollerCAN::readPositionCurrent(uint8_t id, uint8_t addr) 699 | { 700 | return readMotorParameter(id, addr, ROLLERCAN_POSITION_CURRENT) / 100.0f; 701 | } 702 | 703 | int8_t UnitRollerCAN::writePositionKp(uint8_t id, uint8_t addr, uint32_t positionKp) 704 | { 705 | int8_t result = writeMotorPID(id, addr, ROLLERCAN_POSITION_KP, positionKp); 706 | if (!result) { 707 | return result; 708 | } 709 | if (positionKp != readPositionKp(id, addr)) { 710 | return ROLLER_WRITE_FAILED; 711 | } 712 | return ROLLER_WRITE_SUCCESS; 713 | } 714 | 715 | uint32_t UnitRollerCAN::readPositionKp(uint8_t id, uint8_t addr) 716 | { 717 | return readMotorParameter(id, addr, ROLLERCAN_POSITION_KP); 718 | } 719 | 720 | int8_t UnitRollerCAN::writePositionKi(uint8_t id, uint8_t addr, uint32_t positionKi) 721 | { 722 | int8_t result = writeMotorPID(id, addr, ROLLERCAN_POSITION_KI, positionKi); 723 | if (!result) { 724 | return result; 725 | } 726 | if (positionKi != readPositionKi(id, addr)) { 727 | return ROLLER_WRITE_FAILED; 728 | } 729 | return ROLLER_WRITE_SUCCESS; 730 | } 731 | 732 | uint32_t UnitRollerCAN::readPositionKi(uint8_t id, uint8_t addr) 733 | { 734 | return readMotorParameter(id, addr, ROLLERCAN_POSITION_KI); 735 | } 736 | 737 | int8_t UnitRollerCAN::writePositionKd(uint8_t id, uint8_t addr, uint32_t positionKd) 738 | { 739 | int8_t result = writeMotorPID(id, addr, ROLLERCAN_POSITION_KD, positionKd); 740 | if (!result) { 741 | return result; 742 | } 743 | if (positionKd != readPositionKd(id, addr)) { 744 | return ROLLER_WRITE_FAILED; 745 | } 746 | return ROLLER_WRITE_SUCCESS; 747 | } 748 | 749 | uint32_t UnitRollerCAN::readPositionKd(uint8_t id, uint8_t addr) 750 | { 751 | return readMotorParameter(id, addr, ROLLERCAN_POSITION_KD); 752 | } 753 | 754 | int8_t UnitRollerCAN::writeCurrent(uint8_t id, uint8_t addr, int32_t current) 755 | { 756 | static const int32_t min = -1200; 757 | static const int32_t max = 1200; 758 | current = constrain(current, min, max); 759 | int8_t result = writeMotorParameter(id, addr, ROLLERCAN_CURRENT, current * 100); 760 | if (!result) { 761 | return result; 762 | } 763 | if (current != readCurrent(id, addr)) { 764 | return ROLLER_WRITE_FAILED; 765 | } 766 | return ROLLER_WRITE_SUCCESS; 767 | } 768 | 769 | int32_t UnitRollerCAN::readCurrent(uint8_t id, uint8_t addr) 770 | { 771 | return readMotorParameter(id, addr, ROLLERCAN_CURRENT) / 100.0f; 772 | } 773 | 774 | int8_t UnitRollerCAN::writeEncoder(uint8_t id, uint8_t addr, int32_t encoder) 775 | { 776 | int8_t result = writeMotorParameter(id, addr, ROLLERCAN_ENCODER, encoder); 777 | if (!result) { 778 | return result; 779 | } 780 | if (encoder != readEncoder(id, addr)) { 781 | return ROLLER_WRITE_FAILED; 782 | } 783 | return ROLLER_WRITE_SUCCESS; 784 | } 785 | 786 | int32_t UnitRollerCAN::readEncoder(uint8_t id, uint8_t addr) 787 | { 788 | return readMotorParameter(id, addr, ROLLERCAN_ENCODER); 789 | } 790 | 791 | int32_t UnitRollerCAN::readActualSpeed(uint8_t id, uint8_t addr) 792 | { 793 | return readMotorParameter(id, addr, ROLLERCAN_ACTUAL_SPEED) / 100; 794 | } 795 | 796 | int32_t UnitRollerCAN::readActualPosition(uint8_t id, uint8_t addr) 797 | { 798 | return readMotorParameter(id, addr, ROLLERCAN_ACTUAL_POSITION) / 100; 799 | } 800 | 801 | int32_t UnitRollerCAN::readActualCurrent(uint8_t id, uint8_t addr) 802 | { 803 | return readMotorParameter(id, addr, ROLLERCAN_ACTUAL_CURRENT) / 100; 804 | } 805 | 806 | int32_t UnitRollerCAN::readActualVin(uint8_t id, uint8_t addr) 807 | { 808 | return readMotorParameter(id, addr, ROLLERCAN_VIN) / 100; 809 | } 810 | 811 | int32_t UnitRollerCAN::readActualTemp(uint8_t id, uint8_t addr) 812 | { 813 | return readMotorParameter(id, addr, ROLLERCAN_TEMP); 814 | } 815 | 816 | int8_t UnitRollerCAN::readRGBMode(uint8_t id, uint8_t addr) 817 | { 818 | return readMotorParameter(id, addr, ROLLERCAN_RGB_MODE); 819 | } 820 | 821 | int8_t UnitRollerCAN::writeRGBMode(uint8_t id, uint8_t addr, roller_rgb_t mode) 822 | { 823 | int8_t result = writeMotorParameter(id, addr, ROLLERCAN_RGB_MODE, mode); 824 | if (!result) { 825 | return result; 826 | } 827 | if (mode != readRGBMode(id, addr)) { 828 | return ROLLER_WRITE_FAILED; 829 | } 830 | return ROLLER_WRITE_SUCCESS; 831 | } 832 | 833 | int8_t UnitRollerCAN::readRGB(uint8_t id, uint8_t addr, uint8_t *rgbValues) 834 | { 835 | int32_t returnValue = readMotorParameter(id, addr, ROLLERCAN_RGB_COLOR); 836 | rgbValues[0] = readData[6]; // R value 837 | rgbValues[1] = readData[5]; // G value 838 | rgbValues[2] = readData[4]; // B value 839 | return returnValue; 840 | } 841 | 842 | int8_t UnitRollerCAN::writeRGB(uint8_t id, uint8_t addr, int32_t color) 843 | { 844 | acquireMutex(); 845 | uint8_t rgbValues[3]; 846 | memset(canData, 0, sizeof(canData)); 847 | canData[0] = (ROLLERCAN_RGB_COLOR & 0xFF); 848 | canData[1] = (ROLLERCAN_RGB_COLOR >> 8) & 0xFF; 849 | canData[2] = addr; 850 | rgbValues[0] = (color >> 11) & 0x1F; // R (5 bits) 851 | rgbValues[1] = (color >> 5) & 0x3F; // G (6 bits) 852 | rgbValues[2] = color & 0x1F; // B (5 bits) 853 | canData[4] = (rgbValues[2] * 255) / 31; // Expand to 255 854 | canData[5] = (rgbValues[1] * 255) / 63; // Expand to 255 855 | canData[6] = (rgbValues[0] * 255) / 31; 856 | if (!sendData(id, ROLLERCAN_WRITE_I2C_CMD, 0, canData)) { 857 | releaseMutex(); 858 | return ROLLER_SERIAL_SEND_FAILURE; 859 | } 860 | receiveData(); 861 | releaseMutex(); 862 | readRGB(id, addr, rgbValues); 863 | int32_t rgbInt = ((rgbValues[0] << 16) | (rgbValues[1] << 8) | rgbValues[2]); 864 | if (color != rgbInt) { 865 | releaseMutex(); 866 | return ROLLER_WRITE_FAILED; 867 | } 868 | releaseMutex(); 869 | return ROLLER_WRITE_SUCCESS; 870 | } 871 | 872 | int8_t UnitRollerCAN::readRGBBrightness(uint8_t id, uint8_t addr) 873 | { 874 | return readMotorParameter(id, addr, ROLLERCAN_RGB_BRIGHTNESS); 875 | } 876 | 877 | int8_t UnitRollerCAN::writeRGBBrightness(uint8_t id, uint8_t addr, uint8_t brightness) 878 | { 879 | int8_t result = writeMotorParameter(id, addr, ROLLERCAN_RGB_BRIGHTNESS, brightness); 880 | if (!result) { 881 | return result; 882 | } 883 | if (brightness != readRGBBrightness(id, addr)) { 884 | return ROLLER_WRITE_FAILED; 885 | } 886 | return ROLLER_WRITE_SUCCESS; 887 | } 888 | 889 | int8_t UnitRollerCAN::readRawOutput(uint8_t id, uint8_t addr) 890 | { 891 | return readMotorRawParameter(id, addr, I2C_OUTPUT_REG); 892 | } 893 | 894 | int8_t UnitRollerCAN::writeRawOutput(uint8_t id, uint8_t addr, bool en) 895 | { 896 | int8_t result = writeMotorRawParameter(id, addr, I2C_OUTPUT_REG, 1, 1, en); 897 | if (result < 0) { 898 | return result; 899 | } 900 | if (en != readRawOutput(id, addr)) { 901 | return ROLLER_WRITE_FAILED; 902 | } 903 | return ROLLER_WRITE_SUCCESS; 904 | } 905 | 906 | int8_t UnitRollerCAN::readRawMode(uint8_t id, uint8_t addr) 907 | { 908 | return readMotorRawParameter(id, addr, I2C_MODE_REG); 909 | } 910 | 911 | int8_t UnitRollerCAN::writeRawMode(uint8_t id, uint8_t addr, roller_mode_t mode) 912 | { 913 | int8_t result = writeMotorRawParameter(id, addr, I2C_MODE_REG, 1, 1, mode); 914 | if (result < 0) { 915 | return result; 916 | } 917 | if (mode != readRawMode(id, addr)) { 918 | return ROLLER_WRITE_FAILED; 919 | } 920 | return ROLLER_WRITE_SUCCESS; 921 | } 922 | 923 | int32_t UnitRollerCAN::readRawSpeed(uint8_t id, uint8_t addr) 924 | { 925 | return readMotorRawParameter(id, addr, I2C_SPEED_REG) / 100.0f; 926 | } 927 | 928 | int8_t UnitRollerCAN::writeRawSpeed(uint8_t id, uint8_t addr, int32_t speed) 929 | { 930 | int8_t result = writeMotorRawParameter(id, addr, I2C_SPEED_REG, 1, 4, speed * 100); 931 | if (result < 0) { 932 | return result; 933 | } 934 | if (speed != readRawSpeed(id, addr)) { 935 | return ROLLER_WRITE_FAILED; 936 | } 937 | return ROLLER_WRITE_SUCCESS; 938 | } 939 | 940 | int32_t UnitRollerCAN::readRawSpeedCurrent(uint8_t id, uint8_t addr) 941 | { 942 | return readMotorRawParameter(id, addr, I2C_SPEED_MAX_CURRENT_REG) / 100.0f; 943 | } 944 | 945 | int8_t UnitRollerCAN::writeRawSpeedCurrent(uint8_t id, uint8_t addr, int32_t speedCurrent) 946 | { 947 | int8_t result = writeMotorRawParameter(id, addr, I2C_SPEED_MAX_CURRENT_REG, 1, 4, speedCurrent * 100); 948 | if (result < 0) { 949 | return result; 950 | } 951 | if (speedCurrent != readRawSpeedCurrent(id, addr)) { 952 | return ROLLER_WRITE_FAILED; 953 | } 954 | return ROLLER_WRITE_SUCCESS; 955 | } 956 | 957 | uint32_t UnitRollerCAN::readRawSpeedKp(uint8_t id, uint8_t addr) 958 | { 959 | return readMotorRawParameter(id, addr, I2C_SPEED_PID_REG); 960 | } 961 | 962 | int8_t UnitRollerCAN::writeRawSpeedKp(uint8_t id, uint8_t addr, uint32_t speedKp) 963 | { 964 | int8_t result = writeMotorRawParameter(id, addr, I2C_SPEED_PID_REG, 1, 4, speedKp); 965 | if (result < 0) { 966 | return result; 967 | } 968 | if (speedKp != readRawSpeedKp(id, addr)) { 969 | return ROLLER_WRITE_FAILED; 970 | } 971 | return ROLLER_WRITE_SUCCESS; 972 | } 973 | 974 | uint32_t UnitRollerCAN::readRawSpeedKi(uint8_t id, uint8_t addr) 975 | { 976 | return readMotorRawParameter(id, addr, I2C_SPEED_PID_REG + 4); 977 | } 978 | 979 | int8_t UnitRollerCAN::writeRawSpeedKi(uint8_t id, uint8_t addr, uint32_t speedKi) 980 | { 981 | int8_t result = writeMotorRawParameter(id, addr, I2C_SPEED_PID_REG + 4, 1, 4, speedKi); 982 | if (result < 0) { 983 | return result; 984 | } 985 | if (speedKi != readRawSpeedKi(id, addr)) { 986 | return ROLLER_WRITE_FAILED; 987 | } 988 | return ROLLER_WRITE_SUCCESS; 989 | } 990 | 991 | uint32_t UnitRollerCAN::readRawSpeedKd(uint8_t id, uint8_t addr) 992 | { 993 | return readMotorRawParameter(id, addr, I2C_SPEED_PID_REG + 8); 994 | } 995 | 996 | int8_t UnitRollerCAN::writeRawSpeedKd(uint8_t id, uint8_t addr, uint32_t speedKd) 997 | { 998 | int8_t result = writeMotorRawParameter(id, addr, I2C_SPEED_PID_REG + 8, 1, 4, speedKd); 999 | if (result < 0) { 1000 | return result; 1001 | } 1002 | if (speedKd != readRawSpeedKd(id, addr)) { 1003 | return ROLLER_WRITE_FAILED; 1004 | } 1005 | return ROLLER_WRITE_SUCCESS; 1006 | } 1007 | 1008 | int32_t UnitRollerCAN::readRawPosition(uint8_t id, uint8_t addr) 1009 | { 1010 | return readMotorRawParameter(id, addr, I2C_POS_REG) / 100.0f; 1011 | } 1012 | 1013 | int8_t UnitRollerCAN::writeRawPosition(uint8_t id, uint8_t addr, int32_t position) 1014 | { 1015 | int8_t result = writeMotorRawParameter(id, addr, I2C_POS_REG, 1, 4, position * 100); 1016 | if (result < 0) { 1017 | return result; 1018 | } 1019 | if (position != readRawPosition(id, addr)) { 1020 | return ROLLER_WRITE_FAILED; 1021 | } 1022 | return ROLLER_WRITE_SUCCESS; 1023 | } 1024 | 1025 | int32_t UnitRollerCAN::readRawPositionCurrent(uint8_t id, uint8_t addr) 1026 | { 1027 | return readMotorRawParameter(id, addr, I2C_POS_MAX_CURRENT_REG) / 100.0f; 1028 | } 1029 | 1030 | int8_t UnitRollerCAN::writeRawPositionCurrent(uint8_t id, uint8_t addr, int32_t positionCurrent) 1031 | { 1032 | int8_t result = writeMotorRawParameter(id, addr, I2C_POS_MAX_CURRENT_REG, 1, 4, positionCurrent * 100); 1033 | if (result < 0) { 1034 | return result; 1035 | } 1036 | if (positionCurrent != readRawPositionCurrent(id, addr)) { 1037 | return ROLLER_WRITE_FAILED; 1038 | } 1039 | return ROLLER_WRITE_SUCCESS; 1040 | } 1041 | 1042 | uint32_t UnitRollerCAN::readRawPositionKp(uint8_t id, uint8_t addr) 1043 | { 1044 | return readMotorRawParameter(id, addr, I2C_POS_PID_REG); 1045 | } 1046 | 1047 | int8_t UnitRollerCAN::writeRawPositionKp(uint8_t id, uint8_t addr, uint32_t positionKp) 1048 | { 1049 | int8_t result = writeMotorRawParameter(id, addr, I2C_POS_PID_REG, 1, 4, positionKp); 1050 | if (result < 0) { 1051 | return result; 1052 | } 1053 | if (positionKp != readRawPositionKp(id, addr)) { 1054 | return ROLLER_WRITE_FAILED; 1055 | } 1056 | return ROLLER_WRITE_SUCCESS; 1057 | } 1058 | 1059 | uint32_t UnitRollerCAN::readRawPositionKi(uint8_t id, uint8_t addr) 1060 | { 1061 | return readMotorRawParameter(id, addr, I2C_POS_PID_REG + 4); 1062 | } 1063 | 1064 | int8_t UnitRollerCAN::writeRawPositionKi(uint8_t id, uint8_t addr, uint32_t positionKi) 1065 | { 1066 | int8_t result = writeMotorRawParameter(id, addr, I2C_POS_PID_REG + 4, 1, 4, positionKi); 1067 | if (result < 0) { 1068 | return result; 1069 | } 1070 | if (positionKi != readRawPositionKi(id, addr)) { 1071 | return ROLLER_WRITE_FAILED; 1072 | } 1073 | return ROLLER_WRITE_SUCCESS; 1074 | } 1075 | 1076 | uint32_t UnitRollerCAN::readRawPositionKd(uint8_t id, uint8_t addr) 1077 | { 1078 | return readMotorRawParameter(id, addr, I2C_POS_PID_REG + 8); 1079 | } 1080 | 1081 | int8_t UnitRollerCAN::writeRawPositionKd(uint8_t id, uint8_t addr, uint32_t positionKd) 1082 | { 1083 | int8_t result = writeMotorRawParameter(id, addr, I2C_POS_PID_REG + 8, 1, 4, positionKd); 1084 | if (result < 0) { 1085 | return result; 1086 | } 1087 | if (positionKd != readRawPositionKd(id, addr)) { 1088 | return ROLLER_WRITE_FAILED; 1089 | } 1090 | return ROLLER_WRITE_SUCCESS; 1091 | } 1092 | 1093 | int32_t UnitRollerCAN::readRawCurrent(uint8_t id, uint8_t addr) 1094 | { 1095 | return readMotorRawParameter(id, addr, I2C_CURRENT_REG) / 100.0f; 1096 | } 1097 | 1098 | int8_t UnitRollerCAN::writeRawCurrent(uint8_t id, uint8_t addr, int32_t current) 1099 | { 1100 | int8_t result = writeMotorRawParameter(id, addr, I2C_CURRENT_REG, 1, 4, current * 100); 1101 | if (result < 0) { 1102 | return result; 1103 | } 1104 | if (current != readRawCurrent(id, addr)) { 1105 | return ROLLER_WRITE_FAILED; 1106 | } 1107 | return ROLLER_WRITE_SUCCESS; 1108 | } 1109 | 1110 | int32_t UnitRollerCAN::readRawEncoder(uint8_t id, uint8_t addr) 1111 | { 1112 | return readMotorRawParameter(id, addr, I2C_DIAL_COUNTER_REG); 1113 | } 1114 | 1115 | int8_t UnitRollerCAN::writeRawEncoder(uint8_t id, uint8_t addr, int32_t encoder) 1116 | { 1117 | int8_t result = writeMotorRawParameter(id, addr, I2C_DIAL_COUNTER_REG, 1, 4, encoder); 1118 | if (result < 0) { 1119 | return result; 1120 | } 1121 | if (encoder != readRawEncoder(id, addr)) { 1122 | return ROLLER_WRITE_FAILED; 1123 | } 1124 | return ROLLER_WRITE_SUCCESS; 1125 | } 1126 | 1127 | int8_t UnitRollerCAN::writeRawFlash(uint8_t id, uint8_t addr, bool en) 1128 | { 1129 | int8_t result = writeMotorRawParameter(id, addr, I2C_SAVE_FLASH_REG, 1, 1, en); 1130 | if (!result) { 1131 | return result; 1132 | } 1133 | return ROLLER_WRITE_SUCCESS; 1134 | } 1135 | 1136 | int32_t UnitRollerCAN::readRawActualSpeed(uint8_t id, uint8_t addr) 1137 | { 1138 | return readMotorRawParameter(id, addr, I2C_SPEED_READBACK_REG) / 100.0f; 1139 | } 1140 | 1141 | int32_t UnitRollerCAN::readRawActualPosition(uint8_t id, uint8_t addr) 1142 | { 1143 | return readMotorRawParameter(id, addr, I2C_POS_READBACK_REG) / 100.0f; 1144 | } 1145 | 1146 | int32_t UnitRollerCAN::readRawActualCurrent(uint8_t id, uint8_t addr) 1147 | { 1148 | return readMotorRawParameter(id, addr, I2C_CURRENT_READBACK_REG) / 100.0f; 1149 | } 1150 | 1151 | int32_t UnitRollerCAN::readRawActualVin(uint8_t id, uint8_t addr) 1152 | { 1153 | return readMotorRawParameter(id, addr, I2C_VIN_REG) / 100.0f; 1154 | } 1155 | 1156 | int32_t UnitRollerCAN::readRawActualTemp(uint8_t id, uint8_t addr) 1157 | { 1158 | return readMotorRawParameter(id, addr, I2C_TEMP_REG); 1159 | } 1160 | 1161 | int8_t UnitRollerCAN::readRawRGBMode(uint8_t id, uint8_t addr) 1162 | { 1163 | int32_t returnValue = readMotorRawParameter(id, addr, I2C_RGB_REG); 1164 | if (returnValue < 0) { 1165 | return returnValue; 1166 | } 1167 | return readData[3]; 1168 | } 1169 | 1170 | int8_t UnitRollerCAN::writeRawRGBMode(uint8_t id, uint8_t addr, roller_rgb_t mode) 1171 | { 1172 | int8_t result = writeMotorRawParameter(id, addr, I2C_RGB_REG + 3, 1, 1, mode); 1173 | if (result < 0) { 1174 | return result; 1175 | } 1176 | if (mode != readRawRGBMode(id, addr)) { 1177 | return ROLLER_WRITE_FAILED; 1178 | } 1179 | return ROLLER_WRITE_SUCCESS; 1180 | } 1181 | 1182 | int8_t UnitRollerCAN::readRawRGB(uint8_t id, uint8_t addr, uint8_t *rgbValues) 1183 | { 1184 | int32_t returnValue = readMotorRawParameter(id, addr, I2C_RGB_REG); 1185 | rgbValues[0] = readData[2]; // R value 1186 | rgbValues[1] = readData[1]; // G value 1187 | rgbValues[2] = readData[0]; // B value 1188 | 1189 | return returnValue; 1190 | } 1191 | 1192 | int8_t UnitRollerCAN::writeRawRGB(uint8_t id, uint8_t addr, int32_t color) 1193 | { 1194 | acquireMutex(); 1195 | uint8_t rgbValues[3]; 1196 | memset(canData, 0, sizeof(canData)); 1197 | rgbValues[0] = (color >> 11) & 0x1F; // R (5 bits) 1198 | rgbValues[1] = (color >> 5) & 0x3F; // G (6 bits) 1199 | rgbValues[2] = color & 0x1F; // B (5 bits) 1200 | uint8_t new_value; 1201 | 1202 | canData[0] = 4; 1203 | canData[1] = I2C_RGB_REG; 1204 | canData[2] = (rgbValues[2] * 255) / 31; // Expand to 255 1205 | canData[3] = (rgbValues[1] * 255) / 63; // Expand to 255 1206 | canData[4] = (rgbValues[0] * 255) / 31; 1207 | if (!sendData(id, ROLLERCAN_WRITE_I2C_RAW_CMD, addr | 0x80, canData)) { 1208 | releaseMutex(); 1209 | return ROLLER_SERIAL_SEND_FAILURE; 1210 | } 1211 | receiveData(); 1212 | releaseMutex(); 1213 | readRawRGB(id, addr, rgbValues); 1214 | int32_t rgbInt = ((rgbValues[0] << 16) | (rgbValues[1] << 8) | rgbValues[2]); 1215 | if (color != rgbInt) { 1216 | releaseMutex(); 1217 | return ROLLER_WRITE_FAILED; 1218 | } 1219 | releaseMutex(); 1220 | return ROLLER_WRITE_SUCCESS; 1221 | } 1222 | 1223 | int8_t UnitRollerCAN::readRawRGBBrightness(uint8_t id, uint8_t addr) 1224 | { 1225 | return readMotorRawParameter(id, addr, I2C_RGB_BRIGHTNESS_REG); 1226 | } 1227 | 1228 | int8_t UnitRollerCAN::writeRawRGBBrightness(uint8_t id, uint8_t addr, uint8_t brightness) 1229 | { 1230 | int8_t result = writeMotorRawParameter(id, addr, I2C_RGB_BRIGHTNESS_REG, 1, 1, brightness); 1231 | if (result < 0) { 1232 | return result; 1233 | } 1234 | if (brightness != readRawRGBBrightness(id, addr)) { 1235 | return ROLLER_WRITE_FAILED; 1236 | } 1237 | return ROLLER_WRITE_SUCCESS; 1238 | } 1239 | 1240 | int8_t UnitRollerCAN::readRawFirmwareVersion(uint8_t id, uint8_t addr) 1241 | { 1242 | return readMotorRawParameter(id, addr, I2C_FIRMWARE_VERSION_REG); 1243 | } 1244 | 1245 | uint8_t UnitRollerCAN::readRawI2CAddress(uint8_t id, uint8_t addr) 1246 | { 1247 | return readMotorRawParameter(id, addr, I2C_ADDRESS_REG); 1248 | } 1249 | 1250 | int8_t UnitRollerCAN::writeRawI2CAddress(uint8_t id, uint8_t addr, uint8_t newAddr) 1251 | { 1252 | int8_t result = writeMotorRawParameter(id, addr, I2C_ADDRESS_REG, 1, 1, newAddr); 1253 | if (result < 0) { 1254 | return result; 1255 | } 1256 | if (newAddr != readRawI2CAddress(id, newAddr)) { 1257 | return ROLLER_WRITE_FAILED; 1258 | } 1259 | return ROLLER_WRITE_SUCCESS; 1260 | } 1261 | 1262 | int8_t UnitRollerCAN::writeResetStallProtect(uint8_t id, uint8_t addr, bool en) 1263 | { 1264 | int8_t result = writeMotorRawParameter(id, addr, I2C_RESET_STALLED_PROTECT_REG, 1, 1, en); 1265 | if (result < 0) { 1266 | return result; 1267 | } 1268 | return ROLLER_WRITE_SUCCESS; 1269 | } 1270 | 1271 | int8_t UnitRollerCAN::readStallProtect(uint8_t id, uint8_t addr) 1272 | { 1273 | return readMotorRawParameter(id, addr, I2C_STALL_PROTECTION_REG); 1274 | } 1275 | 1276 | int8_t UnitRollerCAN::writePosRangeProtect(uint8_t id, uint8_t addr, bool en) 1277 | { 1278 | int8_t result = writeMotorRawParameter(id, addr, I2C_POS_RANGE_PROTECT_REG, 1, 1, en); 1279 | if (result < 0) { 1280 | return result; 1281 | } 1282 | return ROLLER_WRITE_SUCCESS; 1283 | } 1284 | 1285 | int8_t UnitRollerCAN::writeStallProtect(uint8_t id, uint8_t addr, bool en) 1286 | { 1287 | int8_t result = writeMotorRawParameter(id, addr, I2C_STALL_PROTECTION_REG, 1, 1, en); 1288 | if (result < 0) { 1289 | return result; 1290 | } 1291 | if (en != readStallProtect(id, addr)) { 1292 | return ROLLER_WRITE_FAILED; 1293 | } 1294 | return ROLLER_WRITE_SUCCESS; 1295 | } 1296 | 1297 | int8_t UnitRollerCAN::readButton(uint8_t id, uint8_t addr) 1298 | { 1299 | return readMotorRawParameter(id, addr, I2C_KEY_SWTICH_MODE_REG); 1300 | } 1301 | 1302 | int8_t UnitRollerCAN::writeButton(uint8_t id, uint8_t addr, bool en) 1303 | { 1304 | int8_t result = writeMotorRawParameter(id, addr, I2C_KEY_SWTICH_MODE_REG, 1, 1, en); 1305 | if (result < 0) { 1306 | return result; 1307 | } 1308 | if (en != readButton(id, addr)) { 1309 | return ROLLER_WRITE_FAILED; 1310 | } 1311 | return ROLLER_WRITE_SUCCESS; 1312 | } 1313 | 1314 | int8_t UnitRollerCAN::readErrorCode(uint8_t id, uint8_t addr) 1315 | { 1316 | return readMotorRawParameter(id, addr, I2C_ERROR_CODE_REG); 1317 | } 1318 | 1319 | int8_t UnitRollerCAN::readSysStatus(uint8_t id, uint8_t addr) 1320 | { 1321 | return readMotorRawParameter(id, addr, I2C_SYS_STATUS_REG); 1322 | } 1323 | 1324 | uint8_t UnitRollerCAN::readMotorID(uint8_t id, uint8_t addr) 1325 | { 1326 | readMotorRawParameter(id, addr, I2C_ID_REG); 1327 | return readData[3]; 1328 | } 1329 | 1330 | int8_t UnitRollerCAN::writeMotorID(uint8_t id, uint8_t addr, uint8_t motorId) 1331 | { 1332 | int8_t result = writeMotorRawParameter(id, addr, I2C_ID_REG, 1, 1, motorId); 1333 | if (result < 0) { 1334 | return result; 1335 | } 1336 | if (motorId != readMotorID(id, addr)) { 1337 | return ROLLER_WRITE_FAILED; 1338 | } 1339 | return ROLLER_WRITE_SUCCESS; 1340 | } 1341 | 1342 | int8_t UnitRollerCAN::readBPS(uint8_t id, uint8_t addr) 1343 | { 1344 | return readMotorRawParameter(id, addr, I2C_BPS_REG); 1345 | } 1346 | 1347 | int8_t UnitRollerCAN::writeBPS(uint8_t id, uint8_t addr, roller_bps_t bps) 1348 | { 1349 | int8_t result = writeMotorRawParameter(id, addr, I2C_BPS_REG, 1, 1, bps); 1350 | if (result < 0) { 1351 | return result; 1352 | } 1353 | if (bps != readBPS(id, addr)) { 1354 | return ROLLER_WRITE_FAILED; 1355 | } 1356 | return ROLLER_WRITE_SUCCESS; 1357 | } 1358 | 1359 | bool UnitRollerCAN::sendData(uint8_t can_id, uint8_t cmd_id, uint16_t option, const uint8_t *data) 1360 | { 1361 | ping_message.flags |= (1 << 0); 1362 | ping_message.identifier = 0x00000000 | (cmd_id << 24) | (option << 16) | can_id; 1363 | for (int i = 0; i < 8; i++) { 1364 | ping_message.data[i] = data[i]; 1365 | } 1366 | #if defined UNIT_ROLLER_DEBUG 1367 | Serial.printf("send data: 0x%02X ", ping_message.identifier); 1368 | for (int i = 0; i < 8; i++) { 1369 | Serial.printf("0x%02X ", ping_message.data[i]); 1370 | } 1371 | Serial.printf("\n"); 1372 | #else 1373 | #endif 1374 | esp_err_t transmitResult = twai_transmit(&ping_message, 2000); 1375 | 1376 | if (transmitResult == ESP_OK) { 1377 | return true; 1378 | } else { 1379 | return false; 1380 | } 1381 | } 1382 | 1383 | int8_t UnitRollerCAN::receiveData() 1384 | { 1385 | twai_message_t rx_msg; 1386 | if (twai_receive(&rx_msg, pdMS_TO_TICKS(300)) == ESP_OK) { 1387 | #if defined UNIT_ROLLER_DEBUG 1388 | Serial.printf("received identifier: 0x%02X\r\n", rx_msg.identifier); 1389 | Serial.print("received data: "); 1390 | for (int i = 0; i < rx_msg.data_length_code; i++) { 1391 | Serial.printf("0x%02X ", rx_msg.data[i]); 1392 | } 1393 | Serial.println("\r\n"); 1394 | #else 1395 | #endif 1396 | for (int i = 0; i < rx_msg.data_length_code; i++) { 1397 | readData[i] = rx_msg.data[i]; 1398 | } 1399 | // Extract the CAN ID and other information 1400 | recv_motorId = (rx_msg.identifier >> 8) & 0xFF; // Bit8~Bit15: CAN ID of current motor 1401 | recv_faultInfo = (rx_msg.identifier >> 16) & 0x07; // Bit16~18: Fault information 1402 | recv_mode = (rx_msg.identifier >> 19) & 0x07; // Bit19~21: mode 1403 | recv_status = (rx_msg.identifier >> 22) & 0x03; // Bit22~23: status 1404 | return ROLLER_WRITE_SUCCESS; 1405 | } 1406 | return ROLLER_UNEXPECTED_RESPONSE; 1407 | } 1408 | 1409 | int8_t UnitRollerCAN::setMotorParameter(uint8_t id, uint16_t parameterId, int32_t parameterData) 1410 | { 1411 | acquireMutex(); 1412 | memset(canData, 0, sizeof(canData)); 1413 | canData[0] = (parameterId & 0xFF); 1414 | canData[1] = (parameterId >> 8) & 0xFF; 1415 | canData[4] = (parameterData & 0xFF); 1416 | canData[5] = (parameterData >> 8) & 0xFF; 1417 | canData[6] = (parameterData >> 16) & 0xFF; 1418 | canData[7] = (parameterData >> 24) & 0xFF; 1419 | if (!sendData(id, ROLLERCAN_WRITE_CMD, 0, canData)) { 1420 | releaseMutex(); 1421 | return ROLLER_SERIAL_SEND_FAILURE; 1422 | } 1423 | receiveData(); 1424 | releaseMutex(); 1425 | return ROLLER_WRITE_SUCCESS; 1426 | } 1427 | 1428 | int8_t UnitRollerCAN::setMotorPID(uint8_t id, uint16_t parameterId, uint32_t parameterData) 1429 | { 1430 | acquireMutex(); 1431 | memset(canData, 0, sizeof(canData)); 1432 | canData[0] = (parameterId & 0xFF); 1433 | canData[1] = (parameterId >> 8) & 0xFF; 1434 | canData[4] = (parameterData & 0xFF); 1435 | canData[5] = (parameterData >> 8) & 0xFF; 1436 | canData[6] = (parameterData >> 16) & 0xFF; 1437 | canData[7] = (parameterData >> 24) & 0xFF; 1438 | if (!sendData(id, ROLLERCAN_WRITE_CMD, 0, canData)) { 1439 | releaseMutex(); 1440 | return ROLLER_SERIAL_SEND_FAILURE; 1441 | } 1442 | receiveData(); 1443 | releaseMutex(); 1444 | return ROLLER_WRITE_SUCCESS; 1445 | } 1446 | 1447 | int32_t UnitRollerCAN::getMotorParameter(uint8_t id, uint16_t parameterId) 1448 | { 1449 | acquireMutex(); 1450 | memset(canData, 0, sizeof(canData)); 1451 | canData[0] = (parameterId & 0xFF); 1452 | canData[1] = (parameterId >> 8) & 0xFF; 1453 | if (!sendData(id, ROLLERCAN_READ_CMD, 0, canData)) { 1454 | releaseMutex(); 1455 | return ROLLER_WRITE_SUCCESS; 1456 | } 1457 | int8_t result = receiveData(); 1458 | if (result < 0) { 1459 | releaseMutex(); 1460 | return result; 1461 | } 1462 | int32_t returnValue = handleValue(readData[4], readData[5], readData[6], readData[7]); 1463 | #if defined UNIT_ROLLER_DEBUG 1464 | Serial.printf("Value:%d\n", returnValue); 1465 | #else 1466 | #endif 1467 | releaseMutex(); 1468 | return returnValue; 1469 | } 1470 | 1471 | int32_t UnitRollerCAN::readMotorParameter(uint8_t id, uint8_t addr, uint16_t parameterId) 1472 | { 1473 | acquireMutex(); 1474 | memset(canData, 0, sizeof(canData)); 1475 | canData[0] = (parameterId & 0xFF); 1476 | canData[1] = (parameterId >> 8) & 0xFF; 1477 | canData[2] = addr; 1478 | if (!sendData(id, ROLLERCAN_READ_I2C_CMD, 0, canData)) { 1479 | releaseMutex(); 1480 | return ROLLER_WRITE_FAILED; 1481 | } 1482 | int8_t result = receiveData(); 1483 | if (result < 0) { 1484 | releaseMutex(); 1485 | return result; 1486 | } 1487 | int32_t returnValue = handleValue(readData[4], readData[5], readData[6], readData[7]); 1488 | #if defined UNIT_ROLLER_DEBUG 1489 | Serial.printf("returnValue:%d\n", returnValue); 1490 | #else 1491 | #endif 1492 | releaseMutex(); 1493 | return returnValue; 1494 | } 1495 | 1496 | int8_t UnitRollerCAN::writeMotorParameter(uint8_t id, uint8_t addr, uint16_t parameterId, int32_t parameterData) 1497 | { 1498 | acquireMutex(); 1499 | memset(canData, 0, sizeof(canData)); 1500 | canData[0] = (parameterId & 0xFF); 1501 | canData[1] = (parameterId >> 8) & 0xFF; 1502 | canData[2] = addr; 1503 | canData[4] = (parameterData & 0xFF); 1504 | canData[5] = (parameterData >> 8) & 0xFF; 1505 | canData[6] = (parameterData >> 16) & 0xFF; 1506 | canData[7] = (parameterData >> 24) & 0xFF; 1507 | if (!sendData(id, ROLLERCAN_WRITE_I2C_CMD, 0, canData)) { 1508 | releaseMutex(); 1509 | return ROLLER_SERIAL_SEND_FAILURE; 1510 | } 1511 | receiveData(); 1512 | releaseMutex(); 1513 | return ROLLER_WRITE_SUCCESS; 1514 | } 1515 | int8_t UnitRollerCAN::writeMotorPID(uint8_t id, uint8_t addr, uint16_t parameterId, uint32_t parameterData) 1516 | { 1517 | acquireMutex(); 1518 | memset(canData, 0, sizeof(canData)); 1519 | canData[0] = (parameterId & 0xFF); 1520 | canData[1] = (parameterId >> 8) & 0xFF; 1521 | canData[2] = addr; 1522 | canData[4] = (parameterData & 0xFF); 1523 | canData[5] = (parameterData >> 8) & 0xFF; 1524 | canData[6] = (parameterData >> 16) & 0xFF; 1525 | canData[7] = (parameterData >> 24) & 0xFF; 1526 | if (!sendData(id, ROLLERCAN_WRITE_I2C_CMD, 0, canData)) { 1527 | releaseMutex(); 1528 | return ROLLER_SERIAL_SEND_FAILURE; 1529 | } 1530 | receiveData(); 1531 | releaseMutex(); 1532 | return ROLLER_WRITE_SUCCESS; 1533 | } 1534 | 1535 | int32_t UnitRollerCAN::readMotorRawParameter(uint8_t id, uint8_t addr, uint8_t reg) 1536 | { 1537 | memset(canData, 0, sizeof(canData)); 1538 | int8_t result = writeMotorRawParameter(id, addr, reg, 1, 0, 0); 1539 | if (result < 0) { 1540 | return result; 1541 | } 1542 | acquireMutex(); 1543 | memset(canData, 0, sizeof(canData)); 1544 | canData[0] = addr; 1545 | canData[1] = 4; 1546 | if (!sendData(id, ROLLERCAN_READ_I2C_RAW_CMD, 0, canData)) { 1547 | releaseMutex(); 1548 | return ROLLER_WRITE_FAILED; 1549 | } 1550 | int8_t res = receiveData(); 1551 | if (res < 0) { 1552 | releaseMutex(); 1553 | return res; 1554 | } 1555 | int32_t returnValue = handleValue(readData[0], readData[1], readData[2], readData[3]); 1556 | releaseMutex(); 1557 | return returnValue; 1558 | } 1559 | 1560 | int8_t UnitRollerCAN::writeMotorRawParameter(uint8_t id, uint8_t addr, uint8_t reg, uint8_t option, uint8_t len, 1561 | int32_t parameterData) 1562 | { 1563 | acquireMutex(); 1564 | memset(canData, 0, sizeof(canData)); 1565 | uint8_t new_value; 1566 | canData[0] = len + 1; 1567 | canData[1] = reg; 1568 | canData[2] = (parameterData & 0xFF); 1569 | canData[3] = (parameterData >> 8) & 0xFF; 1570 | canData[4] = (parameterData >> 16) & 0xFF; 1571 | canData[5] = (parameterData >> 24) & 0xFF; 1572 | if (option == 1) { 1573 | new_value = addr | 0x80; // If option is 1, set the high value 1574 | } else { 1575 | new_value = addr; 1576 | } 1577 | if (!sendData(id, ROLLERCAN_WRITE_I2C_RAW_CMD, new_value, canData)) { 1578 | releaseMutex(); 1579 | return ROLLER_SERIAL_SEND_FAILURE; 1580 | } 1581 | receiveData(); 1582 | releaseMutex(); 1583 | return ROLLER_WRITE_SUCCESS; 1584 | } 1585 | 1586 | int8_t UnitRollerCAN::writeMotorRawPID(uint8_t id, uint8_t addr, uint8_t reg, uint8_t option, uint8_t len, 1587 | uint32_t parameterData) 1588 | { 1589 | acquireMutex(); 1590 | memset(canData, 0, sizeof(canData)); 1591 | uint8_t new_value; 1592 | canData[0] = len + 1; 1593 | canData[1] = reg; 1594 | canData[2] = (parameterData & 0xFF); 1595 | canData[3] = (parameterData >> 8) & 0xFF; 1596 | canData[4] = (parameterData >> 16) & 0xFF; 1597 | canData[5] = (parameterData >> 24) & 0xFF; 1598 | if (option == 1) { 1599 | new_value = addr | 0x80; // If option is 1, set the high value 1600 | } else { 1601 | new_value = addr; 1602 | } 1603 | if (!sendData(id, ROLLERCAN_WRITE_I2C_RAW_CMD, new_value, canData)) { 1604 | releaseMutex(); 1605 | return ROLLER_SERIAL_SEND_FAILURE; 1606 | } 1607 | receiveData(); 1608 | releaseMutex(); 1609 | return ROLLER_WRITE_SUCCESS; 1610 | } 1611 | -------------------------------------------------------------------------------- /src/unit_rolleri2c.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | *SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | *SPDX-License-Identifier: MIT 5 | */ 6 | 7 | #ifndef __UNIT_ROLLERI2C_H 8 | #define __UNIT_ROLLERI2C_H 9 | 10 | #include "Arduino.h" 11 | #include "Wire.h" 12 | #include "unit_roller_common.hpp" 13 | 14 | class UnitRollerI2C { 15 | public: 16 | /** 17 | * @brief Initializes the UnitRollerI2C object with I2C communication settings. 18 | * 19 | * This function configures the I2C bus with specified SDA and SCL pins, sets the clock speed, 20 | * and checks for communication with the device at the given address. It returns true if 21 | * the device responds to the initial transmission; otherwise, it returns false. 22 | * 23 | * @param wire Pointer to a TwoWire object used for I2C communication. 24 | * @param addr The I2C address of the device to communicate with. 25 | * @param sda The GPIO pin number used for the SDA line. 26 | * @param scl The GPIO pin number used for the SCL line. 27 | * @param speed The clock speed for the I2C bus in Hertz. 28 | * 29 | * @return True if the initialization was successful and the device is responsive, 30 | * false otherwise. 31 | * 32 | * @note It is recommended to call this function before atdatating any other 33 | * communication with the device. A delay is included after setting up 34 | * the I2C configuration to allow the device time to stabilize. 35 | */ 36 | bool begin(TwoWire *wire = &Wire, uint8_t addr = I2C_ADDR, uint8_t sda = 21, uint8_t scl = 22, 37 | uint32_t speed = 4000000L); 38 | 39 | /** 40 | * @brief Sets the operational mode of the UnitRollerI2C device. 41 | * 42 | * This function writes a byte to the mode register of the 43 | * UnitRollerI2C device to configure its operational mode. 44 | * The desired operational mode is specified by the input parameter. 45 | * 46 | * @param mode A byte value representing the desired operational mode: 47 | * - 1: Speed Mode 48 | * - 2: Position Mode 49 | * - 3: Current Mode 50 | * - 4: Encoder Mode 51 | * 52 | * @note Ensure that I2C communication has been properly initialized 53 | * before calling this function. The specific register being written 54 | * to is identified by the constant UnitRollerI2C_MODE_REG. 55 | */ 56 | void setMode(roller_mode_t mode); 57 | 58 | /** 59 | * @brief Enables or disables the output of the UnitRollerI2C device. 60 | * 61 | * This function writes a single byte to the output register of the 62 | * UnitRollerI2C device to control whether the output is enabled 63 | * or disabled. The value of the input parameter determines the state 64 | * of the output. 65 | * 66 | * @param en A byte value representing the desired output state: 67 | * - 0: Disable output 68 | * - 1: Enable output 69 | * 70 | * @note Ensure that I2C communication has been properly initialized 71 | * before calling this function. The specific register being written 72 | * to is identified by the constant UnitRollerI2C_OUTPUT_REG. 73 | */ 74 | void setOutput(uint8_t en); 75 | 76 | /** 77 | * @brief Sets the speed of the UnitRollerI2C device. 78 | * 79 | * This function writes a 32-bit integer value to the speed register of the 80 | * UnitRollerI2C device, allowing the user to configure the motor's speed. 81 | * The speed value can be positive or negative, where positive values typically 82 | * indicate forward motion and negative values indicate reverse motion. 83 | * 84 | * @param speed A 32-bit integer representing the desired speed of the motor. 85 | * The valid range may depend on the specific implementation and 86 | * capabilities of the UnitRollerI2C device. 87 | * 88 | * @note Ensure that I2C communication has been properly initialized 89 | * before calling this function. The specific register being written 90 | * to is identified by the constant UnitRollerI2C_SPEED_REG. 91 | */ 92 | void setSpeed(int32_t speed); 93 | 94 | /** 95 | * @brief Sets the maximum current limit for speed control in the UnitRollerI2C device. 96 | * 97 | * This function writes a 32-bit integer value to the maximum current register of the 98 | * UnitRollerI2C device. This allows the user to set a limit on the current that 99 | * can be drawn by the motor when operating at maximum speed, which helps prevent 100 | * overheating or damage to the device. 101 | * 102 | * @param current A 32-bit signed integer representing the desired current limit. 103 | * The valid range is from -120,000 to 120,000, which corresponds 104 | * to the allowable current levels in milliamps. 105 | * 106 | * @note Ensure that I2C communication has been properly initialized 107 | * before calling this function. The specific register being written 108 | * to is identified by the constant UnitRollerI2C_SPEED_MAX_CURRENT_REG. 109 | */ 110 | void setSpeedMaxCurrent(int32_t current); 111 | 112 | /** 113 | * @brief Sets the PID (Proportional, Integral, Derivative) coefficients for speed control 114 | * in the UnitRollerI2C device. 115 | * 116 | * This function writes three 32-bit unsigned integer values to the PID coefficient register of 117 | * the UnitRollerI2C device. These coefficients are used in the PID control algorithm 118 | * to regulate the speed of the motor, allowing for precise control based on the 119 | * current error, accumulated past errors, and the rate of change of error. 120 | * 121 | * @param p A 32-bit unsigned integer representing the proportional coefficient of the PID controller. 122 | * This coefficient determines how aggressively the controller responds to the current error. 123 | * For example: mottor P=0.004, speedP setting value=0.004*100000=400, 124 | * 125 | * @param i A 32-bit unsigned integer representing the integral coefficient of the PID controller. 126 | * This coefficient helps eliminate steady-state error by adjusting the output based 127 | * on the accumulated error over time. 128 | * For example: mottor I=0.002, speedI settingvalue=0.002*10000000=20000, 129 | * 130 | * @param d A 32-bit unsigned integer representing the derivative coefficient of the PID controller. 131 | * This coefficient predicts future error based on its rate of change, providing a 132 | * damping effect to reduce overshoot. 133 | * For example: mottor D=16.00, speedD setting value=16.00*100000=1600000, 134 | * 135 | * @note Ensure that I2C communication has been properly initialized 136 | * before calling this function. The specific register being written 137 | * to is identified by the constant UnitRollerI2C_SPEED_PID_REG. 138 | * Each coefficient is sent in the following order: proportional, integral, and then derivative. 139 | */ 140 | void setSpeedPID(uint32_t p, uint32_t i, uint32_t d); 141 | 142 | /** 143 | * @brief Sets the position of the UnitRollerI2C device. 144 | * 145 | * This function writes a 32-bit integer value to the position register of the 146 | * UnitRollerI2C device, allowing the user to configure the desired position 147 | * for operation. The position value can be positive or negative, depending on 148 | * the specific implementation and the context in which the device operates. 149 | * 150 | * @param pos A 32-bit integer representing the desired position of the device. 151 | * The valid range for the position may depend on the specific use case 152 | * and capabilities of the UnitRollerI2C device. 153 | * 154 | * @note Ensure that I2C communication has been properly initialized 155 | * before calling this function. The specific register being written 156 | * to is identified by the constant UnitRollerI2C_POS_REG. 157 | */ 158 | void setPos(int32_t pos); 159 | 160 | /** 161 | * @brief Sets the maximum current limit for position control in the UnitRollerI2C device. 162 | * 163 | * This function writes a 32-bit integer value to the maximum current register of the 164 | * UnitRollerI2C device. This allows the user to set a limit on the current that 165 | * can be drawn by the motor when operating at maximum position, helping to prevent 166 | * overheating and ensuring safe operation of the device. 167 | * 168 | * @param current A 32-bit signed integer representing the desired current limit. 169 | * The valid range is from -120,000 to 120,000, which corresponds 170 | * to the allowable current levels in milliamps. 171 | * 172 | * @note Ensure that I2C communication has been properly initialized 173 | * before calling this function. The specific register being written 174 | * to is identified by the constant UnitRollerI2C_POS_MAX_CURRENT_REG. 175 | */ 176 | void setPosMaxCurrent(int32_t current); 177 | 178 | /** 179 | * @brief Sets the PID (Proportional, Integral, Derivative) coefficients for position control 180 | * in the UnitRollerI2C device. 181 | * 182 | * This function writes three 32-bit unsigned integer values to the PID coefficient register of 183 | * the UnitRollerI2C device. These coefficients are used in the PID control algorithm 184 | * to accurately control the position of the motor, allowing for fine adjustments based on 185 | * the current positional error, accumulated past errors, and the rate of change of error. 186 | * 187 | * @param p A 32-bit unsigned integer representing the proportional coefficient of the PID controller. 188 | * This coefficient determines how aggressively the controller responds to the current positional error. 189 | * For example: mottor P=0.004, speedP setting value=0.004*100000=400, 190 | * 191 | * @param i A 32-bit unsigned integer representing the integral coefficient of the PID controller. 192 | * This coefficient helps eliminate steady-state error by adjusting the output based 193 | * on the accumulated positional error over time. 194 | * For example: mottor I=0.002, speedI settingvalue=0.002*10000000=20000, 195 | * 196 | * @param d A 32-bit unsigned integer representing the derivative coefficient of the PID controller. 197 | * This coefficient predicts future positional error based on its rate of change, providing a 198 | * damping effect to reduce overshoot when moving to the desired position. 199 | * For example: mottor D=16.00, speedD setting value=16.00*100000=1600000, 200 | * 201 | * @note Ensure that I2C communication has been properly initialized 202 | * before calling this function. The specific register being written 203 | * to is identified by the constant UnitRollerI2C_POS_PID_REG. 204 | * Each coefficient is sent in the following order: proportional, integral, and then derivative. 205 | */ 206 | void setPosPID(uint32_t p, uint32_t i, uint32_t d); 207 | 208 | /** 209 | * @brief Sets the current limit for the UnitRollerI2C device. 210 | * 211 | * This function writes a 32-bit integer value to the current register of the 212 | * UnitRollerI2C device. This allows the user to specify the desired current 213 | * level (in milliamps or appropriate units) that the device should maintain 214 | * during operation, helping to protect against overcurrent conditions. 215 | * 216 | * @param current A 32-bit signed integer representing the desired current limit. 217 | * The valid range is from -120,000 to 120,000, which corresponds 218 | * to the allowable current levels in milliamps. 219 | * 220 | * @note Ensure that I2C communication has been properly initialized 221 | * before calling this function. The specific register being written 222 | * to is identified by the constant UnitRollerI2C_CURRENT_REG. 223 | */ 224 | void setCurrent(int32_t current); 225 | 226 | /** 227 | * @brief Sets the dial counter value for the UnitRollerI2C encoder. 228 | * 229 | * This function writes a 32-bit integer value to the dial counter register of 230 | * the UnitRollerI2C device. The dial counter is used to track the position or 231 | * rotation count of the encoder, allowing for precise measurement and control of 232 | * angular displacement. 233 | * 234 | * @param counter A 32-bit signed integer representing the desired dial counter value. 235 | * This value can be set to reflect the current position of the encoder 236 | * and may range anywhere within the limits of a 32-bit signed integer. 237 | * 238 | * @note Ensure that I2C communication has been properly initialized 239 | * before calling this function. The specific register being written 240 | * to is identified by the constant UnitRollerI2C_DIAL_COUNTER_REG. 241 | */ 242 | void setDialCounter(int32_t counter); 243 | 244 | /** 245 | * @brief Sets the RGB mode for the UnitRollerI2C device. 246 | * 247 | * This function writes a value to the RGB mode register to configure the 248 | * device's operation mode for RGB lighting. The mode can be set to either 249 | * a system-default or user-defined configuration. 250 | * 251 | * @param mode A uint8_t value representing the desired RGB mode. 252 | * Possible values are: 253 | * - 0: System-default mode 254 | * - 1: User-defined mode 255 | * 256 | * @note Ensure that I2C communication has been properly initialized 257 | * before calling this function. The RGB mode is set by writing to 258 | * the register identified by UnitRollerI2C_RGB_REG + 3. 259 | */ 260 | void setRGBMode(roller_rgb_t mode); 261 | 262 | /** 263 | * @brief Set the RGB color value. 264 | * 265 | * This function converts the specified color value to BGR format and writes it 266 | * to the appropriate register of the device. 267 | * 268 | * @param color The color value to set, typically an integer representing RGB color. 269 | * If using a 16-bit RGB565 format, the color consists of 5 bits for red, 270 | * 6 bits for green, and 5 bits for blue. In this case, the color parameter 271 | * should be provided in the correct format to ensure accurate extraction. 272 | * 273 | * - R: (color >> 11) & 0x1F (5 bits) 274 | * - G: (color >> 5) & 0x3F (6 bits) 275 | * - B: color & 0x1F (5 bits) 276 | * 277 | * The extracted R, G, and B components will be expanded to 8 bits for compatibility 278 | * with standard RGB values. 279 | * 280 | * @note Extraction and expansion algorithm: 281 | * - Red component is expanded to 8 bits by multiplying by 255 and dividing by 31. 282 | * - Green component is expanded to 8 bits by multiplying by 255 and dividing by 63. 283 | * - Blue component is expanded to 8 bits by multiplying by 255 and dividing by 31. 284 | * 285 | * Finally, the R, G, B values are stored in a byte array in BGR format and 286 | * written to the device via the writeBytes function. 287 | */ 288 | void setRGB(int32_t color); 289 | 290 | /** 291 | * @brief Sets the brightness of the RGB LED on the UnitRollerI2C device. 292 | * 293 | * This function writes a byte to the RGB brightness register of the 294 | * UnitRollerI2C device, allowing the user to adjust the brightness 295 | * level of the RGB LED. The brightness level is specified by the 296 | * input parameter, which should be within the defined range. 297 | * 298 | * @param brightness A byte value representing the desired brightness level, 299 | * valid in the range of 0 to 100. 300 | * - 0: Off 301 | * - 100: Maximum brightness 302 | * 303 | * @note Ensure that I2C communication has been properly initialized 304 | * before calling this function. The specific register being written 305 | * to is identified by the constant UnitRollerI2C_RGB_BRIGHTNESS_REG. 306 | */ 307 | void setRGBBrightness(uint8_t brightness); 308 | 309 | /** 310 | * @brief Sets the motor ID for the UnitRollerI2C device. 311 | * 312 | * This function writes a byte to the ID register of the 313 | * UnitRollerI2C device to configure its motor ID. 314 | * The motor ID is used to uniquely identify the motor within 315 | * a system that may have multiple motors connected. 316 | * 317 | * @param id A byte value representing the motor ID, valid in the range 318 | * of 0 to 255. Each motor should have a unique ID within this range. 319 | * 320 | * @note Ensure that I2C communication has been properly initialized 321 | * before calling this function. The specific register being written 322 | * to is identified by the constant UnitRollerI2C_ID_REG. 323 | */ 324 | void setMotorID(uint8_t id); 325 | 326 | /** 327 | * @brief Sets the baud rate for the UnitRollerI2C device. 328 | * 329 | * This function writes a byte to the baud rate register of the 330 | * UnitRollerI2C device, allowing the user to configure the 331 | * communication speed. The specified baud rate is determined by 332 | * the input parameter. 333 | * 334 | * @param bps A byte value representing the desired baud rate: 335 | * - 0: 115200 bps 336 | * - 1: 19200 bps 337 | * - 2: 9600 bps 338 | * 339 | * @note Ensure that I2C communication has been properly initialized 340 | * before calling this function. The specific register being written 341 | * to is identified by the constant UnitRollerI2C_BPS_REG. 342 | */ 343 | void setBPS(roller_bps_t bps); 344 | 345 | /** 346 | * @brief Saves the most recent configuration changes of the UnitRollerI2C device to flash memory. 347 | * 348 | * This function writes a value to the designated flash save register to 349 | * trigger the storage of the latest configuration settings into non-volatile 350 | * flash memory. This ensures that all modifications made during the current 351 | * session are retained even when the device is powered off or reset. 352 | * 353 | * @note A single byte with the value of 1 is sent to the register 354 | * (UnitRollerI2C_SAVE_FLASH_REG) to initiate the saving process. 355 | * After the write operation, a delay of 100 milliseconds is included 356 | * to allow sufficient time for the saving process to complete. 357 | * 358 | * Ensure that I2C communication has been properly initialized 359 | * before calling this function. 360 | */ 361 | void saveConfigToFlash(void); 362 | 363 | /** 364 | * @brief Set the motor position range protection mechanism. 365 | * 366 | * This function enables or disables the position range protection mechanism 367 | * for the motor. 368 | * 369 | * @param en A uint8_t value to enable (1) or disable (0) the protection 370 | * mechanism. 371 | * - 0: Disable 372 | * - 1: Enable 373 | * 374 | * @details This function writes the specified value to a designated register 375 | * to control the position range protection of the motor during operation. The 376 | * protection mechanism helps prevent the motor from exceeding its safe 377 | * operating range, avoiding potential damage. 378 | * 379 | * @return void 380 | */ 381 | void posRangeProtect(uint8_t en); 382 | /** 383 | * @brief Resets the stalled protection mechanism of the UnitRollerI2C device. 384 | * 385 | * This function writes a specific value to the stalled protection reset register 386 | * to clear any stall conditions that may have been detected by the device. 387 | * This is useful for re-enabling normal operation after a stall has occurred 388 | * and needs to be addressed. 389 | * 390 | * @note A single byte with the value of 1 is sent to the register 391 | * (UnitRollerI2C_RESET_STALLED_PROTECT_REG) to initiate the reset 392 | * of the stalled protection feature. 393 | * 394 | * Ensure that I2C communication has been properly initialized 395 | * before calling this function. 396 | */ 397 | void resetStalledProtect(void); 398 | 399 | /** 400 | * @brief Configures the key switch mode on the UnitRollerI2C device. 401 | * 402 | * This function sets the key switch mode by writing a byte to the 403 | * corresponding register in the UnitRollerI2C device. It takes an 404 | * enable/disable value as input, which determines the mode of operation. 405 | * 406 | * @param en A byte value (0 or 1) indicating whether to enable (1) 407 | * or disable (0) the key switch mode. 408 | * 409 | * @note The function assumes that the I2C communication has been properly 410 | * initialized before calling this function. The specific register 411 | * being written to is defined by the constant 412 | * UnitRollerI2C_KEY_SWTICH_MODE_REG. 413 | */ 414 | void setKeySwitchMode(uint8_t en); 415 | 416 | /** 417 | * @brief Configures the stall protection feature of the UnitRollerI2C device. 418 | * 419 | * This function writes a byte to the stall protection register of the 420 | * UnitRollerI2C device to enable or disable the stall protection feature. 421 | * This feature helps prevent motor stalls by monitoring the motor's operation 422 | * and taking corrective action when necessary. 423 | * 424 | * @param en A byte value indicating whether to enable (1) or disable (0) 425 | * the stall protection feature. 426 | * 427 | * @note Ensure that I2C communication has been properly initialized 428 | * before calling this function. The specific register being written 429 | * to is identified by the constant UnitRollerI2C_STALL_PROTECTION_REG. 430 | */ 431 | void setStallProtection(uint8_t en); 432 | 433 | /** 434 | * @brief Sets the I2C address for the UnitRollerI2C device. 435 | * 436 | * This function updates the I2C address used to communicate with the 437 | * UnitRollerI2C device. It sends the new address to the device over 438 | * the I2C bus, allowing for dynamic reconfiguration of communication 439 | * settings. 440 | * 441 | * @param addr The new I2C address to be set for the device. This should 442 | * be a valid I2C address between 1 and 127. 443 | * 444 | * @return uint8_t The updated I2C address that was set for the device. 445 | * 446 | * @note Ensure that the specified address does not conflict with other 447 | * devices on the I2C bus. It is also important to verify that 448 | * the device is powered on and properly connected before calling 449 | * this function. 450 | */ 451 | uint8_t setI2CAddress(uint8_t addr); 452 | 453 | /** 454 | * @brief Start the encoder calibration process. 455 | * 456 | * This is an internal factory command that 457 | * is used to initiate the calibration process for the magnetic encoder. 458 | * 459 | * 460 | * @note Ensure that I2C communication has been properly initialized 461 | * before calling this function. 462 | */ 463 | void startAngleCal(void); 464 | 465 | /** 466 | * @brief Update the encoder calibration value to the UnitRollerI2C device. 467 | * 468 | * This is an internal factory command 469 | * used to update the calibration value of the magnetic encoder. 470 | * 471 | * 472 | * @note Ensure that I2C communication has been properly initialized 473 | * before calling this function. 474 | */ 475 | void updateAngleCal(void); 476 | 477 | /** 478 | * @brief Retrieves the status of calibrating the magnetic encoder. 479 | * 480 | * This is an internal factory command 481 | * used to retrieve the calibration status of the magnetic encoder. 482 | * 483 | * @return uint8_t 1 Calibrating 484 | * 0 Not calibrated 485 | * 486 | * @note Ensure that I2C communication has been properly initialized 487 | * before calling this function. 488 | */ 489 | uint8_t getCalBusyStatus(void); 490 | 491 | /** 492 | * @brief Retrieves the Speed PID parameters from the UnitRollerI2C device. 493 | * 494 | * This function reads the proportional (P), integral (I), and derivative (D) 495 | * values used in the speed PID control loop from the device's registers. 496 | * The retrieved values are stored in the provided pointers. 497 | * 498 | * @param p A pointer to a uint32_t variable where the proportional value will be stored. 499 | * @param i A pointer to a uint32_t variable where the integral value will be stored. 500 | * @param d A pointer to a uint32_t variable where the derivative value will be stored. 501 | * 502 | * @note The function reads 12 bytes of data starting from the register 503 | * (UnitRollerI2C_SPEED_PID_REG). The first 4 bytes correspond to the P value, 504 | * the next 4 bytes correspond to the I value, and the last 4 bytes correspond 505 | * to the D value. Ensure that I2C communication has been properly initialized 506 | * before calling this function. 507 | */ 508 | void getSpeedPID(uint32_t *p, uint32_t *i, uint32_t *d); 509 | 510 | /** 511 | * @brief Retrieves the Position PID parameters from the UnitRollerI2C device. 512 | * 513 | * This function reads the proportional (P), integral (I), and derivative (D) 514 | * values used in the position PID control loop from the device's registers. 515 | * The retrieved values are then stored in the provided pointers. 516 | * 517 | * @param p A pointer to a uint32_t variable where the proportional value will be stored. 518 | * @param i A pointer to a uint32_t variable where the integral value will be stored. 519 | * @param d A pointer to a uint32_t variable where the derivative value will be stored. 520 | * 521 | * @note The function reads 12 bytes of data starting from the register 522 | * (UnitRollerI2C_POS_PID_REG). The first 4 bytes correspond to the P value, 523 | * the next 4 bytes correspond to the I value, and the last 4 bytes correspond 524 | * to the D value. Ensure that I2C communication has been properly initialized 525 | * before calling this function. 526 | */ 527 | void getPosPID(uint32_t *p, uint32_t *i, uint32_t *d); 528 | 529 | /** 530 | * @brief Retrieves the RGB values from the Unit Roller I2C device. 531 | * 532 | * This function reads three bytes of RGB data from the specified 533 | * I2C address and stores the values in the provided pointers. 534 | * The RGB values are expected to be ordered as follows: 535 | * - R: data[2] 536 | * - G: data[1] 537 | * - B: data[0] 538 | * 539 | * @param r Pointer to a uint8_t variable where the red value will be stored. 540 | * @param g Pointer to a uint8_t variable where the green value will be stored. 541 | * @param b Pointer to a uint8_t variable where the blue value will be stored. 542 | * 543 | * @note Ensure that the pointers passed to this function are valid 544 | * and point to allocated memory large enough to hold the values. 545 | */ 546 | void getRGB(uint8_t *r, uint8_t *g, uint8_t *b); 547 | 548 | /** 549 | * @brief Retrieves the speed value from the UnitRollerI2C device. 550 | * 551 | * This function reads a 32-bit integer value representing the desired or 552 | * commanded speed of the device. The retrieved value indicates the speed 553 | * setting that the device is configured to achieve. 554 | * 555 | * @return int32_t The speed value, as a signed 32-bit integer. 556 | * The value may represent speed in units such as RPM 557 | * (revolutions per minute) or another relevant measure, 558 | * depending on the device's specifications. 559 | * 560 | * @note The function reads 4 bytes of data starting from the register 561 | * (UnitRollerI2C_SPEED_REG). Ensure that I2C communication has been 562 | * properly initialized before calling this function. 563 | */ 564 | int32_t getSpeed(void); 565 | 566 | /** 567 | * @brief Retrieves the maximum current value permitted at the specified speed 568 | * from the UnitRollerI2C device. 569 | * 570 | * This function reads a 32-bit integer value representing the maximum 571 | * current that the device is allowed to draw when operating at its set speed. 572 | * This value can be useful for ensuring safe operation and preventing 573 | * overcurrent conditions. 574 | * 575 | * @return int32_t The maximum current value, as a signed 32-bit integer. 576 | * The value may represent current in units such as milliamps 577 | * (mA) or another relevant measure, depending on the device's 578 | * specifications. 579 | * 580 | * @note The function reads 4 bytes of data starting from the register 581 | * (UnitRollerI2C_SPEED_MAX_CURRENT_REG). Ensure that I2C communication 582 | * has been properly initialized before calling this function. 583 | */ 584 | int32_t getSpeedMaxCurrent(void); 585 | 586 | /** 587 | * @brief Retrieves the actual speed readback value from the UnitRollerI2C device. 588 | * 589 | * This function reads a 32-bit integer value representing the current speed 590 | * of the device. The retrieved value indicates the actual speed being measured 591 | * at the moment and is returned to the caller. 592 | * 593 | * @return int32_t The actual speed value, as a signed 32-bit integer. 594 | * The value may represent speed in units such as RPM 595 | * (revolutions per minute) or another relevant measure, 596 | * depending on the device's specifications. 597 | * 598 | * @note The function reads 4 bytes of data starting from the register 599 | * (UnitRollerI2C_SPEED_READBACK_REG). Ensure that I2C communication has been 600 | * properly initialized before calling this function. 601 | */ 602 | int32_t getSpeedReadback(void); 603 | 604 | /** 605 | * @brief Retrieves the current position value from the UnitRollerI2C device. 606 | * 607 | * This function reads a 32-bit integer value representing the current position 608 | * of the device. The retrieved value indicates the position in units that are 609 | * defined by the device's specifications, which could be in counts, degrees, 610 | * or another relevant measure. 611 | * 612 | * @return int32_t The current position value, as a signed 32-bit integer. 613 | * The specific unit of measurement depends on the device 614 | * implementation and configuration. 615 | * 616 | * @note The function reads 4 bytes of data starting from the register 617 | * (UnitRollerI2C_POS_REG). Ensure that I2C communication has been 618 | * properly initialized before calling this function. 619 | */ 620 | int32_t getPos(void); 621 | 622 | /** 623 | * @brief Retrieves the maximum current value permitted at the specified position 624 | * from the UnitRollerI2C device. 625 | * 626 | * This function reads a 32-bit integer value representing the maximum 627 | * current that the device is allowed to draw when operating at its set position. 628 | * This value is important for preventing overcurrent situations and ensuring safe 629 | * operation of the device. 630 | * 631 | * @return int32_t The maximum current value, as a signed 32-bit integer. 632 | * The value may represent current in units such as milliamps 633 | * (mA) or another relevant measure, depending on the device's 634 | * specifications. 635 | * 636 | * @note The function reads 4 bytes of data starting from the register 637 | * (UnitRollerI2C_POS_MAX_CURRENT_REG). Ensure that I2C communication 638 | * has been properly initialized before calling this function. 639 | */ 640 | int32_t getPosMaxCurrent(void); 641 | 642 | /** 643 | * @brief Retrieves the real-time position value from the UnitRollerI2C device. 644 | * 645 | * This function reads a 32-bit integer value representing the current 646 | * position of the device in real time. The retrieved value provides 647 | * insight into the actual position where the device is currently located, 648 | * which may be useful for monitoring and control purposes. 649 | * 650 | * @return int32_t The real-time position value, as a signed 32-bit integer. 651 | * The specific unit of measurement depends on the device's 652 | * specifications, such as counts, degrees, or another relevant 653 | * measure. 654 | * 655 | * @note The function reads 4 bytes of data starting from the register 656 | * (UnitRollerI2C_POS_READBACK_REG). Ensure that I2C communication has been 657 | * properly initialized before calling this function. 658 | */ 659 | int32_t getPosReadback(void); 660 | 661 | /** 662 | * @brief Retrieves the current value from the UnitRollerI2C device. 663 | * 664 | * This function reads a 32-bit integer value representing the current 665 | * flowing through the device. The retrieved value is stored in a dataorary 666 | * variable and returned to the caller. 667 | * 668 | * @return int32_t The current value, as a signed 32-bit integer. 669 | * The value may represent the current in milliamps (mA) or 670 | * another unit, depending on the device's specifications. 671 | * 672 | * @note The function reads 4 bytes of data starting from the register 673 | * (UnitRollerI2C_CURRENT_REG). Ensure that I2C communication has been 674 | * properly initialized before calling this function. 675 | */ 676 | int32_t getCurrent(void); 677 | 678 | /** 679 | * @brief Retrieves the real-time current value from the UnitRollerI2C device. 680 | * 681 | * This function reads a 32-bit integer value representing the current 682 | * flowing through the device in real time. The retrieved value provides 683 | * insight into the actual current consumption of the device, which is useful 684 | * for monitoring performance and ensuring safe operation. 685 | * 686 | * @return int32_t The real-time current value, as a signed 32-bit integer. 687 | * The specific unit of measurement may vary, commonly represented 688 | * in milliamps (mA) or another relevant measure, depending on 689 | * the device's specifications. 690 | * 691 | * @note The function reads 4 bytes of data starting from the register 692 | * (UnitRollerI2C_CURRENT_READBACK_REG). Ensure that I2C communication 693 | * has been properly initialized before calling this function. 694 | */ 695 | int32_t getCurrentReadback(void); 696 | 697 | /** 698 | * @brief Retrieves the encoder value from the motor using the UnitRollerI2C device. 699 | * 700 | * This function reads a 32-bit integer value representing the current 701 | * position of the motor's encoder. The retrieved value is crucial for 702 | * tracking the motor's position or rotation count, which can be used 703 | * for precise control and feedback in various applications. 704 | * 705 | * @return int32_t The encoder value, as a signed 32-bit integer. 706 | * This value may represent counts, ticks, or another 707 | * relevant unit depending on the specific implementation 708 | * and configuration of the encoder. 709 | * 710 | * @note The function reads 4 bytes of data starting from the register 711 | * (UnitRollerI2C_DIAL_COUNTER_REG). Ensure that I2C communication 712 | * has been properly initialized before calling this function. 713 | */ 714 | int32_t getDialCounter(void); 715 | 716 | /** 717 | * @brief Retrieves the input voltage value from the UnitRollerI2C device. 718 | * 719 | * This function reads a 32-bit integer value representing the input 720 | * voltage (Vin) supplied to the device. The retrieved value is useful 721 | * for monitoring the power supply conditions and ensuring that the 722 | * device operates within acceptable voltage levels. 723 | * 724 | * @return int32_t The input voltage value, as a signed 32-bit integer. 725 | * The specific unit of measurement may vary, commonly 726 | * represented in volts (V) or millivolts (mV), depending 727 | * on the device's specifications. 728 | * 729 | * @note The function reads 4 bytes of data starting from the register 730 | * (UnitRollerI2C_VIN_REG). Ensure that I2C communication has been 731 | * properly initialized before calling this function. 732 | */ 733 | int32_t getVin(void); 734 | 735 | /** 736 | * @brief Retrieves the Temperature of the motor from the UnitRollerI2C device. 737 | * 738 | * This function reads a 32-bit integer value representing the current 739 | * Temperature of the motor. The retrieved value is essential for monitoring 740 | * the thermal conditions of the motor to prevent overheating and ensure safe 741 | * operation. 742 | * 743 | * @return int32_t The motor Temperature value, as a signed 32-bit integer. 744 | * The specific unit of measurement may vary, commonly 745 | * represented in degrees Celsius (°C) or another relevant 746 | * unit, depending on the device's specifications. 747 | * 748 | * @note The function reads 4 bytes of data starting from the register 749 | * (UnitRollerI2C_TEMP_REG). Ensure that I2C communication has been 750 | * properly initialized before calling this function. 751 | */ 752 | int32_t getTemp(void); 753 | 754 | /** 755 | * @brief Retrieves the system status of the motor from the UnitRollerI2C device. 756 | * 757 | * This function reads a single byte representing the current operating 758 | * status of the motor. The retrieved status can be used to determine 759 | * whether the motor is in standby, actively running, or experiencing an error. 760 | * 761 | * @return uint8_t The motor status: 762 | * - 0: Standby 763 | * - 1: Running 764 | * - 2: Error 765 | * Other values may represent different statuses depending on the 766 | * specific implementation of the device. 767 | * 768 | * @note The function reads 1 byte of data starting from the register 769 | * (UnitRollerI2C_SYS_STATUS_REG). Ensure that I2C communication 770 | * has been properly initialized before calling this function. 771 | */ 772 | uint8_t getSysStatus(void); 773 | 774 | /** 775 | * @brief Retrieves the error code from the UnitRollerI2C device. 776 | * 777 | * This function reads a single byte representing the current error state 778 | * of the motor. The retrieved error code can be used to diagnose issues 779 | * such as overvoltage or mechanical jams. 780 | * 781 | * @return uint8_t The motor error code: 782 | * - 0: No error 783 | * - 1: Overvoltage 784 | * - 2: Jam 785 | * Other values may represent different error states depending on 786 | * the specific implementation of the device. 787 | * 788 | * @note The function reads 1 byte of data starting from the register 789 | * (UnitRollerI2C_ERROR_CODE_REG). Ensure that I2C communication 790 | * has been properly initialized before calling this function. 791 | */ 792 | uint8_t getErrorCode(void); 793 | 794 | /** 795 | * @brief Get the current state of the motor position range protection 796 | * mechanism. 797 | * 798 | * This function reads the status of the position range protection mechanism 799 | * for the motor. 800 | * 801 | * @details The function retrieves the value from a designated register, 802 | * indicating whether the position range protection is enabled or disabled. 803 | * The returned value can be used to determine the current state of the 804 | * protection mechanism: 805 | * - 0: Disabled 806 | * - 1: Enabled 807 | * 808 | * @return uint8_t The current state of the position range protection (0 or 809 | * 1). 810 | */ 811 | uint8_t getPosRangeProtect(void); 812 | 813 | /** 814 | * @brief Retrieves the current status of the stall protection feature 815 | * from the UnitRollerI2C device. 816 | * 817 | * This function reads a byte from the stall protection register of the 818 | * UnitRollerI2C device to determine whether the stall protection feature 819 | * is enabled or disabled. The returned value indicates the current state. 820 | * 821 | * @return A byte value representing the stall protection status: 822 | * 0 if disabled, 1 if enabled. 823 | * 824 | * @note Ensure that I2C communication has been properly initialized 825 | * before calling this function. The specific register being read 826 | * from is defined by the constant UnitRollerI2C_STALL_PROTECTION_REG. 827 | */ 828 | uint8_t getStallProtection(void); 829 | 830 | /** 831 | * @brief Retrieves the current key switch mode from the UnitRollerI2C device. 832 | * 833 | * This function reads a single byte representing the current key switch mode 834 | * setting. The retrieved value indicates whether the button switching mode is 835 | * enabled and how it operates during running mode. 836 | * 837 | * @return uint8_t The key switch mode: 838 | * - 0: Off (button switching mode disabled) 839 | * - 1: Press and hold for 5 seconds to switch modes while in running mode 840 | * Other values may indicate different configurations depending on the 841 | * specific implementation of the device. 842 | * 843 | * @note The function reads 1 byte of data starting from the register 844 | * (UnitRollerI2C_KEY_SWTICH_MODE_REG). Ensure that I2C communication 845 | * has been properly initialized before calling this function. 846 | */ 847 | uint8_t getKeySwitchMode(void); 848 | 849 | /** 850 | * @brief Retrieves the output status of the motor from the UnitRollerI2C device. 851 | * 852 | * This function reads a single byte representing the current output 853 | * status of the motor. The retrieved status indicates whether the motor 854 | * is powered on or off. 855 | * 856 | * @return uint8_t The output status: 857 | * - 0: Motor off 858 | * - 1: Motor on 859 | * Other values may represent different statuses depending on the 860 | * specific implementation of the device. 861 | * 862 | * @note The function reads 1 byte of data starting from the register 863 | * (UnitRollerI2C_OUTPUT_REG). Ensure that I2C communication 864 | * has been properly initialized before calling this function. 865 | */ 866 | uint8_t getOutputStatus(void); 867 | 868 | /** 869 | * @brief Retrieves the current operating mode of the motor from the UnitRollerI2C device. 870 | * 871 | * This function reads a single byte representing the current mode in which 872 | * the motor is operating. The retrieved mode can be used to understand 873 | * how the motor is configured for operation. 874 | * 875 | * @return uint8_t The motor mode: 876 | * - 1: Speed Mode 877 | * - 2: Position Mode 878 | * - 3: Current Mode 879 | * - 4: Encoder Mode 880 | * Other values may represent different modes depending on the 881 | * specific implementation of the device. 882 | * 883 | * @note The function reads 1 byte of data starting from the register 884 | * (UnitRollerI2C_MODE_REG). Ensure that I2C communication 885 | * has been properly initialized before calling this function. 886 | */ 887 | uint8_t getMotorMode(void); 888 | 889 | /** 890 | * @brief Retrieves the ID of the motor from the UnitRollerI2C device. 891 | * 892 | * This function reads a single byte representing the unique identifier 893 | * of the motor. The retrieved ID can be used for identification purposes, 894 | * especially in systems with multiple motors. 895 | * 896 | * @return uint8_t The motor ID, which is a unique identifier for the motor. 897 | * The specific value will depend on the motor configuration and 898 | * assignment. 899 | * 900 | * @note The function reads 1 byte of data starting from the register 901 | * (UnitRollerI2C_ID_REG). Ensure that I2C communication 902 | * has been properly initialized before calling this function. 903 | */ 904 | uint8_t getMotorID(void); 905 | 906 | /** 907 | * @brief Retrieves the baud rate setting (BPS) from the UnitRollerI2C device. 908 | * 909 | * This function reads a single byte representing the current baud rate 910 | * configuration of the communication interface. The retrieved value indicates 911 | * the supported baud rates for communication. 912 | * 913 | * @return uint8_t The baud rate setting: 914 | * - 0: 115200 bps 915 | * - 1: 19200 bps 916 | * - 2: 9600 bps 917 | * Other values may represent different configurations based on the 918 | * specific implementation of the device. 919 | * 920 | * @note The function reads 1 byte of data starting from the register 921 | * (UnitRollerI2C_BPS_REG). Ensure that I2C communication 922 | * has been properly initialized before calling this function. 923 | */ 924 | uint8_t getBPS(void); 925 | 926 | /** 927 | * @brief Retrieves the brightness level of the RGB output from the UnitRollerI2C device. 928 | * 929 | * This function reads a single byte representing the current brightness setting 930 | * of the RGB LED. The retrieved value can be used to determine the intensity 931 | * of the RGB output. 932 | * 933 | * @return uint8_t The RGB brightness level, typically represented on a scale 934 | * (e.g., 0-100) where: 935 | * - 0: Minimum brightness (off) 936 | * - 100: Maximum brightness (fully on) 937 | * Other values may represent varying levels of brightness, depending 938 | * on the device configuration. 939 | * 940 | * @note The function reads 1 byte of data starting from the register 941 | * (UnitRollerI2C_RGB_BRIGHTNESS_REG). Ensure that I2C communication 942 | * has been properly initialized before calling this function. 943 | */ 944 | uint8_t getRGBBrightness(void); 945 | 946 | /** 947 | * @brief Retrieves the current RGB mode from the UnitRollerI2C device. 948 | * 949 | * This function reads a single byte representing the current mode of 950 | * the RGB output. The retrieved value indicates whether the RGB settings 951 | * are using the system default or user-defined configurations. 952 | * 953 | * @return uint8_t The RGB mode: 954 | * - 0: System-default mode 955 | * - 1: User-defined mode 956 | * Other values may represent different modes depending on the 957 | * specific implementation of the device. 958 | * 959 | * @note The function reads 1 byte of data starting from the register 960 | * (UnitRollerI2C_RGB_REG + 3). Ensure that I2C communication 961 | * has been properly initialized before calling this function. 962 | */ 963 | uint8_t getRGBMode(void); 964 | 965 | /** 966 | * @brief Retrieves the firmware version from the UnitRollerI2C device. 967 | * 968 | * This function sends a request to the device to read the current firmware 969 | * version, which can be useful for debugging and ensuring compatibility 970 | * with software features. 971 | * 972 | * @return uint8_t The firmware version as a single byte. The interpretation 973 | * of this value will depend on the specific firmware versioning 974 | * scheme used by the device manufacturer. 975 | * 976 | * @note The function initiates an I2C transmission to the specified address 977 | * (_addr) and reads the firmware version from the register 978 | * (FIRMWARE_VERSION_REG). Ensure that I2C communication has been 979 | * properly initialized before calling this function. 980 | */ 981 | uint8_t getFirmwareVersion(void); 982 | 983 | /** 984 | * @brief Retrieves the I2C address from the UnitRollerI2C device. 985 | * 986 | * This function sends a request to read the current I2C address 987 | * configuration of the device. The retrieved value can be useful for 988 | * understanding the communication setup, especially in multi-device 989 | * environments. 990 | * 991 | * @return uint8_t The I2C address of the device as configured. This value 992 | * indicates the address used for I2C communication. 993 | * 994 | * @note The function initiates an I2C transmission to the specified address 995 | * (_addr) and reads the I2C address from the register 996 | * (I2C_ADDRESS_REG). Ensure that I2C communication has been properly 997 | * initialized before calling this function. 998 | */ 999 | uint8_t getI2CAddress(void); 1000 | 1001 | private: 1002 | uint8_t _addr; 1003 | TwoWire *_wire; 1004 | uint8_t _scl; 1005 | uint8_t _sda; 1006 | uint32_t _speed; 1007 | 1008 | /** 1009 | * @brief Writes a sequence of bytes to a specific register on a device. 1010 | * 1011 | * This function begins a transmission to the specified I2C address, writes the register 1012 | * address followed by a series of bytes from the provided buffer, and then ends the transmission. 1013 | * 1014 | * @param addr The I2C address of the device to communicate with. 1015 | * @param reg The register address within the device where data will be written. 1016 | * @param buffer A pointer to the array of bytes to be written to the device. 1017 | * @param length The number of bytes to write from the buffer. 1018 | * 1019 | * @note If the transmission fails, you may not receive a proper acknowledgment 1020 | * from the device. Check the return status of endTransmission() if needed. 1021 | */ 1022 | void writeBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, uint8_t length); 1023 | 1024 | /** 1025 | * @brief Reads a sequence of bytes from a specific register on a device. 1026 | * 1027 | * This function begins a transmission to the specified I2C address, writes the register 1028 | * address from which data will be read, and then requests the specified number of bytes 1029 | * from that device into the provided buffer. 1030 | * 1031 | * @param addr The I2C address of the device to communicate with. 1032 | * @param reg The register address within the device from which data will be read. 1033 | * @param buffer A pointer to the array where the read bytes will be stored. 1034 | * @param length The number of bytes to read from the device. 1035 | * 1036 | * @note The function uses repeated start condition during transmission by passing 1037 | * 'false' to endTransmission() to allow for reading without releasing the bus. 1038 | * Ensure that the device at the given address is ready to provide the requested data. 1039 | */ 1040 | void readBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, uint8_t length); 1041 | 1042 | /** 1043 | * @brief Converts a float value to an array of bytes. 1044 | * 1045 | * This function takes a floating-point number and converts it into a byte array representation. 1046 | * It uses a union to reinterpret the float as an array of 4 bytes (assuming a standard 32-bit float). 1047 | * 1048 | * @param s The floating-point value to be converted. 1049 | * @param d A pointer to the destination array where the byte representation will be stored. 1050 | * 1051 | * @note The caller is responsible for ensuring that the destination array has enough 1052 | * space (at least 4 bytes) to store the byte representation of the float. 1053 | */ 1054 | float bytesToFloat(uint8_t *s); 1055 | 1056 | /** 1057 | * @brief Converts an array of bytes to a floating-point value. 1058 | * 1059 | * This function takes an array of 4 bytes (assuming a standard 32-bit float) 1060 | * and converts it into a floating-point number. It uses a union to reinterpret 1061 | * the byte array as a float. 1062 | * 1063 | * @param s A pointer to the array of bytes representing the float value. 1064 | * 1065 | * @return The floating-point value represented by the input byte array. 1066 | * 1067 | * @note The caller must ensure that the input array contains at least 4 bytes. 1068 | */ 1069 | void floatToBytes(float s, uint8_t *d); 1070 | }; 1071 | 1072 | #endif 1073 | --------------------------------------------------------------------------------