STM32无刷电机全套开发资料(源码、原理图、PCB工程及说明文档)

目录

1、原理图、PCB、BOOM表

2、设计描述 

2.1 前言

2.2 设计电路规范

 3、代码

4、资料清单

资料下载地址:STM32无刷电机全套开发资料(源码、原理图、PCB工程及说明文档)

1、原理图、PCB、BOOM表

 

2、设计描述 

2.1 前言

        经过一个星期的画PCB,今天终于化了,整体看上去还比较满意,具体的性能基本满足需求

2.2 设计电路规范

 1、线间距。

      这里应该遵循3W规则,所谓3W就是为了减少线间串扰,应保证线间距足够大,当线中心不少于3倍线宽,则可 保持70%的电场不互相干扰。如要达到98%的电场不互相干扰,可使用10W的间距。——这是查阅华为PCB布线规则所得。

 

     2、电源线过细。

      这里我查阅了华为PCB教程得到了下面一个表格。这里线宽跟所能承受最大电流的关系表

  3、电源环路。(用图说明)

 3、代码

/*
    This file is part of AutoQuad ESC32.

    AutoQuad ESC32 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.

    AutoQuad ESC32 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 AutoQuad ESC32.  If not, see

    Copyright © 2011, 2012, 2013  Bill Nesbitt
*/

#include "run.h"
#include "main.h"
#include "timer.h"
#include "adc.h"
#include "fet.h"
#include "pwm.h"
#include "cli.h"
#include "binary.h"
#include "config.h"
#include "misc.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_pwr.h"
#include "stm32f10x_iwdg.h"
#include "stm32f10x_dbgmcu.h"
#include <math.h>

uint32_t runMilis;   //systick中断中自加.没有什么控制用途
static uint32_t oldIdleCounter;  //上次main函数中,死循环次数.
float idlePercent;   //空闲时间百分比(在main循环里,什么事情也不做.main死循环运行的时间)
float avgAmps, maxAmps; //平均电流, 最大电流
float avgVolts;      //当前ADC采集转换后的电池电压(也就是12v)

float rpm;           //当前转速(1分钟多少转) 测量值 在runRpm函数中计算出来.在runThrotLim中还要继续使用.
float targetRpm;     //目标转速 设定值(只在闭环 或 闭环推力模式下使用此变量)

static float rpmI;
static float runRPMFactor;
static float maxCurrentSQRT;  //最大电流 平方根 后
uint8_t disarmReason;//此变量没啥作用.只用于给上位机显示当前的 调试代码(或者说停止电机的原因)
uint8_t commandMode; //串口通讯的模式, cli是ascii模式, binary是二进制通讯模式
static uint8_t runArmCount;
volatile uint8_t runMode;//运行模式 (开环模式, RPM模式, 推力模式, 伺服模式)
static float maxThrust;

//执行看门狗喂狗
void runFeedIWDG(void) {
#ifdef RUN_ENABLE_IWDG
    IWDG_ReloadCounter();
#endif
}

// setup the hardware independent watchdog
// 初始化并开启独立看门狗
uint16_t runIWDGInit(int ms)
{
#ifndef RUN_ENABLE_IWDG
    return 0;
#else
        uint16_t prevReloadVal;
        int reloadVal;

        IWDG_ReloadCounter();//喂狗

        DBGMCU_Config(DBGMCU_IWDG_STOP, ENABLE);//当在jtag调试的时候.停止看门狗

        // IWDG timeout equal to 10 ms (the timeout may varies due to LSI frequency dispersion)
        // Enable write access to IWDG_PR and IWDG_RLR registers
        IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//允许访问IWDG_PR和IWDG_RLR寄存器

        // IWDG counter clock: LSI/4
        IWDG_SetPrescaler(IWDG_Prescaler_4);

        // Set counter reload value to obtain 10ms IWDG TimeOut.
        //  Counter Reload Value        = 10ms/IWDG counter clock period
        //                                = 10ms / (RUN_LSI_FREQ/4)
        //                                = 0.01s / (RUN_LSI_FREQ/4)
        //                                = RUN_LSI_FREQ/(4 * 100)
        //                                = RUN_LSI_FREQ/400
        reloadVal = RUN_LSI_FREQ*ms/4000;

        if (reloadVal < 1)
                reloadVal = 1;
        else if (reloadVal > 0xfff)
                reloadVal = 0xfff;

        prevReloadVal = IWDG->RLR;

        IWDG_SetReload(reloadVal);

        // Reload IWDG counter
        IWDG_ReloadCounter();

        // Enable IWDG (the LSI oscillator will be enabled by hardware)
        IWDG_Enable();

        return (prevReloadVal*4000/RUN_LSI_FREQ);
#endif
}

