Program Listing for File dji_motor.hpp

Return to documentation for file (src/tap/motor/dji_motor.hpp)

/*
 * Copyright (c) 2020-2021 Advanced Robotics at the University of Washington <robomstr@uw.edu>
 *
 * This file is part of Taproot.
 *
 * Taproot is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Taproot is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Taproot.  If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef TAPROOT_DJI_MOTOR_HPP_
#define TAPROOT_DJI_MOTOR_HPP_

#include <string>

#include "tap/architecture/timeout.hpp"
#include "tap/communication/can/can_rx_listener.hpp"

#include "modm/math/geometry/angle.hpp"

#include "motor_interface.hpp"

namespace tap::motor
{
enum MotorId : uint32_t
{
    MOTOR1 = 0X201,
    MOTOR2 = 0x202,
    MOTOR3 = 0x203,
    MOTOR4 = 0x204,
    MOTOR5 = 0x205,
    MOTOR6 = 0x206,
    MOTOR7 = 0x207,
    MOTOR8 = 0x208,
};

class DjiMotor : public can::CanRxListener, public MotorInterface
{
public:
    // 0 - 8191 for dji motors
    static constexpr uint16_t ENC_RESOLUTION = 8192;

    // Maximum values for following motors
    // Controller for the M2006, in mA output
    static constexpr uint16_t MAX_OUTPUT_C610 = 10000;
    // Controller for the M3508, in mA output (Mapped to a 20A range though, not 1:1)
    static constexpr uint16_t MAX_OUTPUT_C620 = 16384;
    // Controller for the M3510, in mA output (Not known if mapped to 20A range)
    static constexpr uint16_t MAX_OUTPUT_820R = 32767;

    // Output is in mV
    static constexpr uint16_t MAX_OUTPUT_GM6020 = 25000;
    // Output is in mV
    static constexpr uint16_t MAX_OUTPUT_GM3510 = 29000;

    // Internal gear ratio of the following motors
    static constexpr float GEAR_RATIO_M3508 = 3591.0f / 187.0f;
    static constexpr float GEAR_RATIO_M3510_L1 = 3.7f / 1.0f;
    static constexpr float GEAR_RATIO_M3510_L2 = 5.2f / 1.0f;
    static constexpr float GEAR_RATIO_M3510_L3 = 19.0f / 1.0f;
    static constexpr float GEAR_RATIO_M3510_L4 = 27.0f / 1.0f;
    static constexpr float GEAR_RATIO_M2006 = 36.0f / 1.0f;

    DjiMotor(
        Drivers* drivers,
        MotorId desMotorIdentifier,
        tap::can::CanBus motorCanBus,
        bool isInverted,
        const char* name,
        uint16_t encoderWrapped = ENC_RESOLUTION / 2,
        int64_t encoderRevolutions = 0,
        bool currentControl = false);

    mockable ~DjiMotor();

    void initialize() override;

    float getPositionUnwrapped() const override;

    float getPositionWrapped() const override;

    int64_t getEncoderUnwrapped() const override;

    uint16_t getEncoderWrapped() const override;

    void resetEncoderValue() override;

    DISALLOW_COPY_AND_ASSIGN(DjiMotor)


    void processMessage(const modm::can::Message& message) override;

    void setDesiredOutput(int32_t desiredOutput) override;

    bool isMotorOnline() const override;

    mockable void serializeCanSendData(modm::can::Message* txMessage) const;

    int16_t getOutputDesired() const override;

    mockable uint32_t getMotorIdentifier() const;

    int8_t getTemperature() const override;

    int16_t getTorque() const override;

    int16_t getShaftRPM() const override;

    mockable bool isMotorInverted() const;

    mockable tap::can::CanBus getCanBus() const;

    mockable const char* getName() const;

    mockable bool isInCurrentControl() const;

    template <typename T>
    static void assertEncoderType()
    {
        constexpr bool good_type =
            std::is_same<typename std::decay<T>::type, std::int64_t>::value ||
            std::is_same<typename std::decay<T>::type, std::uint16_t>::value;
        static_assert(good_type, "x is not of the correct type");
    }

    template <typename T>
    static T degreesToEncoder(float angle)
    {
        assertEncoderType<T>();
        return static_cast<T>((ENC_RESOLUTION * angle) / 360);
    }

    template <typename T>
    static float encoderToDegrees(T encoder)
    {
        assertEncoderType<T>();
        return (360.0f * static_cast<float>(encoder)) / ENC_RESOLUTION;
    }

private:
    // wait time before the motor is considered disconnected, in milliseconds
    static const uint32_t MOTOR_DISCONNECT_TIME = 100;

    const char* motorName;

    void updateEncoderValue(uint16_t newEncWrapped);

    Drivers* drivers;

    uint32_t motorIdentifier;

    tap::can::CanBus motorCanBus;

    int16_t desiredOutput;

    int16_t shaftRPM;

    int8_t temperature;

    int16_t torque;

    bool motorInverted;

    uint16_t encoderWrapped;

    int64_t encoderRevolutions;

    uint16_t encoderHomePosition;

    tap::arch::MilliTimeout motorDisconnectTimeout;

    bool currentControl;
};

}  // namespace tap::motor

#endif  // TAPROOT_DJI_MOTOR_HPP_