Skip to content

File RBCXMotor.cpp

File List > demo-projets > esp > RBCXMotor.cpp

Go to the documentation of this file.

#include "RBCXMotor.h"
#include "RBCXManager.h"

#include "rbcx.pb.h"

static constexpr uint32_t minVersionPositional = 0x010100;

namespace rb {

Motor::Motor() {
    m_power = 0;
    m_speed = 0;
    m_position = 0;
    m_mode = MotorMode_POWER;
    m_lastReq = CoprocReq_MotorReq_init_zero;
    m_pwm_max_percent = 100;
}

void Motor::requestInfo(callback_t cb) {
    Manager::get().coprocFwVersionAssert(
        minVersionPositional, "positional motor control (drive)");

    std::lock_guard<std::mutex> l(m_mutex);

    if (m_infoCbs.empty()) {
        Manager::get().sendToCoproc(CoprocReq {
            .which_payload = CoprocReq_motorReq_tag,
            .payload = {
                .motorReq = CoprocReq_MotorReq {
                    .motorIndex = (uint32_t)m_id,
                    .which_motorCmd = CoprocReq_MotorReq_getState_tag,
                },
            },
        });
    }

    if (cb) {
        m_infoCbs.emplace_back(std::move(cb));
    }
}

void Motor::power(int16_t value) {
    sendMotorReq(CoprocReq_MotorReq {
        .motorIndex = (uint32_t)m_id,
        .which_motorCmd = CoprocReq_MotorReq_setPower_tag,
        .motorCmd = {
            .setPower = scale(value),
        },
    });
}

void Motor::speed(int16_t ticksPerSecond) {
    sendMotorReq(CoprocReq_MotorReq {
        .motorIndex = (uint32_t)m_id,
        .which_motorCmd = CoprocReq_MotorReq_setVelocity_tag,
        .motorCmd = {
            .setVelocity = scale(ticksPerSecond),
        },
    });
}

void Motor::brake(uint16_t value) {
    sendMotorReq(CoprocReq_MotorReq {
        .motorIndex = (uint32_t)m_id,
        .which_motorCmd = CoprocReq_MotorReq_setBrake_tag,
        .motorCmd = {
            .setBrake = value,
        },
    });
}

void Motor::pwmMaxPercent(int8_t percent) {
    m_pwm_max_percent = std::min(int8_t(100), std::max(int8_t(0), percent));
}

void Motor::driveToValue(int32_t positionAbsolute, int16_t speedTicksPerSecond,
    callback_t callback) {
    Manager::get().coprocFwVersionAssert(
        minVersionPositional, "positional motor control (drive)");

    sendPositionReq(false,
        CoprocReq_MotorReq_SetPosition {
            .targetPosition = positionAbsolute,
            .runningVelocity = scale(speedTicksPerSecond),
        },
        std::move(callback));
}

void Motor::drive(int32_t positionRelative, int16_t speedTicksPerSecond,
    callback_t callback) {
    Manager::get().coprocFwVersionAssert(
        minVersionPositional, "positional motor control (drive)");
    sendPositionReq(true,
        CoprocReq_MotorReq_SetPosition {
            .targetPosition = positionRelative,
            .runningVelocity = scale(speedTicksPerSecond),
        },
        std::move(callback));
}

void Motor::setConfig(const MotorConfig& conf) {
    Manager::get().coprocFwVersionAssert(
        minVersionPositional, "positional motor control (drive)");

    const CoprocReq coprocReq = {
        .which_payload = CoprocReq_motorReq_tag,
        .payload = {
            .motorReq = CoprocReq_MotorReq {
                .motorIndex = (uint32_t)m_id,
                .which_motorCmd = CoprocReq_MotorReq_setConfig_tag,
                .motorCmd = {
                    .setConfig = conf,
                },
            },
        },
    };

    Manager::get().sendToCoproc(coprocReq);
}

void Motor::setCurrentPosition(int32_t pos) {
    Manager::get().coprocFwVersionAssert(
        minVersionPositional, "positional motor control (drive)");

    std::lock_guard<std::mutex> l(m_mutex);

    m_position = pos;

    const CoprocReq coprocReq = {
        .which_payload = CoprocReq_motorReq_tag,
        .payload = {
            .motorReq = CoprocReq_MotorReq {
                .motorIndex = (uint32_t)m_id,
                .which_motorCmd = CoprocReq_MotorReq_homePosition_tag,
                .motorCmd = {
                    .homePosition = pos,
                },
            },
        },
    };

    Manager::get().sendToCoproc(coprocReq);
}

int16_t Motor::scale(int16_t val) {
    return int32_t(val) * m_pwm_max_percent / 100;
}

void Motor::sendPositionReq(bool additive,
    const CoprocReq_MotorReq_SetPosition& req, callback_t&& callback) {

    {
        std::lock_guard<std::mutex> l(m_mutex);

        Manager::get().resetMotorsFailSafe();
        memset(&m_lastReq, 0, sizeof(CoprocReq_MotorReq));

        m_mode = MotorMode_POSITION;
        m_speed = req.runningVelocity;
        m_positionCb = callback;

        const pb_size_t tag = additive ? CoprocReq_MotorReq_addPosition_tag
                                       : CoprocReq_MotorReq_setPosition_tag;
        const CoprocReq coprocReq = {
            .which_payload = CoprocReq_motorReq_tag,
            .payload = {
                .motorReq = CoprocReq_MotorReq {
                    .motorIndex = (uint32_t)m_id,
                    .which_motorCmd = tag,
                    .motorCmd = {
                        .setPosition = req,
                    },
                },
            },
        };
        Manager::get().sendToCoproc(coprocReq);
    }
}

void Motor::sendMotorReq(const CoprocReq_MotorReq& req) {
    {
        std::lock_guard<std::mutex> l(m_mutex);

        Manager::get().resetMotorsFailSafe();

        if (memcmp(&m_lastReq, &req, sizeof(CoprocReq_MotorReq)) == 0)
            return;
        memcpy(&m_lastReq, &req, sizeof(CoprocReq_MotorReq));

        switch (req.which_motorCmd) {
        case CoprocReq_MotorReq_setPower_tag:
            m_mode = MotorMode_POWER;
            break;
        case CoprocReq_MotorReq_setBrake_tag:
            m_mode = MotorMode_BRAKE;
            break;
        case CoprocReq_MotorReq_setVelocity_tag:
            m_mode = MotorMode_VELOCITY;
            break;
        default:
            abort();
        }

        if (m_mode != MotorMode_POSITION && m_positionCb) {
            m_positionCb = nullptr;
        }

        const CoprocReq coprocReq = {
            .which_payload = CoprocReq_motorReq_tag,
            .payload = {
                .motorReq = req,
            },
        };
        Manager::get().sendToCoproc(coprocReq);
    }
}

void Motor::onMotorStat(const CoprocStat_MotorStat& msg) {
    callback_t positionCb;
    std::vector<callback_t> infoCbs;

    {
        std::lock_guard<std::mutex> l(m_mutex);
        if (m_mode == MotorMode_POSITION && msg.mode == MotorMode_POSITION_IDLE
            && m_positionCb) {
            m_positionCb.swap(positionCb);
        }

        if (!m_infoCbs.empty()) {
            m_infoCbs.swap(infoCbs);
        }

        m_mode = msg.mode;
        m_position = msg.position;
        m_power = msg.power;
        m_speed = msg.velocity;
    }

    if (positionCb) {
        positionCb(*this);
    }

    for (const auto& cb : infoCbs) {
        cb(*this);
    }
}

}; // namespace rb