//esc32 非正常停止运行 进入初始化
void runDisarm(int reason) {
        fetSetDutyCycle(0);  //fet占空比设置为0

        timerCancelAlarm2();
        state = ESC_STATE_DISARMED;
        pwmIsrAllOn();

        digitalHi(statusLed);   // turn off
        digitalLo(errorLed);    // turn on
        disarmReason = reason;  // 设置停机原因.给上位机查看状态使用
}

//手动运行
void runArm(void) {
        int i;

        fetSetDutyCycle(0);
        timerCancelAlarm2();
        digitalHi(errorLed);
        digitalLo(statusLed);   // turn on

        if (runMode == SERVO_MODE) {
                state = ESC_STATE_RUNNING;
        }
        else {
                state = ESC_STATE_STOPPED;
                if (inputMode == ESC_INPUT_UART)
                        runMode = OPEN_LOOP;
                fetSetBraking(0);
        }

        // extra beeps signifying run mode
        for (i = 0; i < runMode + 1; i++) {
                fetBeep(250, 600);
                timerDelay(10000);
        }

//        fetBeep(150, 800);
}

//电机开始运行
void runStart(void) {
        // reset integral bevore new motor startup
        runRpmPIDReset();//先复位I值

        if ((p[START_ALIGN_TIME] == 0) && (p[START_STEPS_NUM] == 0)) {
                state = ESC_STATE_STARTING;  //设置为准备启动状态
                fetStartCommutation(0);//换向启动
        }
        else {
                motorStartSeqInit();//普通启动
        }
}

//电机停止运行
void runStop(void) {
    runMode = OPEN_LOOP;
    fetSetDutyCycle(0);
}

//设置运行的占空比 duty = 0~100
uint8_t runDuty(float duty) {
    uint8_t ret = 0;

    if (duty >= 0.0f || duty <= 100.0f) {
                runMode = OPEN_LOOP;
                fetSetBraking(0);
                fetSetDutyCycle((uint16_t)(fetPeriod*duty*0.01f));//最大周期 * 占空比(0~100) / 100
                ret = 1;
    }

    return ret;
}

//pwm.c中断中调用  或  串口命令输入调用
void runNewInput(uint16_t setpoint) {
        static uint16_t lastPwm;
        static float filteredSetpoint = 0;

        // Lowpass Input if configured
        // TODO: Make lowpass independent from pwm update rate
        if (p[PWM_LOWPASS]) {
                filteredSetpoint = (p[PWM_LOWPASS] * filteredSetpoint + (float)setpoint) / (1.0f + p[PWM_LOWPASS]);
                setpoint = filteredSetpoint;
        }

        if (state == ESC_STATE_RUNNING && setpoint != lastPwm)
        {
                if (runMode == OPEN_LOOP)
                {
                        //开环模式
                        fetSetDutyCycle(fetPeriod * (int32_t)(setpoint-pwmLoValue) / (int32_t)(pwmHiValue - pwmLoValue));
                }
                else if (runMode == CLOSED_LOOP_RPM)
                {
                        //闭环转速模式
                        float target = p[PWM_RPM_SCALE] * (setpoint-pwmLoValue) / (pwmHiValue - pwmLoValue);

                        // limit to configured maximum
                        targetRpm = (target > p[PWM_RPM_SCALE]) ? p[PWM_RPM_SCALE] : target;
                }
                // THRUST Mode
                else if (runMode == CLOSED_LOOP_THRUST)
                {
                        //闭环推力模式
                        float targetThrust;  // desired trust
                        float target;        // target(rpm)

                        // Calculate targetThrust based on input and MAX_THRUST
                        targetThrust = maxThrust * (setpoint-pwmLoValue) / (pwmHiValue - pwmLoValue);

                        // Workaraound: Negative targetThrust will screw up sqrtf() and create MAX_RPM on throttle min. Dangerous!
                        if (targetThrust > 0.0f) {
                                // Calculate target(rpm) based on targetThrust
                                target = ((sqrtf(p[THR1TERM] * p[THR1TERM] + 4.0f * p[THR2TERM] * targetThrust) - p[THR1TERM] ) / ( 2.0f * p[THR2TERM] ));
                        }
                        // targetThrust is negative (pwm_in < pwmLoValue)
                        else {
                                target = 0.0f;
                        }

                        // upper limit for targetRpm is configured maximum PWM_RPM_SCALE (which is MAX_RPM)
                        targetRpm = (target > p[PWM_RPM_SCALE]) ? p[PWM_RPM_SCALE] : target;
                }
                else if (runMode == SERVO_MODE)
                {
                        //伺服模式下
                        fetSetAngleFromPwm(setpoint);
                }

                lastPwm = setpoint;
        }
        else if ((state == ESC_STATE_NOCOMM || state == ESC_STATE_STARTING) && setpoint <= pwmLoValue)
        {
                fetSetDutyCycle(0);
                state = ESC_STATE_RUNNING;
        }
        else if (state == ESC_STATE_DISARMED && setpoint > pwmMinValue && setpoint <= pwmLoValue)
        {
                runArmCount++;
                if (runArmCount > RUN_ARM_COUNT)
                        runArm();
        }
        else {
                runArmCount = 0;
        }

        if (state == ESC_STATE_STOPPED && setpoint >= pwmMinStart) {
                //电机开始运行
                runStart();
        }
}

//电调运行看门狗. 主要是判断电调的当前一些状态.做出停机等处理
static void runWatchDog(void)
{
        register uint32_t t, d, p;

        //__asm volatile ("cpsid i");
        //CPSID_I();
        __disable_irq();
        t = timerMicros;      //当前的系统tick时间
        d = detectedCrossing;
        p = pwmValidMicros;   //在PWM输入模式下.把timerMicros的时间赋值给此变量
        //__asm volatile ("cpsie i");
        //CPSIE_I();
        __enable_irq();

        if (state == ESC_STATE_STARTING && fetGoodDetects > fetStartDetects) //这里要检测到fetStartDetects好的检测,才允许切换电机状态
        {
                //是启动状态.切换到 运行状态
                state = ESC_STATE_RUNNING;
                digitalHi(statusLed);   // turn off
        }
        else if (state >= ESC_STATE_STOPPED)
        {
                //运行模式状态下.会一直在这里检测状态.如果状态不对出错.会调用runDisarm函数停止

                // running or starting
                d = (t >= d) ? (t - d) : (TIMER_MASK - d + t);

                // timeout if PWM signal disappears
                if (inputMode == ESC_INPUT_PWM)
                {
                        //PWM模式 判断PWM输入是否超时
                        p = (t >= p) ? (t - p) : (TIMER_MASK - p + t);

                        if (p > PWM_TIMEOUT)
                                runDisarm(REASON_PWM_TIMEOUT);//pwm输入超时
                }

                if (state >= ESC_STATE_STARTING && d > ADC_CROSSING_TIMEOUT)
                {
                        if (fetDutyCycle > 0) {
                                runDisarm(REASON_CROSSING_TIMEOUT);//错误停止
                        }
                        else
                        {
                                runArm();//手动运行起来
                                pwmIsrRunOn();//PWM开启输入比较
                        }
                }
                else if (state >= ESC_STATE_STARTING && fetBadDetects > fetDisarmDetects)  //运行状态中  检测到错误的个数后.进入这个判断
                {
                        //在运行过程中,出现错误.停止运行
                        if (fetDutyCycle > 0)
                                runDisarm(REASON_BAD_DETECTS);//错误停止
                }
                else if (state == ESC_STATE_STOPPED)
                {
                        //停止模式
                        adcAmpsOffset = adcAvgAmps;        // record current amperage offset
                }
        }
        else if (state == ESC_STATE_DISARMED && !(runMilis % 100))
        {
                //停止模式下
                adcAmpsOffset = adcAvgAmps;        // record current amperage offset
                digitalTogg(errorLed);
        }
}

void runRpmPIDReset(void) {
    rpmI = 0.0f;
}

//这个应该是计算PID
//rpm:测量的转速值
//target:目标的转速值
static int32_t runRpmPID(float rpm, float target) {
        float error;
        float ff, rpmP;
        float iTerm = rpmI;
        float output;

        // feed forward
        ff = ((target*target* p[FF1TERM] + target*p[FF2TERM]) / avgVolts) * fetPeriod;

        error = (target - rpm);//计算出偏差

        if (error > 1000.0f)
                error = 1000.0f;

        if (error > 0.0f) {
                rpmP = error * p[PTERM];  //P
                rpmI += error * p[ITERM]; //I
        }
        else {
                rpmP =  error * p[PTERM] * p[PNFAC];
                rpmI += error * p[ITERM] * p[INFAC];
        }

        if (fetBrakingEnabled)
        {
                //开启了制动模式
                if (rpm < 300.0f) {
                        fetSetBraking(0);
                }
                else if (error <= -100.0f) {
                        fetSetBraking(1);
                }
                else if (fetBraking && error > -25.0f){
                        fetSetBraking(0);
                }
        }

        output = ff + (rpmP + rpmI) * (1.0f / 1500.0f) * fetPeriod;

        // don't allow integral to continue to rise if at max output
        if (output >= fetPeriod)
                rpmI = iTerm;

        return output;
}

//计算出电机转速,根据当前转速计算出PID输出值,设置占空比
static uint8_t runRpm(void)
{
    if (state > ESC_STATE_STARTING)
        {
                //电机处于运行状态 计算出当前转速rpm
                //        rpm = rpm * 0.90f + (runRPMFactor / (float)crossingPeriod) * 0.10f;
                //        rpm -= (rpm - (runRPMFactor / (float)crossingPeriod)) * 0.25f;
                //        rpm = (rpm + (runRPMFactor / (float)crossingPeriod)) * 0.5f;
                //        rpm = (rpm + ((32768.0f * runRPMFactor) / (float)adcCrossingPeriod)) * 0.5f; // increased resolution, fixed filter here
                rpm = p[RPM_MEAS_LP] * rpm + ((32768.0f * runRPMFactor) / (float)adcCrossingPeriod) * (1.0f - p[RPM_MEAS_LP]); // increased resolution, variable filter here

                // run closed loop control
                if (runMode == CLOSED_LOOP_RPM)
                {
                        //运行在闭环模式下
                        fetSetDutyCycle(runRpmPID(rpm, targetRpm));
                        return 1;
                }
                // run closed loop control also for THRUST mode
                else if (runMode == CLOSED_LOOP_THRUST)
                {
                        //运行在闭环推力模式
                        fetSetDutyCycle(runRpmPID(rpm, targetRpm));
                        return 1;
                }
                else
                {
                        return 0;
                }
        }
        else
        {
                //电机在停止状态下
                rpm = 0.0f;
                return 0;
    }
}

static void runSetupPVD(void) {
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // Configure EXTI Line16(PVD Output) to generate an interrupt on rising and falling edges
    EXTI_ClearITPendingBit(EXTI_Line16);
    EXTI_InitStructure.EXTI_Line = EXTI_Line16;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    // Enable the PVD Interrupt
    NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // Configure the PVD Level to 2.2V
    PWR_PVDLevelConfig(PWR_PVDLevel_2V2);//配置pvd电压等级.当电压小于2.2V的时候产生中断

    // Enable the PVD Output
    PWR_PVDCmd(ENABLE);
}

void runInit(void) {
    runSetupPVD();
    runSetConstants();
    runMode = p[STARTUP_MODE];//启动 运行模式

        //系统tickcount时钟
    SysTick_Config(SystemCoreClock / 1000); // 1ms
    NVIC_SetPriority(SysTick_IRQn, 2);            // lower priority

    // setup hardware watchdog
    runIWDGInit(20);
}

#define RUN_CURRENT_ITERM        1.0f
#define RUN_CURRENT_PTERM        10.0f
#define RUN_MAX_DUTY_INCREASE        1.0f

float currentIState;

//根据PID计算出PWM占空比的值
static int32_t runCurrentPID(int32_t duty) {
    float error;
    float pTerm, iTerm;

    error = avgAmps - p[MAX_CURRENT];

    currentIState += error;
    if (currentIState < 0.0f)
                currentIState = 0.0f;
    iTerm = currentIState * RUN_CURRENT_ITERM;

    pTerm = error * RUN_CURRENT_PTERM;
    if (pTerm < 0.0f)
                pTerm = 0.0f;

    duty = duty - iTerm - pTerm;

    if (duty < 0)
                duty = 0;

    return duty;
}

//计算得到实际的占空比fetActualDutyCycle
//参数duty:实际上就是fetDutyCycle传递进来的.想要运行的周期
static void runThrotLim(int32_t duty)
{
        float maxVolts; //最大的电压
        int32_t maxDuty;//最大的周期

        // only if a limit is set
        if (p[MAX_CURRENT] > 0.0f)
        {
                //如果实际的占空比和设置的占空比不一样.那么会实时改变CPU的PWM寄存器.

                // if current limiter is calibrated - best performance   使用电流限制器校准.性能最好
                if (p[CL1TERM] != 0.0f)
                {
                        maxVolts = p[CL1TERM] + p[CL2TERM]*rpm + p[CL3TERM]*p[MAX_CURRENT] + p[CL4TERM]*rpm*maxCurrentSQRT + p[CL5TERM]*maxCurrentSQRT;
                        maxDuty = maxVolts * (fetPeriod / avgVolts);

                        if (duty > maxDuty)
                                fetActualDutyCycle = maxDuty;
                        else
                                fetActualDutyCycle = duty;
                }
                // otherwise, use PID - less accurate, lower performance  使用PID来计算.不大准确.性能低
                else
                {
                        fetActualDutyCycle += fetPeriod * (RUN_MAX_DUTY_INCREASE * 0.01f);
                        if (fetActualDutyCycle > duty)
                                fetActualDutyCycle = duty;
                        fetActualDutyCycle = runCurrentPID(fetActualDutyCycle);//用PID来计算出当前要运行的占空比
                }
        }
        else {
                fetActualDutyCycle = duty;
        }

        //设置到CPU寄存器里.算出来的实际PWM占空比
        _fetSetDutyCycle(fetActualDutyCycle);
}

//系统tickcount中断
void SysTick_Handler(void) {
    // reload the hardware watchdog
    runFeedIWDG();


    avgVolts = adcAvgVolts * ADC_TO_VOLTS;                     //转换后的电池电压(一般是12V) = ADC采集电压原始值 * 电压算法
    avgAmps = (adcAvgAmps - adcAmpsOffset) * adcToAmps;        //平均电流 = (当前电流 - 停止时候的电流) * 转换公式
    maxAmps = (adcMaxAmps - adcAmpsOffset) * adcToAmps;        //最大电流 = (最大电流 - 停止时候的电流) * 转换公式


    if (runMode == SERVO_MODE)
        {
                //伺服模式
                fetUpdateServo();
    }
    else
        {
                runWatchDog();//检测电调的状态.做出相应的停机处理
                runRpm();     //计算RPM,计算PID,设置运行PWM占空比
                runThrotLim(fetDutyCycle);//计算得到实际PWM占空比.如果有偏差.那么在这里会实时改变PWM的占空比值
    }


        //计算空闲时间百分比 通过串口发送给上位机  没什么用途
    idlePercent = 100.0f * (idleCounter-oldIdleCounter) * minCycles / totalCycles;
//  空闲时间百分比 = 100 * (本次循环次数 - 上次循环次数) * 最小周期 / 总共周期
    oldIdleCounter = idleCounter;
    totalCycles = 0;


        //处理串口数据 和串口交互使用的
    if (commandMode == CLI_MODE)
                cliCheck();    //ascii模式
    else
                binaryCheck(); //二进制模式

    runMilis++;
}

//低电压中断
void PVD_IRQHandler(void) {
    // voltage dropping too low
    if (EXTI_GetITStatus(EXTI_Line16) != RESET) {
                // shut everything down
                runDisarm(REASON_LOW_VOLTAGE);

                // turn on both LEDs
                digitalLo(statusLed);
                digitalLo(errorLed);

                EXTI_ClearITPendingBit(EXTI_Line16);
    }
}

void runSetConstants(void) {
    int32_t startupMode = (int)p[STARTUP_MODE];
    float maxCurrent = p[MAX_CURRENT];

        //运行模式
    if (startupMode < 0 || startupMode >= NUM_RUN_MODES)
                startupMode = 0;

    if (maxCurrent > RUN_MAX_MAX_CURRENT)
                maxCurrent = RUN_MAX_MAX_CURRENT;
    else if (maxCurrent < RUN_MIN_MAX_CURRENT)
                maxCurrent = RUN_MIN_MAX_CURRENT;

    runRPMFactor = (1e6f * (float)TIMER_MULT * 120.0f) / (p[MOTOR_POLES] * 6.0f);
    maxCurrentSQRT = sqrtf(maxCurrent);

    p[MOTOR_POLES] = (int)p[MOTOR_POLES];
    p[STARTUP_MODE] = startupMode;
    p[MAX_CURRENT] = maxCurrent;

    // Calculate MAX_THRUST from PWM_RPM_SCALE (which is MAX_RPM) and THRxTERMs
    // Based on "thrust = rpm * a1 + rpm^2 * a2"
    maxThrust = p[PWM_RPM_SCALE] * p[THR1TERM] + p[PWM_RPM_SCALE] * p[PWM_RPM_SCALE] * p[THR2TERM];
}

4、资料清单

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/551485.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【微信小程序】分包

整个小程序所有分包大小不超过 20M&#xff08;开通虚拟支付后的小游戏不超过30M&#xff09; 单个分包/主包大小不能超过 2M在小程序启动时&#xff0c;默认会下载主包并启动主包内页面&#xff0c;当用户进入分包内某个页面时&#xff0c;客户端会把对应分包下载下来&#xf…

Windows版MySQL5.7解压直用(免安装-绿色-项目打包直接使用)

windows下mysql分类 MySQL分为 安装版和解压版 安装版: 安装方便&#xff0c;下一步------下一步就OK了&#xff0c;但重装系统更换环境又要重新来一遍&#xff0c;会特别麻烦解压版&#xff08;推荐&#xff09;&#xff1a; 这种方式&#xff08;项目打包特别方便&#xf…

网红泡泡机单片机方案开发定制

酷得&#xff08;i-coder&#xff09;是一家专业的技术服务公司&#xff0c;致力于为各类智能硬件提供高效、稳定、安全的底层驱动解决方案。我们拥有一支经验丰富、技术精湛的团队&#xff0c;能够为客户提供全方位的底层驱动开发服务。 下面是酷得的开发流程&#xff1a; 1…

NH2-PEG-Silane 氨基聚乙二醇硅烷 生物材料表面修饰

NH2-PEG-Silane 氨基聚乙二醇硅烷 生物材料表面修饰 【中文名称】氨基聚乙二醇硅烷 【英文名称】Silane-PEG-NH2 【结 构】 【品 牌】碳水科技&#xff08;Tanshtech&#xff09; 【纯 度】95%以上 【保 存】-20 【规 格】500mg,1g,5g,10g 【产品特性】 生…

NLP基础—jieba分词

jieba分词 支持四种分词模式 精确模式 试图将句子最精确地切开,适合文本分析;全模式 把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;搜索引擎模式 在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。paddle模式 利用Paddle…

MATLAB 体素滤波(62)

MATLAB 体素滤波(62) 一、算法介绍二、算法实现1.代码(已验证,直接运行)一、算法介绍 这里的代码完成文件读入,体素滤波,效果显示,结果输出的操作,下面是效果截图,后面是代码。 体素滤波(Voxel Filtering)是一种用于三维点云数据处理的方法,其原理类似于二维图像…

Nginx内存池相关源码剖析(三)小块内存分配逻辑

在Nginx中&#xff0c;小块内存通常指的是那些大小相对较小、分配和释放频率较高的内存块。这些内存块由于数量众多、管理复杂&#xff0c;因此需要使用一种高效的内存管理机制来减少内存管理的开销和内存碎片的产生。 Nginx内存池通过一种预分配和复用的方式来管理小块内存。当…

Reka团队打造前沿多模态语言模型,展现卓越性能

eka&#xff0c;一家新兴的人工智能公司&#xff0c;近期推出了一系列强大的多模态语言模型 - Reka Core、Reka Flash和Reka Edge。这些模型不仅能处理和推理文本&#xff0c;还能够灵活应对图像、视频和音频等多种输入&#xff0c;在各项测试中表现出色&#xff0c;在某些指标…

AI光芯登上Science,开启算力新纪元

智能光芯片“太极”&#xff1a;清华大学的科技壮举&#xff0c;开启算力新纪元 在科技的浩瀚星海中&#xff0c;每一次创新都是对未知世界的探索和征服。近日&#xff0c;清华大学电子工程系与自动化系的联合团队&#xff0c;凭借其深厚的科研实力和创新精神&#xff0c;研发出…

OpenCV4.10使用形态运算提取水平线和垂直线

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV的查找命中或未命中 下一篇&#xff1a;OpenCV4.9图像金字塔-CSDN博客 目标 在本教程中&#xff0c;您将学习如何&#xff1a; 应用两个非常常见的形态运算符&#xff08;即膨胀和…

【贪心 堆 】3081. 替换字符串中的问号使分数最小

算法可以发掘本质&#xff0c;如&#xff1a; 一&#xff0c;若干师傅和徒弟互有好感&#xff0c;有好感的师徒可以结对学习。师傅和徒弟都只能参加一个对子。如何让对子最多。 二&#xff0c;有无限多1X2和2X1的骨牌&#xff0c;某个棋盘若干格子坏了&#xff0c;如何在没有坏…

OpenHarmony社交分享类APP开发实战

介绍 本示例是一个社交分享类APP&#xff0c;搭建了不同的页面向用户提供获取社交信息等能力。为了减少频繁权限弹窗对用户的干扰&#xff0c;同时提供更小的授权范围&#xff0c;使用了安全控件做临时授权场景。当用户实际点击了某种类型的安全控件时&#xff0c;会由系统弹出…

Golang 开发实战day11 - Pass By Value

&#x1f3c6;个人专栏 &#x1f93a; leetcode &#x1f9d7; Leetcode Prime &#x1f3c7; Golang20天教程 &#x1f6b4;‍♂️ Java问题收集园地 &#x1f334; 成长感悟 欢迎大家观看&#xff0c;不执着于追求顶峰&#xff0c;只享受探索过程 Golang 开发实战day11 - 按值…

SpringCloud中的nacos配置中心分析

一、概述 nacos可以作为配置管理使用&#xff0c;为各个微服务之间提供统一的配置中心&#xff0c;方便管理所有服务的配置。 二、什么是配置中心&#xff1f; 配置中心&#xff1a;一般SpringBoot项目都使用在resources下创建类似application.yml之类的配置文件来管理整个项目…

微信生态洗牌,私域拥抱公域的逐步试探

一直被人们奉为“私域神器”的微信&#xff0c;如今&#xff0c;变化越来越大了&#xff0c;微信的几次更新&#xff0c;透露出很多不一样的信息&#xff0c;在微信的很多使用场景中&#xff0c;都逐渐在向平台化公域流量分发的方向发展&#xff0c;不断的尝试从私域走向公域&a…

2024年【起重机械指挥】考试题及起重机械指挥复审模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 起重机械指挥考试题是安全生产模拟考试一点通总题库中生成的一套起重机械指挥复审模拟考试&#xff0c;安全生产模拟考试一点通上起重机械指挥作业手机同步练习。2024年【起重机械指挥】考试题及起重机械指挥复审模拟…

社科院与新加坡社科大学工商管理博士——在职读博行而不辍,未来可期

在职读博&#xff0c;对于许多人来说&#xff0c;既是一种挑战&#xff0c;也是一种机遇。它要求我们在繁忙的工作之余&#xff0c;还要抽出时间来深入研究学术&#xff0c;不断提升自己的专业素养。然而&#xff0c;正是这种行而不辍的精神&#xff0c;让我们能够在职业生涯中…

C++类和对象:构造函数,析构函数,拷贝构造

文章目录 1.类的6个默认成员函数2. 构造函数2.1 概念2.2 特性 3.析构函数3.1 概念3.2 特性 4.拷贝构造 1.类的6个默认成员函数 一个类中什么都不写&#xff0c;就是空类。而空类实际上有成员&#xff0c;当一个类中什么都不写时&#xff0c;编译器会生成六个对应默认成员函数。…

解读我国最新网络安全运维与数据处理安全规范:强化数字化时代安全基石

近日&#xff0c;全国网络安全标准化技术委员会秘书处公布了一系列重要的网络安全与数据安全相关技术规范草案&#xff0c;包括《网络安全技术 网络安全运维实施指南》、《网络安全技术 信息系统灾难恢复规范》以及《数据安全技术 政务数据处理安全要求》。这些规范旨在应对当前…

JavaScript权威指南(第7版) 笔记 - 第 7 章 数组

能用代码说清楚的&#xff0c;绝不多废话&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; Linux创始人Linus的名言&#xff1a;Talk is cheap&#xff0c;show me the code ! &#xff0c;博主技术博文会精心给出能说明问题的范例代码&#xff01;…