What Is Float And How To Calculate Total & Free Float?

本文详细解析了项目管理中浮动的概念,包括总浮动和自由浮动的区别及计算方法,通过实例帮助理解浮动在路径和活动层面的含义。

In one of the recent discussion on our Forum, I realized PMP® aspirants have lots of questions on float of activities.There is a lot of confusion about different types of floats which can exist in a schedule network diagram. Total float and free float are considered same by many aspirants. It’s high time we drill this down so that all the confusions go off.

The term float is used to express the flexibility. This flexibility can be at the project level or at the activity level. Few points/definitions to be understood before we get into float of an activity.

  1. During a schedule network diagram – activity can be either predecessor or successor activity corresponding to the dependent activity we refer to
    • Predecessor – An activity that logically comes before a dependent activity in a schedule
    • Successor – A dependent activity that logically comes after another activity on a schedule.
  2. Critical Path – The critical path is the sequence of activities that represents the longest path through a project, which determines the shortest possible project duration
    • All activities on the critical path are called critical path activities
  3. Schedule Network Diagram – is a graphical representation of the logical relationships, also referred to as dependencies, among the project schedule activities
  4. PDM (Precedence Diagramming Method) – A technique used for constructing a schedule model in which activities are represented by nodes and are graphically linked by one or more logical relationships to show the sequence in which the activities are to be performed

I am not going into details of above and details of how to create a network diagram, ES, EF, and LS& LF for activities.

Now let’s get back to float. There are 2 types of floats which can exist i.e.

  1. Total Float
  2. Free Float

Let’s see what these floats are all about

Total Float

“The amount of time that a schedule activity can be delayed or extended from its early start date without delaying the project finish date or violating a schedule constraint.”

So this is talking about flexibility we have at project level. Now in a network diagram, we can have multiple paths to reach the end. So this float talks about flexibility one path has as compared to others.

Simple formula to calculate total float is our usual formula i.e. LS (Late Start) – ES (Early Start) or LF (Late, Finish) – EF (Early Finish)

Free Float

Now comes the real challenge, Free Float is different to Total Float and yes, it’s not a small difference which can confuse one with another.

“The amount of time that a schedule activity can be delayed without delaying the early start date of any successor or violating a schedule constraint”

Simple formula to calculate Free Float is ES (of successor) – EF of current activity

Here we are talking about activities and how much an activity can be delayed as compared to its successors

Looking at above lets bottom out few differences which can help us understand what are these two floats all about

Total Float Free Float
Calculated at path level of activities Calculated at the activity level
Defines flexibility of a path w.r.t project end date Define flexibility of activity w.r.t its successor start
Formula LS-ES or LF-EF Formula ES (of successors) – EF of current activity -1
Can come into existence if network diagram has multiple path and there are activities which are not there on Critical Path Can come into existence if successor is having more than one activity converging on it or the successor activity is having a constraint applied

Let’s look at one example to compile the stuff. Look at below network diagram

Network-diagram

What does this diagram depict?

  1. There are 3 paths ACE, BCE & BDE. ACE will be the critical path with total float 0 and the critical path length 18
  2. Activities A, C & E will be having even free float 0 (no kind of float/flexibility for critical path activities)
  3. Total float for B is 1 (LF-EF OR LS-ES) & activity D is 6
  4. Out of B & D which activity can have free float? Activity B is not satisfying free float definition. I.e. B can be delayed w.r.t C (6-4-1=1) but not w.r.t D (5-4-1=0). So if “ANY” part of the definition is not satisfying i.e. B can’t be delayed without impacting ANY successor of it.
  5. Free float for activity D = 14-7-1 = 6. This activity satisfies the definition along with point 4 and also there is no dependency/constraint in example which can hinder activity D having flexibility

I hope now the basic difference between these floats is clear and Float mystery is not more floating for you . If you still face any doubts or confusions you may refer to two points- first the definition and second the above table. Happy reading and do post follow up questions.

将代码中的输入改为通过socket接收(参考代码中的receive_data_via_socket()函数),输出改为通过socket发送(参考代码中的send_data_via_socket()函数)。将只执行一次的逻辑(proc_oneshot)改成持续执行接收来自socket的数据:/** @brief Source file of vendor ai net sample code. @file ai_net_with_mblob.c @ingroup ai_net_sample @note Nothing. Copyright Novatek Microelectronics Corp. 2021. All rights reserved. */ /*-----------------------------------------------------------------------------*/ /* Including Files */ /*-----------------------------------------------------------------------------*/ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include "hdal.h" #include "hd_debug.h" #include "vendor_ai.h" #include "vendor_ai_cpu/vendor_ai_cpu.h" #include <sys/time.h> #if defined(_NVT_NVR_SDK_) #include <comm/nvtmem_if.h> #include <sys/ioctl.h> #endif #if defined(_BSP_NA51068_) || defined(_BSP_NA51090_) #include "vendor_common.h" #endif // platform dependent #if defined(__LINUX) #include <signal.h> #include <pthread.h> //for pthread API #define MAIN(argc, argv) int main(int argc, char** argv) #define GETCHAR() getchar() #else #include <FreeRTOS_POSIX.h> #include <FreeRTOS_POSIX/signal.h> #include <FreeRTOS_POSIX/pthread.h> //for pthread API #include <kwrap/util.h> //for sleep API #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #define sleep(x) vos_util_delay_ms(1000*(x)) #define msleep(x) vos_util_delay_ms(x) #define usleep(x) vos_util_delay_us(x) #include <kwrap/examsys.h> //for MAIN(), GETCHAR() API #define MAIN(argc, argv) EXAMFUNC_ENTRY(ai3_net_with_mblob, argc, argv) #define GETCHAR() NVT_EXAMSYS_GETCHAR() #endif #define DEBUG_MENU 1 #define DUMP_POSTPROC_INFO 1 #define DBG_OUT_DUMP 0 // debug mode, dump output iobuf #define FLOAT_IN 0 #define FLOAT_OUT 0 /////////////////////////////////////////////////////////////////////////////// #define NET_PATH_ID UINT32 #define VENDOR_AI_CFG 0x000f0000 //vendor ai config #define AI_RGB_BUFSIZE(w, h) (ALIGN_CEIL_4((w) * HD_VIDEO_PXLFMT_BPP(HD_VIDEO_PXLFMT_RGB888_PLANAR) / 8) * (h)) #define MULTI_BATCH_IN 0 #define CONFIG_INTERNAL_BUFFER 0 #define OUTPUT 1 // 是否输出,debug用 #define BATCH_SIZE 64 UINT32 g_proc_num=10; UINT32 dump_time_ut=0; UINT32 dump_time_proc=0; UINT32 dump_output=0; static UINT MPROCESS_FOR_AIISP =0; CHAR dump_path[256]; /////////////////////////////////////////////////////////////////////////////// /*-----------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------*/ typedef struct _MEM_PARM { UINTPTR pa; UINTPTR va; UINT32 size; UINTPTR blk; } MEM_PARM; /*-----------------------------------------------------------------------------*/ /* Global Functions */ /*-----------------------------------------------------------------------------*/ static HD_RESULT receive_data_via_socket(NET_PROC *p_net, int sockfd, UINT32 input_cnt) { HD_RESULT ret = HD_OK; UINT32 i; for (i = 0; i < p_net->net_info.in_buf_cnt; i++) { // 接收输入数据长度 UINT32 data_size = p_net -> in_buf[i].size; // 预期输入数据大小 size_t total_recevied = 0; size_t remaining = data_size; // 剩余需要接收的 //char *data_buffer = (char *)p_net->in_buf[i].va; uintptr_t data_buffer = p_net -> in_buf[i].va; // MEM_PARM mem_parm; // mem_parm.va = p_net->in_buf[i].va; // 超时退出设置 struct timeval tv; tv.tv_sec = 5; tv.tv_usec = 0; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)); while (remaining > 0) { ssize_t bytes_received = recv(sockfd, (void *)(data_buffer + total_recevied), remaining, 0); if (bytes_received <= 0){ if (bytes_received == 0) { printf("Client closed connection during data transfer\n"); return HD_ERR_USER; } else if (errno == EAGAIN || errno == EWOULDBLOCK) { printf("Socket receive timeout\n"); return HD_ERR_TIMEDOUT; } else { perror("recv error during data transfer \n"); return HD_ERR_USER; } } total_recevied += bytes_received; remaining -= bytes_received; } if (input_cnt == 0) // 只在第一次打印此信息 { printf("\n Received input %d data via socket, size: %u bytes\n", i, data_size); } } return ret; } #if OUTPUT==1 /** * @brief 通过Socket发送输出结果 * @param p_net 网络处理结构体指针 * @param sockfd Socket文件描述符 * @return HD_RESULT 操作结果 */ static HD_RESULT send_data_via_socket(NET_PROC *p_net, int sockfd, UINT32 input_cnt, char* out_print) { HD_RESULT ret = HD_OK; UINT32 outlay_num = p_net->net_info.out_buf_cnt; LONG total_size = 0; VENDOR_AI3_BUF ai_buf = {0}; if (out_print == NULL) { printf("out_print malloc size fail \n"); return HD_ERR_FAIL; } // total_size += sprintf(out_print + total_size, "input index %u\n", input_cnt); /* 格式化输出结果 */ for (UINT32 i=0; i < outlay_num; i++) { ret = vendor_ai3_net_get(p_net->proc_id, p_net->net_info.out_path_list[i], &ai_buf); UINT32 out_length = ai_buf.time * ai_buf.batch_num * ai_buf.channel * ai_buf.height * ai_buf.width; // 输出数据量 // /* 新增文件写入部分 */ FILE *fp = fopen("output.bin", "wb+"); // 以二进制写入模式打开文件 if (fp == NULL) { perror("Error opening file"); // 输出错误信息 return HD_ERR_FAIL; // 返回错误码 } size_t written = fwrite((void *)p_net->out_mem_float[i].va, sizeof(FLOAT), out_length, fp); // 写入文件 printf("output ai buf size:%d, out length:%d \n", ai_buf.size, out_length); if (written != out_length) { perror("Error writing to file"); // 输出写入错误 fclose(fp); return HD_ERR_FAIL; } fclose(fp); // 关闭文件 if (HD_OK != ret) { printf("net_path(%u), proc_id(%u) get out buf fail, i(%d), out_path(0x%x)\n", p_net->net_id, p_net->proc_id, i, p_net->net_info.out_path_list[i]); return ret; } if (input_cnt == 1 && i % dump_mean_time_freq == 0) { printf("#######output_size:%u\n", out_length); } FLOAT *curr_layer_float_ptr =(FLOAT *)p_net->out_mem_float[i].va; for (UINT32 k = 0; k < out_length-1; k++) { // 2025.10.21新增:多batch时需要每行只输出一个样本的结果 if ((k+1) % (ai_buf.time * ai_buf.channel * ai_buf.height * ai_buf.width) == 0 && ai_buf.batch_num != 1) { total_size += sprintf(out_print + total_size, "%f\n", *(curr_layer_float_ptr+k)); } else { total_size += sprintf(out_print + total_size, "%f ", *(curr_layer_float_ptr+k)); } //total_size += sprintf(out_print + total_size, "%f ", *(curr_layer_float_ptr+k)); } total_size += sprintf(out_print + total_size, "%f\n", *(curr_layer_float_ptr+(out_length-1))); } write(sockfd, out_print, total_size); // 释放内存 // for (UINT32 i = 0; i < outlay_num; i++) // { // free(outlayer_float[i]); // outlayer_float[i] = NULL; // } // free(outlayer_float); // outlayer_float = NULL; return ret; } #endif /** * @brief 设置Socket服务器 * @return int 监听Socket的文件描述符 */ static int setup_socket_server(void) { int server_fd; struct sockaddr_in address; int opt = 1; // 创建Socket文件描述符 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // 设置Socket选项 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { perror("setsockopt failed"); close(server_fd); exit(EXIT_FAILURE); } // 绑定地址和端口 address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(SOCKET_PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); close(server_fd); exit(EXIT_FAILURE); } // 开始监听 if (listen(server_fd, MAX_CLIENTS) < 0) { perror("listen failed"); close(server_fd); exit(EXIT_FAILURE); } printf("Socket server listening on port %d\n", SOCKET_PORT); return server_fd; } static HD_RESULT mem_alloc(MEM_PARM *mem_parm, CHAR* name, UINT32 size) { HD_RESULT ret = HD_OK; UINTPTR pa = 0; void *va = NULL; //alloc private pool ret = hd_common_mem_alloc(name, &pa, (void**)&va, size, DDR_ID0); if (ret!= HD_OK) { return ret; } mem_parm->pa = pa; mem_parm->va = (UINTPTR)va; mem_parm->size = size; mem_parm->blk = (UINTPTR)-1; return HD_OK; } static HD_RESULT mem_free(MEM_PARM *mem_parm) { HD_RESULT ret = HD_OK; //free private pool ret = hd_common_mem_free(mem_parm->pa, (void *)mem_parm->va); if (ret!= HD_OK) { return ret; } mem_parm->pa = 0; mem_parm->va = 0; mem_parm->size = 0; mem_parm->blk = (UINT32)-1; return HD_OK; } static INT32 mem_load(MEM_PARM *mem_parm, const CHAR *filename) { FILE *fd; INT32 size = 0; fd = fopen(filename, "rb"); if (!fd) { printf("cannot read %s\r\n", filename); size = -1; goto exit; } fseek(fd, 0, SEEK_END); size = ftell(fd); fseek(fd, 0, SEEK_SET); // check "ai_in_buf" enough or not if (mem_parm->size < (UINT32)size) { printf("ERROR: ai_in_buf(%u) is not enough, input file(%u)\r\n", mem_parm->size, (UINT32)size); size = -1; goto exit; } if (size < 0) { printf("getting %s size failed\r\n", filename); goto exit; } else if ((INT32)fread((VOID *)mem_parm->va, 1, size, fd) != size) { printf("read size < %d\r\n", size); size = -1; goto exit; } mem_parm->size = size; // we use cpu to read memory, which needs to deal cache flush. if(hd_common_mem_flush_cache((VOID *)mem_parm->va, mem_parm->size) != HD_OK) { printf("flush cache failed.\r\n"); } exit: if (fd) { fclose(fd); } return size; } /*-----------------------------------------------------------------------------*/ /* Input Functions */ /*-----------------------------------------------------------------------------*/ /////////////////////////////////////////////////////////////////////////////// typedef struct _NET_IN_CONFIG { CHAR input_filename[256]; UINT32 w; UINT32 h; UINT32 c; UINT32 b; UINT32 bitdepth; UINT32 loff; UINT32 fmt; UINT32 is_comb_img; // 1: image image (or feature-in) is a combination image (or feature-in). } NET_IN_CONFIG; typedef struct _NET_IN { NET_IN_CONFIG in_cfg; MEM_PARM input_mem; UINT32 in_id; VENDOR_AI3_BUF src_img; } NET_IN; static NET_IN *g_in = NULL; static UINT32 _calc_ai_buf_size(UINT32 loff, UINT32 h, UINT32 c, UINT32 b, UINT32 bitdepth, UINT32 fmt) { UINT size = 0; switch (fmt) { case HD_VIDEO_PXLFMT_YUV420: { size = loff * h * 3 / 2; } break; case HD_VIDEO_PXLFMT_RGB888_PLANAR: { size = AI_RGB_BUFSIZE(loff, h); } break; case HD_VIDEO_PXLFMT_BGR888_PLANAR: { size = AI_RGB_BUFSIZE(loff, h); } break; default: // feature-in { size = loff * h * c * bitdepth/8; } break; } if (!size) { printf("ERROR!! ai_buf size = 0\n"); } return size; } static HD_RESULT _load_buf(MEM_PARM *mem_parm, CHAR *filename, VENDOR_AI3_BUF *p_buf, UINT32 w, UINT32 h, UINT32 c, UINT32 b, UINT32 bitdepth, UINT32 loff, UINT32 fmt) { INT32 file_len; file_len = mem_load(mem_parm, filename); if (file_len < 0) { printf("load buf(%s) fail\r\n", filename); return HD_ERR_NG; } printf("load buf(%s) ok\r\n", filename); p_buf->width = w; p_buf->height = h; p_buf->channel = c; p_buf->batch_num = b; p_buf->line_ofs = loff; p_buf->fmt = fmt; p_buf->pa = mem_parm->pa; p_buf->va = mem_parm->va; p_buf->sign = MAKEFOURCC('A','B','U','F'); p_buf->size = _calc_ai_buf_size(loff, h, c, b, bitdepth, fmt); if (p_buf->size == 0) { printf("load buf(%s) fail, p_buf->size = 0\r\n", filename); return HD_ERR_NG; } return HD_OK; } static HD_RESULT input_init(void) { HD_RESULT ret = HD_OK; int i; for (i = 0; i < 16; i++) { NET_IN* p_net = g_in + i; p_net->in_id = i; } return ret; } static HD_RESULT input_uninit(void) { HD_RESULT ret = HD_OK; return ret; } static HD_RESULT input_set_config(NET_PATH_ID in_path, NET_IN_CONFIG* p_in_cfg) { HD_RESULT ret = HD_OK; NET_IN* p_net = g_in + in_path; UINT32 in_id = p_net->in_id; memcpy((void*)&p_net->in_cfg, (void*)p_in_cfg, sizeof(NET_IN_CONFIG)); printf("in_path(%u) in_id(%u) set in_cfg: file(%s), buf=(%u,%u,%u,%u,%u,%u,%08x)\r\n", in_path, in_id, p_net->in_cfg.input_filename, p_net->in_cfg.w, p_net->in_cfg.h, p_net->in_cfg.c, p_net->in_cfg.b, p_net->in_cfg.bitdepth, p_net->in_cfg.loff, p_net->in_cfg.fmt); return ret; } static HD_RESULT input_open(NET_PATH_ID in_path) { HD_RESULT ret = HD_OK; NET_IN* p_net = g_in + in_path; UINT32 in_id = p_net->in_id; UINT32 buf_size = 0; CHAR mem_name[23] ; snprintf(mem_name, 23, "ai_in_buf %u", in_id); // calculate in buf size buf_size = _calc_ai_buf_size(p_net->in_cfg.loff, p_net->in_cfg.h, p_net->in_cfg.c, p_net->in_cfg.b, p_net->in_cfg.bitdepth, p_net->in_cfg.fmt); if (buf_size == 0) { printf("in_path(%u) in_id(%u) size == 0 \r\n", in_path, in_id); return HD_ERR_FAIL; } // allocate in buf ret = mem_alloc(&p_net->input_mem, mem_name, buf_size * p_net->in_cfg.b); if (ret != HD_OK) { printf("in_path(%u) in_id(%u) alloc ai_in_buf fail\r\n", in_path, in_id); return HD_ERR_FAIL; } printf("alloc_in_buf: pa = 0x%lx, va = 0x%lx, size = %u\n", p_net->input_mem.pa, p_net->input_mem.va, p_net->input_mem.size); // load in buf ret = _load_buf(&p_net->input_mem, p_net->in_cfg.input_filename, &p_net->src_img, p_net->in_cfg.w, p_net->in_cfg.h, p_net->in_cfg.c, p_net->in_cfg.b, p_net->in_cfg.bitdepth, p_net->in_cfg.loff, p_net->in_cfg.fmt); if (ret != HD_OK) { printf("in_path(%u) in_id(%u) input_open fail=%d\n", in_path, in_id, ret); } return ret; } static HD_RESULT input_close(NET_PATH_ID in_path) { HD_RESULT ret = HD_OK; NET_IN* p_net = g_in + in_path; mem_free(&p_net->input_mem); return ret; } static HD_RESULT input_start(NET_PATH_ID in_path) { HD_RESULT ret = HD_OK; return ret; } static HD_RESULT input_stop(NET_PATH_ID in_path) { HD_RESULT ret = HD_OK; return ret; } static HD_RESULT input_pull_buf(NET_PATH_ID in_path, VENDOR_AI3_BUF *p_in, INT32 wait_ms) { HD_RESULT ret = HD_OK; NET_IN* p_net = g_in + in_path; memcpy((void*)p_in, (void*)&(p_net->src_img), sizeof(VENDOR_AI3_BUF)); return ret; } /////////////////////////////////////////////////////////////////////////////// /*-----------------------------------------------------------------------------*/ /* Network Functions */ /*-----------------------------------------------------------------------------*/ typedef struct _NET_PROC_CONFIG { CHAR model_filename[256]; INT32 binsize; void *p_share_model; CHAR label_filename[256]; } NET_PROC_CONFIG; typedef struct _NET_PROC { NET_PROC_CONFIG net_cfg; MEM_PARM proc_mem; UINT32 proc_id; //CHAR out_class_labels[MAX_CLASS_NUM * VENDOR_AIS_LBL_LEN]; MEM_PARM rslt_mem; MEM_PARM io_mem; MEM_PARM intl_mem; MEM_PARM *out_mem; VENDOR_AI3_NET_INFO net_info; } NET_PROC; static NET_PROC *g_net = NULL; static INT32 _getsize_model(char* filename) { FILE *bin_fd; UINT32 bin_size = 0; bin_fd = fopen(filename, "rb"); if (!bin_fd) { printf("get bin(%s) size fail\n", filename); return (-1); } fseek(bin_fd, 0, SEEK_END); bin_size = ftell(bin_fd); fseek(bin_fd, 0, SEEK_SET); fclose(bin_fd); return bin_size; } static UINT32 _load_model(CHAR *filename, UINTPTR va) { FILE *fd; UINT32 file_size = 0, read_size = 0; const UINTPTR model_addr = va; //DBG_DUMP("model addr = %#lx\r\n", model_addr); fd = fopen(filename, "rb"); if (!fd) { printf("load model(%s) fail\r\n", filename); return 0; } fseek ( fd, 0, SEEK_END ); file_size = ALIGN_CEIL_4( ftell(fd) ); fseek ( fd, 0, SEEK_SET ); read_size = fread ((void *)model_addr, 1, file_size, fd); if (read_size != file_size) { printf("size mismatch, real = %d, idea = %d\r\n", (int)read_size, (int)file_size); } fclose(fd); printf("load model(%s) ok\r\n", filename); return read_size; } /* static HD_RESULT _load_label(UINTPTR addr, UINT32 line_len, const CHAR *filename) { FILE *fd; CHAR *p_line = (CHAR *)addr; fd = fopen(filename, "r"); if (!fd) { printf("load label(%s) fail\r\n", filename); return HD_ERR_NG; } while (fgets(p_line, line_len, fd) != NULL) { p_line[strlen(p_line) - 1] = '\0'; // remove newline character p_line += line_len; } if (fd) { fclose(fd); } printf("load label(%s) ok\r\n", filename); return HD_OK; } */ static HD_RESULT network_init(void) { HD_RESULT ret = HD_OK; { VENDOR_AI3_DEV_CFG dev_cfg = {0}; ret = vendor_ai3_dev_init(&dev_cfg); if (ret != HD_OK) { printf("vendor_ai3_dev_init fail=%d\n", ret); return ret; } } // dump AI3 version { VENDOR_AI3_VER ai3_ver = {0}; ret = vendor_ai3_dev_get(VENDOR_AI3_CFG_VER, &ai3_ver); if (ret != HD_OK) { printf("vendor_ai3_dev_get(CFG_VER) fail=%d\n", ret); return ret; } printf("vendor_ai version = %s\r\n", ai3_ver.vendor_ai_impl_version); printf("kflow_ai version = %s\r\n", ai3_ver.kflow_ai_impl_version); printf("kdrv_ai version = %s\r\n", ai3_ver.kdrv_ai_impl_version); } return ret; } static HD_RESULT network_uninit(void) { HD_RESULT ret = HD_OK; ret = vendor_ai3_dev_uninit(); if (ret != HD_OK) { printf("vendor_ai3_dev_uninit fail=%d\n", ret); } return ret; } static INT32 network_mem_config(NET_PATH_ID net_path, HD_COMMON_MEM_INIT_CONFIG* p_mem_cfg, void* p_cfg) { NET_PROC* p_net = g_net + net_path; NET_PROC_CONFIG* p_proc_cfg = (NET_PROC_CONFIG*)p_cfg; #if defined(_NVT_NVR_SDK_) int sys_fd; struct nvtmem_hdal_base sys_hdal; uintptr_t hdal_start_addr0, hdal_start_addr1; sys_fd = open("/dev/nvtmem0", O_RDWR); if (sys_fd < 0) { printf("Error: cannot open /dev/nvtmem0 device.\n"); exit(0); } if (ioctl(sys_fd, NVTMEM_GET_DTS_HDAL_BASE, &sys_hdal) < 0) { printf("PCIE_SYS_IOC_HDALBASE! \n"); close(sys_fd); exit(0); } close(sys_fd); /* init ddr0 user_blk */ hdal_start_addr0 = sys_hdal.base[0]; p_mem_cfg->pool_info[0].start_addr = hdal_start_addr0; p_mem_cfg->pool_info[0].blk_cnt = 1; p_mem_cfg->pool_info[0].blk_size = 200 * 1024 * 1024; p_mem_cfg->pool_info[0].type = HD_COMMON_MEM_USER_BLK; p_mem_cfg->pool_info[0].ddr_id = sys_hdal.ddr_id[0]; printf("create ddr%d: hdal_memory(%#lx, %ldKB), usr_blk(%#lx, %dKB)\n", p_mem_cfg->pool_info[0].ddr_id, hdal_start_addr0, sys_hdal.size[0] / 1024, p_mem_cfg->pool_info[0].start_addr, p_mem_cfg->pool_info[0].blk_size * p_mem_cfg->pool_info[0].blk_cnt / 1024); /* init ddr1 user_blk, if ddr1 is exist */ if (sys_hdal.size[1] != 0) { hdal_start_addr1 = sys_hdal.base[1]; p_mem_cfg->pool_info[1].start_addr = hdal_start_addr1; p_mem_cfg->pool_info[1].blk_cnt = 1; p_mem_cfg->pool_info[1].blk_size = 200 * 1024 * 1024; p_mem_cfg->pool_info[1].type = HD_COMMON_MEM_USER_BLK; p_mem_cfg->pool_info[1].ddr_id = sys_hdal.ddr_id[1]; printf("create ddr%d: hdal_memory(%#lx, %ldKB) usr_blk(%#lx, %dKB)\n", p_mem_cfg->pool_info[1].ddr_id, hdal_start_addr1, sys_hdal.size[1] / 1024, p_mem_cfg->pool_info[1].start_addr, p_mem_cfg->pool_info[1].blk_size * p_mem_cfg->pool_info[1].blk_cnt / 1024); } else { printf("create ddr1: hdal_memory(%#lx, %ldKB) is not exist\n", sys_hdal.base[1], sys_hdal.size[1] / 1024); } usleep(30000); // wait for printf completely #endif memcpy((void*)&p_net->net_cfg, (void*)p_proc_cfg, sizeof(NET_PROC_CONFIG)); if (strlen(p_net->net_cfg.model_filename) == 0) { printf("net_path(%u) input model is null\r\n", net_path); return HD_ERR_NG; } p_net->net_cfg.binsize = _getsize_model(p_net->net_cfg.model_filename); if (p_net->net_cfg.binsize <= 0) { printf("net_path(%u) input model is not exist?\r\n", net_path); return HD_ERR_NG; } printf("net_path(%u) set net_mem_cfg: model-file(%s), binsize=%d\r\n", net_path, p_net->net_cfg.model_filename, p_net->net_cfg.binsize); printf("net_path(%u) set net_mem_cfg: label-file(%s)\r\n", net_path, p_net->net_cfg.label_filename); return HD_OK; } static HD_RESULT network_alloc_io_buf(NET_PATH_ID net_path, UINT32 req_size) { HD_RESULT ret = HD_OK; NET_PROC* p_net = g_net + net_path; CHAR mem_name[23] ; snprintf(mem_name, 23, "ai_io_buf %u", net_path); ret = mem_alloc(&p_net->io_mem, mem_name, req_size); if (ret != HD_OK) { printf("net_path(%u) alloc ai_io_buf fail\r\n", net_path); return HD_ERR_FAIL; } printf("alloc_io_buf: work buf, pa = %#lx, va = %#lx, size = %u\r\n", p_net->io_mem.pa, p_net->io_mem.va, p_net->io_mem.size); return ret; } static HD_RESULT network_free_io_buf(NET_PATH_ID net_path) { HD_RESULT ret = HD_OK; NET_PROC* p_net = g_net + net_path; if (p_net->io_mem.pa && p_net->io_mem.va) { mem_free(&p_net->io_mem); } return ret; } static HD_RESULT network_alloc_intl_buf(NET_PATH_ID net_path, UINT32 req_size) { HD_RESULT ret = HD_OK; NET_PROC* p_net = g_net + net_path; CHAR mem_name[23] ; snprintf(mem_name, 23, "ai_ronly_buf %u", net_path); ret = mem_alloc(&p_net->intl_mem, mem_name, req_size); if (ret != HD_OK) { printf("net_path(%u) alloc ai_ronly_buf fail\r\n", net_path); return HD_ERR_FAIL; } printf("alloc_intl_buf: internal buf, pa = %#lx, va = %#lx, size = %u\r\n", p_net->intl_mem.pa, p_net->intl_mem.va, p_net->intl_mem.size); return ret; } static HD_RESULT network_free_intl_buf(NET_PATH_ID net_path) { HD_RESULT ret = HD_OK; NET_PROC* p_net = g_net + net_path; if (p_net->intl_mem.pa && p_net->intl_mem.va) { mem_free(&p_net->intl_mem); } return ret; } static HD_RESULT network_open(NET_PATH_ID net_path) { HD_RESULT ret = HD_OK; NET_PROC* p_net = g_net + net_path; UINT32 loadsize = 0; CHAR mem_name[23] ; snprintf(mem_name, 23, "model.bin %u", net_path); if (strlen(p_net->net_cfg.model_filename) == 0) { printf("net_path(%u) input model is null\r\n", net_path); return 0; } ret = mem_alloc(&p_net->proc_mem, mem_name, p_net->net_cfg.binsize); if (ret != HD_OK) { printf("net_path(%u) mem_alloc model.bin fail=%d\n", net_path, ret); return HD_ERR_FAIL; } //load file loadsize = _load_model(p_net->net_cfg.model_filename, p_net->proc_mem.va); if (loadsize <= 0) { printf("net_path(%u) input model load fail: %s\r\n", net_path, p_net->net_cfg.model_filename); return 0; } /* // load label ret = _load_label((UINTPTR)p_net->out_class_labels, VENDOR_AIS_LBL_LEN, p_net->net_cfg.label_filename); if (ret != HD_OK) { printf("proc_id(%u) load_label fail=%d\n", proc_id, ret); return HD_ERR_FAIL; } */ { VENDOR_AI3_MODEL_INFO model_info = {0}; model_info.model_buf.pa = p_net->proc_mem.pa; model_info.model_buf.va = p_net->proc_mem.va; model_info.model_buf.size = p_net->proc_mem.size; #if DBG_OUT_DUMP model_info.ctrl = CTRL_BUF_DEBUG | CTRL_JOB_DEBUG | CTRL_JOB_DUMPOUT; #endif #if FLOAT_IN model_info.ctrl = model_info.ctrl | CTRL_BUF_FLOATIN ; #endif #if FLOAT_OUT model_info.ctrl = model_info.ctrl | CTRL_BUF_FLOATOUT ; #endif printf("net_path(%u) vendor_ai3_dev_get(MODEL_INFO) \n", net_path); ret = vendor_ai3_dev_get(VENDOR_AI3_CFG_MODEL_INFO, &model_info); if (ret != HD_OK) { printf("net_path(%u) vendor_ai3_dev_get(MODEL_INFO) fail=%d\n", net_path, ret); return HD_ERR_FAIL; } printf("model_info get => workbuf size = %d, ronlybuf size = %d\r\n", model_info.proc_mem.buf[AI3_PROC_BUF_WORKBUF].size, model_info.proc_mem.buf[AI3_PROC_BUF_RONLYBUF].size); // alloc WORKBUF/RONLYBUF ret = network_alloc_intl_buf(net_path, model_info.proc_mem.buf[AI3_PROC_BUF_RONLYBUF].size); if (ret != HD_OK) { printf("net_path(%u) alloc ronlybuf fail=%d\n", net_path, ret); return HD_ERR_FAIL; } ret = network_alloc_io_buf(net_path, model_info.proc_mem.buf[AI3_PROC_BUF_WORKBUF].size); if (ret != HD_OK) { printf("net_path(%u) alloc workbuf fail=%d\n", net_path, ret); return HD_ERR_FAIL; } } // call open() { VENDOR_AI3_PROC_CFG proc_cfg = {0}; proc_cfg.model_buf.pa = p_net->proc_mem.pa; proc_cfg.model_buf.va = p_net->proc_mem.va; proc_cfg.model_buf.size = p_net->proc_mem.size; proc_cfg.proc_mem.buf[AI3_PROC_BUF_RONLYBUF].pa = p_net->intl_mem.pa; proc_cfg.proc_mem.buf[AI3_PROC_BUF_RONLYBUF].va = p_net->intl_mem.va; proc_cfg.proc_mem.buf[AI3_PROC_BUF_RONLYBUF].size = p_net->intl_mem.size; proc_cfg.proc_mem.buf[AI3_PROC_BUF_WORKBUF].pa = p_net->io_mem.pa; proc_cfg.proc_mem.buf[AI3_PROC_BUF_WORKBUF].va = p_net->io_mem.va; proc_cfg.proc_mem.buf[AI3_PROC_BUF_WORKBUF].size = p_net->io_mem.size; proc_cfg.plugin[AI3_PLUGIN_CPU] = vendor_ai_cpu1_get_engine(); #if DBG_OUT_DUMP proc_cfg.ctrl = CTRL_BUF_DEBUG | CTRL_JOB_DEBUG | CTRL_JOB_DUMPOUT; #endif #if FLOAT_IN proc_cfg.ctrl = proc_cfg.ctrl | CTRL_BUF_FLOATIN ; #endif #if FLOAT_OUT proc_cfg.ctrl = proc_cfg.ctrl | CTRL_BUF_FLOATOUT ; #endif ret = vendor_ai3_net_open(&p_net->proc_id, &proc_cfg, &p_net->net_info); if (ret != HD_OK) { printf("net_path(%u) vendor_ai3_net_open() fail=%d\n", net_path, ret); return HD_ERR_FAIL; } else { printf("net_path(%u) open success => get proc_id(%u)\r\n", net_path, p_net->proc_id); } } return ret; } static HD_RESULT network_close(NET_PATH_ID net_path) { HD_RESULT ret = HD_OK; NET_PROC* p_net = g_net + net_path; UINT32 proc_id = p_net->proc_id; UINT32 i ; // close ret = vendor_ai3_net_close(proc_id); if (ret != HD_OK) { printf("net_path(%u), proc_id(%u) vendor_ai3_net_close fail=%d\n", net_path, proc_id, ret); return HD_ERR_FAIL; } if ((ret = network_free_intl_buf(net_path)) != HD_OK) return ret; if ((ret = network_free_io_buf(net_path)) != HD_OK) return ret; mem_free(&p_net->proc_mem); for (i = 0 ; i < p_net->net_info.out_buf_cnt; i++){ if(p_net->out_mem && p_net->out_mem[i].va) mem_free(&p_net->out_mem[i]); } if(p_net->out_mem) free(p_net->out_mem) ; return ret; } #if DUMP_POSTPROC_INFO static HD_RESULT network_dump_ai_buf(VENDOR_AI3_BUF *p_outbuf) { HD_RESULT ret = HD_OK; printf(" sign(0x%x) pa(0x%lx) va(0x%lx) sz(%u) w(%u) h(%u) ch(%u) batch_num(%u)\n", p_outbuf->sign, p_outbuf->pa, p_outbuf->va, p_outbuf->size, p_outbuf->width, p_outbuf->height, p_outbuf->channel, p_outbuf->batch_num); printf(" l_ofs(%llu) c_ofs(%llu) b_ofs(%llu) t_ofs(%llu) layout(%s) name(%s) scale_ratio(%.6f)\n", p_outbuf->line_ofs, p_outbuf->channel_ofs, p_outbuf->batch_ofs, p_outbuf->time_ofs, p_outbuf->layout, p_outbuf->name, p_outbuf->scale_ratio); // parsing pixel format switch (AI_PXLFMT_TYPE(p_outbuf->fmt)) { case HD_VIDEO_PXLFMT_AI_UINT8: case HD_VIDEO_PXLFMT_AI_SINT8: case HD_VIDEO_PXLFMT_AI_UINT16: case HD_VIDEO_PXLFMT_AI_SINT16: case HD_VIDEO_PXLFMT_AI_UINT32: case HD_VIDEO_PXLFMT_AI_SINT32: case HD_VIDEO_PXLFMT_AI_FLOAT32: { INT8 bitdepth = HD_VIDEO_PXLFMT_BITS(p_outbuf->fmt); INT8 int_bits = HD_VIDEO_PXLFMT_INT(p_outbuf->fmt); INT8 frac_bits = HD_VIDEO_PXLFMT_FRAC(p_outbuf->fmt); printf(" fmt(0x%x) bits(%u) int(%u) frac(%u)\n", p_outbuf->fmt, bitdepth, int_bits, frac_bits); } break; default: switch ((UINT32)p_outbuf->fmt) { case HD_VIDEO_PXLFMT_BGR888_PLANAR: { printf(" fmt(0x%x), BGR888_PLANAR\n", p_outbuf->fmt); } break; case HD_VIDEO_PXLFMT_YUV420: { printf(" fmt(0x%x), YUV420\n", p_outbuf->fmt); } break; case HD_VIDEO_PXLFMT_Y8: { printf(" fmt(0x%x), Y8 only\n", p_outbuf->fmt); } break; case HD_VIDEO_PXLFMT_UV: { printf(" fmt(0x%x), UV only\n", p_outbuf->fmt); } break; case 0: { printf(" fmt(0x%x), AI BUF\n", p_outbuf->fmt); } break; default: printf("unknown pxlfmt(0x%x)\n", p_outbuf->fmt); break; } } printf("\n"); return ret; } /* static INT32 mem_save(MEM_PARM *mem_parm, const CHAR *filename) { FILE *fd; UINT32 size = 0; fd = fopen(filename, "wb"); if (!fd) { printf("ERR: cannot open %s for write!\r\n", filename); return -1; } size = (INT32)fwrite((VOID *)mem_parm->va, 1, mem_parm->size, fd); if (size != mem_parm->size) { printf("ERR: write %s with size %ld < wanted %ld?\r\n", filename, size, mem_parm->size); } else { printf("write %s with %ld bytes.\r\n", filename, mem_parm->size); } if (fd) { fclose(fd); } return size; } */ #endif /////////////////////////////////////////////////////////////////////////////// typedef struct _VIDEO_LIVEVIEW { // (1) input NET_IN_CONFIG net_in_cfg; NET_PATH_ID in_path; // (2) network NET_PROC_CONFIG net_proc_cfg; NET_PATH_ID net_path; pthread_t proc_thread_id; UINT32 proc_start; UINT32 proc_exit; UINT32 proc_oneshot; UINT32 input_blob_num; } VIDEO_LIVEVIEW; static HD_RESULT init_module(void) { HD_RESULT ret; if ((ret = input_init()) != HD_OK) return ret; if ((ret = network_init()) != HD_OK) return ret; return HD_OK; } static HD_RESULT open_module(VIDEO_LIVEVIEW *p_stream) { HD_RESULT ret; //if ((ret = input_open(p_stream->in_path)) != HD_OK) // return ret; if ((ret = network_open(p_stream->net_path)) != HD_OK) return ret; return HD_OK; } static HD_RESULT close_module(VIDEO_LIVEVIEW *p_stream) { HD_RESULT ret; //if ((ret = input_close(p_stream->in_path)) != HD_OK) // return ret; if ((ret = network_close(p_stream->net_path)) != HD_OK) return ret; return HD_OK; } static HD_RESULT exit_module(void) { HD_RESULT ret; if ((ret = input_uninit()) != HD_OK) return ret; if ((ret = network_uninit()) != HD_OK) return ret; return HD_OK; } static HD_RESULT perf_begin(void) { vendor_ai3_dev_perf_begin(VENDOR_AI3_PERF_ID_TIME_UT); return HD_OK; } static HD_RESULT perf_end(void) { UINT32 i; VENDOR_AI3_PERF_TIME_UT perf_time_ut = {0}; vendor_ai3_dev_perf_end(VENDOR_AI3_PERF_ID_TIME_UT, &perf_time_ut); printf("\r\n ************* util-per-proc() *************\r\n"); for (i=0; i<perf_time_ut.core_count; i++) { printf("%8s: time(us) = %6d, util(%%) = %6.2f\r\n", perf_time_ut.core[i].name, perf_time_ut.core[i].time, ((float)perf_time_ut.core[i].util)/100); } return HD_OK; } /////////////////////////////////////////////////////////////////////////////// static VOID *network_user_thread(VOID *arg); static HD_RESULT set_buf_by_in_path_list(VIDEO_LIVEVIEW *p_stream) { HD_RESULT ret = HD_OK; NET_PATH_ID net_path = p_stream->net_path; NET_PROC* p_net = g_net + net_path; VENDOR_AI3_NET_INFO net_info = p_net->net_info; VENDOR_AI3_BUF in_buf = {0}; VENDOR_AI3_BUF tmp_buf = {0}; UINT32 proc_id = p_net->proc_id; UINT32 i = 0, idx = 0, k = 0; UINT32 in_buf_cnt = 0; UINT32 *in_path_list = NULL; /* get in path list */ in_path_list = p_net->net_info.in_path_list; in_buf_cnt = net_info.in_buf_cnt; for (i = 0; i < in_buf_cnt; i++) { /* get in buf (by in path list) */ ret = vendor_ai3_net_get(proc_id, in_path_list[i], &tmp_buf); if (HD_OK != ret) { printf("net_path(%u), proc_id(%u) get in buf fail, i(%d), in_path(0x%x)\n",net_path, proc_id, i, in_path_list[i]); goto exit; } if (dump_output) { // dump in buf printf("dump_in_buf: path_id: 0x%x\n", in_path_list[i]); ret = network_dump_ai_buf(&tmp_buf); if (HD_OK != ret) { printf("net_path(%u), proc_id(%u) dump in buf fail !!\n", net_path, proc_id); goto exit; }} } for (i = 0; i < p_stream->input_blob_num; i++) { NET_IN* p_in = g_in + i; /* load input bin */ ret = input_pull_buf((p_stream->in_path + i), &in_buf, 0); if (HD_OK != ret) { printf("in_path(%u) pull input fail !!\n", (p_stream->in_path + i)); goto exit; } if (p_in->in_cfg.is_comb_img == 0) { for(k =1 ; k < in_buf.batch_num; k++) { UINTPTR dst_va = in_buf.va + (k * in_buf.size); memcpy((VOID*)dst_va , (VOID*)in_buf.va, in_buf.size); hd_common_mem_flush_cache((VOID *)dst_va, in_buf.size); } } //printf(" path_%d(0x%x) pa(0x%lx) va(0x%lx) size(%u)\n", idx, in_path_list[idx], in_buf.pa, in_buf.va, in_buf.size); ret = vendor_ai3_net_set(proc_id, in_path_list[idx], &in_buf); if (HD_OK != ret) { printf("proc_id(%u)push input fail !! i(%u)\n", proc_id, i); goto exit; } idx++; } exit: return ret; } static HD_RESULT set_buf_by_out_path_list(NET_PATH_ID net_path) { HD_RESULT ret = HD_OK; NET_PROC* p_net = g_net + net_path; UINT32 proc_id = p_net->proc_id; UINT32 i; VENDOR_AI3_BUF ai_buf = {0}; /* get out buf */ for (i = 0; i < p_net->net_info.out_buf_cnt; i++) { // get out buf (by out path list) ret = vendor_ai3_net_get(proc_id, p_net->net_info.out_path_list[i], &ai_buf); if (HD_OK != ret) { printf("proc_id(%u) get out buf fail, i(%d), out_path(0x%x)\n", proc_id, i, p_net->net_info.out_path_list[i]); goto exit; } if (ai_buf.size > p_net->out_mem[i].size){ printf("output size %u < ai_buf.size %u\r\n", p_net->out_mem[i].size, ai_buf.size); goto exit; } ai_buf.va = p_net->out_mem[i].va ; ai_buf.pa = p_net->out_mem[i].pa ; ai_buf.size = p_net->out_mem[i].size ; #if FLOAT_OUT ai_buf.fmt = HD_VIDEO_PXLFMT_AI_FLOAT32; #endif ret = vendor_ai3_net_set(proc_id, p_net->net_info.out_path_list[i], &ai_buf); if (HD_OK != ret) { printf("proc_id(%u)set output buf fail !! (%u)\n", proc_id, i); goto exit; } } exit: return ret; } #if (1) static uintptr_t get_post_buf(uint32_t size) { uintptr_t buf = (uintptr_t)malloc(size); return buf; } static VOID release_post_buf(VOID *ptr) { if (ptr) { free(ptr); } return; } #endif #if(1) static HD_RESULT network_dump_out_buf(NET_PATH_ID net_path, VENDOR_AI3_BUF *p_outbuf, UINT32 id) { HD_RESULT ret = HD_OK; //NET_PROC *p_net = g_net + net_path; //INT32 i; //AI_NET_ACCURACY_PARM parm = {0}; //AI_NET_SHAPE shape = {p_outbuf->batch_num, p_outbuf->channel, 1, 1, 1}; //INT32 size = shape.num * shape.channels * shape.height * shape.width; UINT32 length = p_outbuf->batch_num * p_outbuf->channel * p_outbuf->height * p_outbuf->width; FLOAT *p_outbuf_float = (FLOAT *)get_post_buf(length * sizeof(FLOAT)); ret = vendor_ai_cpu_util_fixed2float((VOID *)p_outbuf->va, p_outbuf->fmt, p_outbuf_float, p_outbuf->scale_ratio, length, p_outbuf->zero_point); printf("id:%d size:%d name:%s\n", id, length, p_outbuf->name); #if (1) // save output float bin CHAR out_float_path[256] = {0}; sprintf(out_float_path, "%s/float_%s.bin", dump_path, p_outbuf->name); printf("out_float_path: %s\n", out_float_path); FILE* fp_out = NULL; if ((fp_out = fopen(out_float_path, "wb+")) == NULL) { printf("fopen fail\n"); } else { fwrite((VOID *)p_outbuf_float, sizeof(FLOAT), length, fp_out); //fwrite((VOID *)layer_buffer[i].va, sizeof(INT16), length, fp_out); } if(fp_out){ fclose(fp_out); } // save output fixed bin CHAR out_fixed_path[256] = {0}; sprintf(out_fixed_path, "%s/fixed_%s.bin", dump_path, p_outbuf->name); printf("out_fixed_path: %s\n", out_fixed_path); FILE* fp_out1 = NULL; if ((fp_out1 = fopen(out_fixed_path, "wb+")) == NULL) { printf("fopen fail\n"); } else { //fwrite((VOID *)p_outbuf_float, sizeof(FLOAT), length, fp_out1); fwrite((VOID *)p_outbuf->va, sizeof(INT16), length, fp_out1); } if(fp_out1){ fclose(fp_out1); } #endif /* INT32 *p_idx = (INT32 *)get_post_buf(p_outbuf->channel * sizeof(INT32)); AI_NET_OUTPUT_CLASSS *p_classes = (AI_NET_OUTPUT_CLASSS *)get_post_buf(p_outbuf->batch_num * TOP_N * sizeof(AI_NET_OUTPUT_CLASSS)); parm.in_addr = (uintptr_t)p_outbuf_float; parm.classes = p_classes; parm.shape = shape; parm.top_n = TOP_N; parm.class_idx = p_idx; ret = ai_net_accuracy_process(&parm); printf("Classification Results:\r\n"); for (i = 0; i < parm.top_n; i++) { printf("%d. no=%d, label=%s, score=%f\r\n", i + 1, parm.classes[i].no, &p_net->out_class_labels[parm.classes[i].no * LABEL_LEN], parm.classes[i].score); } */ release_post_buf(p_outbuf_float); //release_post_buf(p_idx); //release_post_buf(p_classes); return ret; } #endif static HD_RESULT get_buf_by_out_path_list(NET_PATH_ID net_path) { HD_RESULT ret = HD_OK; NET_PROC* p_net = g_net + net_path; UINT32 proc_id = p_net->proc_id; UINT32 i; VENDOR_AI3_BUF ai_buf = {0}; printf("########### p_net->net_info.out_buf_cnt %d \r\n",p_net->net_info.out_buf_cnt); /* get out buf */ for (i = 0; i < p_net->net_info.out_buf_cnt; i++) { // get out buf (by out path list) ret = vendor_ai3_net_get(proc_id, p_net->net_info.out_path_list[i], &ai_buf); if (HD_OK != ret) { printf("net_path(%u), proc_id(%u) get out buf fail, i(%d), out_path(0x%x)\n", net_path, proc_id, i, p_net->net_info.out_path_list[i]); goto exit; } #if DUMP_POSTPROC_INFO { //CHAR dump_path[23]; // dump out buf if (hd_common_mem_flush_cache((VOID *)ai_buf.va, ai_buf.size) != HD_OK) { printf("flush cache failed.\r\n"); } printf("dump_out_buf: path_id: 0x%x\n", p_net->net_info.out_path_list[i]); ret = network_dump_ai_buf(&ai_buf); if (HD_OK != ret) { printf("net_path(%u) dump out buf fail !!\n", net_path); goto exit; } //snprintf(dump_path, 23, "%s.bin", ai_buf.name); //printf(" DUMP out_buf (%u): %s va = %lx\n", i, dump_path,(ULONG)p_net->out_mem[i].va); //mem_save(&p_net->out_mem[i], dump_path); ret = network_dump_out_buf(net_path, &ai_buf, i); } #endif } exit: return ret; } static HD_RESULT allocate_buf_by_out_path_list(NET_PATH_ID net_path) { HD_RESULT ret = HD_OK; NET_PROC* p_net = g_net + net_path; UINT32 proc_id = p_net->proc_id; UINT32 i; VENDOR_AI3_BUF ai_buf = {0}; CHAR mem_name[23] ; /* get out path list */ p_net->out_mem = (MEM_PARM *)malloc(sizeof(MEM_PARM) * p_net->net_info.out_buf_cnt); memset(p_net->out_mem, 0, sizeof(MEM_PARM) * p_net->net_info.out_buf_cnt); /* get out buf */ for (i = 0; i < p_net->net_info.out_buf_cnt; i++) { // get out buf (by out path list) ret = vendor_ai3_net_get(proc_id, p_net->net_info.out_path_list[i], &ai_buf); if (HD_OK != ret) { printf("proc_id(%u) get out buf fail, i(%d), out_path(0x%x)\n", proc_id, i, p_net->net_info.out_path_list[i]); goto exit; } // // allocate in buf #if FLOAT_OUT ai_buf.size = ai_buf.width * ai_buf.height * ai_buf.channel * ai_buf.batch_num *sizeof(float) ; #endif snprintf(mem_name, 23, "output_buf %u", i); ret = mem_alloc(&p_net->out_mem[i], mem_name, ai_buf.size); if (ret != HD_OK) { printf("proc_id(%u) alloc ai_in_buf fail\r\n", proc_id); goto exit; } printf("alloc_outbuf: pa = 0x%lx, va = 0x%lx, size = %u\n", p_net->out_mem[i].pa, p_net->out_mem[i].va, p_net->out_mem[i].size); } return ret; exit: for (i = 0 ; i < p_net->net_info.out_buf_cnt; i++){ if(p_net->out_mem && p_net->out_mem[i].va) mem_free(&p_net->out_mem[i]); } if(p_net->out_mem) free(p_net->out_mem) ; return ret; } static HD_RESULT network_user_start(VIDEO_LIVEVIEW *p_stream) { HD_RESULT ret = HD_OK; NET_PROC* p_net = g_net + p_stream->net_path; UINT32 proc_id = p_net->proc_id; p_stream->proc_start = 0; p_stream->proc_exit = 0; p_stream->proc_oneshot = 0; ret = vendor_ai3_net_start(proc_id); if (HD_OK != ret) { printf("net_path(%u), proc_id(%u) vendor_ai3_net_start fail !!\n", p_stream->net_path, proc_id); } ret = pthread_create(&p_stream->proc_thread_id, NULL, network_user_thread, (VOID*)(p_stream)); if (ret < 0) { return HD_ERR_FAIL; } p_stream->proc_start = 1; p_stream->proc_exit = 0; p_stream->proc_oneshot = 0; return ret; } static HD_RESULT network_user_oneshot(VIDEO_LIVEVIEW *p_stream) { HD_RESULT ret = HD_OK; p_stream->proc_oneshot = 1; return ret; } static HD_RESULT network_user_stop(VIDEO_LIVEVIEW *p_stream) { HD_RESULT ret = HD_OK; NET_PROC* p_net = g_net + p_stream->net_path; UINT32 proc_id = p_net->proc_id; p_stream->proc_exit = 1; if (p_stream->proc_thread_id) { pthread_join(p_stream->proc_thread_id, NULL); } //stop: should be call after last time proc ret = vendor_ai3_net_stop(proc_id); if (HD_OK != ret) { printf("net_path(%u), proc_id(%u) vendor_ai3_net_stop fail !!\n", p_stream->net_path, proc_id); } return ret; } static VOID *network_user_thread(VOID *arg) { HD_RESULT ret = HD_OK; VIDEO_LIVEVIEW *p_stream = (VIDEO_LIVEVIEW*)arg; NET_PROC* p_net = g_net + p_stream->net_path; UINT32 proc_id = p_net->proc_id; static struct timeval tstart, tend; static UINT64 cur_time = 0; static UINT64 all_time = 0; static float mean_time = 0; UINT32 count=0; printf("\r\n"); while (p_stream->proc_start == 0) sleep(1); printf("\r\n"); while (p_stream->proc_exit == 0) { if (p_stream->proc_oneshot) { p_stream->proc_oneshot = 0; for (count=0;count<g_proc_num;count++) { // set buf by in_path_list ret = set_buf_by_in_path_list(p_stream); if (HD_OK != ret) { printf("net_path(%u), proc_id(%u) set in_buf fail(%d) !!\n", p_stream->net_path, proc_id, ret); goto skip; } ret = set_buf_by_out_path_list(p_stream->net_path); if (HD_OK != ret) { printf("net_path(%u), proc_id(%u) set in_buf fail(%d) !!\n", p_stream->net_path, proc_id, ret); goto skip; } // do net proc gettimeofday(&tstart, NULL); if(dump_time_ut){ perf_begin(); } ret = vendor_ai3_net_proc(proc_id); if(dump_time_ut){ perf_end(); } gettimeofday(&tend, NULL); if (HD_OK != ret) { printf("net_path(%u), proc_id(%u) proc fail !!\n", p_stream->net_path, proc_id); goto skip; } //count++; cur_time = (UINT64)(tend.tv_sec - tstart.tv_sec) * 1000000 + (tend.tv_usec - tstart.tv_usec); if(count>0){ all_time+=cur_time; mean_time=all_time/(float)(count); if (dump_time_proc){ printf("count %d cur time(us): %lld all time(us): %lld mean time(us): %f \r\n",count,cur_time,all_time,mean_time); } } // printf("net_path(%u), proc_id(%u) oneshot done!\n", p_stream->net_path, proc_id); // get buf by out_path_list if (dump_output) { /* code */ ret = get_buf_by_out_path_list(p_stream->net_path); if (HD_OK != ret) { printf("net_path(%u), proc_id(%u) get out_buf fail(%d) !!\n", p_stream->net_path, proc_id, ret); goto skip; } } } printf("count %d cur time(us): %lld all time(us): %lld mean time(us): %f \r\n",count,cur_time,all_time,mean_time); } usleep(100); } skip: return 0; } /*-----------------------------------------------------------------------------*/ /* Interface Functions */ /*-----------------------------------------------------------------------------*/ MAIN(argc, argv) { VIDEO_LIVEVIEW stream[1] = {0}; HD_COMMON_MEM_INIT_CONFIG mem_cfg = {0}; HD_RESULT ret; INT key; UINT32 j; INT32 idx; #if FLOAT_IN stream[0].input_blob_num = 1; //net_in NET_IN_CONFIG in_cfg = { .input_filename = "/mnt/sd/jpg/float32.bin", .w = 74, .h = 1, .c = 40, .b = 1, .bitdepth = 32, .loff = 296, .fmt = HD_VIDEO_PXLFMT_AI_FLOAT32, .is_comb_img = 1, }; NET_IN_CONFIG in_cfg2 = { .input_filename = "NULL", .w = 0, .h = 0, .c = 0, .b = 0, .bitdepth = 0, .loff = 0, .fmt = 0, .is_comb_img = 0, }; //net proc NET_PROC_CONFIG net_cfg = { .model_filename = "/mnt/sd/para/nvt_model_float32.bin", .label_filename = "/mnt/sd/accuracy/labels.txt" }; #elif MULTI_BATCH_IN /* multi-blob with multi-batch */ stream[0].input_blob_num = 2; //net_in NET_IN_CONFIG in_cfg = { .input_filename = "/mnt/sd/jpg/mblob_mbatch_0.yuv", .w = 12, .h = 12, .c = 2, .b = 8, .bitdepth = 8, .loff = 12, .fmt = HD_VIDEO_PXLFMT_YUV420, .is_comb_img = 1, }; NET_IN_CONFIG in_cfg2 = { .input_filename = "/mnt/sd/jpg/mblob_mbatch_1.bin", .w = 1, .h = 1, .c = 5, .b = 8, .bitdepth = 16, .loff = 2, .fmt = 0xA2101000, .is_comb_img = 1, }; //net proc NET_PROC_CONFIG net_cfg = { .model_filename = "/mnt/sd/para/nvt_model_mblob_mbatch.bin", .label_filename = "/mnt/sd/accuracy/labels.txt" }; #else stream[0].input_blob_num = 3; //net_in NET_IN_CONFIG in_cfg1 = { .input_filename = "/mnt/sd/jpg/mblob.bin", .w = 224, .h = 224, .c = 2, .b = 1, .bitdepth = 8, .loff = 224, .fmt = HD_VIDEO_PXLFMT_YUV420, .is_comb_img = 0, }; NET_IN_CONFIG in_cfg2 = { .input_filename = "/mnt/sd/jpg/mblob.bin", .w = 224, .h = 224, .c = 2, .b = 1, .bitdepth = 8, .loff = 224, .fmt = HD_VIDEO_PXLFMT_YUV420, .is_comb_img = 0, }; NET_IN_CONFIG in_cfg3 = { .input_filename = "/mnt/sd/jpg/mblob.bin", .w = 224, .h = 224, .c = 2, .b = 1, .bitdepth = 8, .loff = 224, .fmt = HD_VIDEO_PXLFMT_YUV420, .is_comb_img = 0, }; //net proc NET_PROC_CONFIG net_cfg = { .model_filename = "/mnt/sd/para/nvt_model_mblob.bin", .label_filename = "/mnt/sd/accuracy/labels.txt" }; #endif // End of #if MULTI_BATCH_IN if(argc < 4){ printf("usage : ai3_net_with_mblob (proc_num) (model_path) (input_blob_num)\n"); printf("usage : (MPROCESS_FOR_AIISP)\n"); printf("usage : (dump_time_UT)\n"); printf("usage : (dump_time_proc)\n"); printf("usage : (dump_output)\n"); printf("usage : (dump_path)\n"); printf("usage : (input_data_path1) (input_w) (input_h) (input_c) (input_b) (input_bitdepth) (input_loff) (input_fmt_10) (input_is_comb_img)\n"); printf("usage : (input_data_path2) (input_w) (input_h) (input_c) (input_b) (input_bitdepth) (input_loff) (input_fmt_10) (input_is_comb_img)\n"); printf("usage : (input_data_path2) (input_w) (input_h) (input_c) (input_b) (input_bitdepth) (input_loff) (input_fmt_10) (input_is_comb_img)\n"); return -1; } printf("\r\n\r\n"); idx = 1; UINT32 proc_num = 0; UINT32 input_blob_num = 0; { if (argc > idx) { sscanf(argv[idx++], "%d", &proc_num); printf("proc_num: %d\n", proc_num); g_proc_num=proc_num; } if (argc > idx) { sscanf(argv[idx++], "%s", net_cfg.model_filename); printf("net_cfg.model_filename: %s\n", net_cfg.model_filename); } if (argc > idx) { sscanf(argv[idx++], "%d", &input_blob_num); printf("input_blob_num: %d\n", input_blob_num); stream[0].input_blob_num=input_blob_num; } if (argc > idx) { sscanf(argv[idx++], "%d", &MPROCESS_FOR_AIISP); printf("MPROCESS_FOR_AIISP : %d\n", MPROCESS_FOR_AIISP); } if (argc > idx) { sscanf(argv[idx++], "%d", &dump_time_ut); printf("dump_time_ut: %d\n", dump_time_ut); } if (argc > idx) { sscanf(argv[idx++], "%d", &dump_time_proc); printf("dump_time_proc: %d\n", dump_time_proc); } if (argc > idx) { sscanf(argv[idx++], "%d", &dump_output); printf("dump_output: %d\n", dump_output); } if (argc > idx) { sscanf(argv[idx++], "%s", dump_path); printf("dump_path: %s\n", dump_path); } if (argc > idx) { sscanf(argv[idx++], "%s", in_cfg1.input_filename); printf("in_cfg1.input_filename: %s\n", in_cfg1.input_filename); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg1.w)); printf("(in_cfg1.w): %d\n", (in_cfg1.w)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg1.h)); printf("(in_cfg1.h): %d\n", (in_cfg1.h)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg1.c)); printf("(in_cfg1.c): %d\n", (in_cfg1.c)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg1.b)); printf("(in_cfg1.b): %d\n", (in_cfg1.b)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg1.bitdepth)); printf("(in_cfg1.bitdepth): %d\n", (in_cfg1.bitdepth)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg1.loff)); printf("(in_cfg1.loff): %d\n", (in_cfg1.loff)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg1.fmt)); printf("(in_cfg1.fmt): %d\n", (in_cfg1.fmt)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg1.is_comb_img)); printf("(in_cfg1.is_comb_img): %d\n", (in_cfg1.is_comb_img)); } if (argc > idx) { sscanf(argv[idx++], "%s", in_cfg2.input_filename); printf("in_cfg2.input_filename: %s\n", in_cfg2.input_filename); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg2.w)); printf("(in_cfg2.w): %d\n", (in_cfg2.w)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg2.h)); printf("(in_cfg2.h): %d\n", (in_cfg2.h)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg2.c)); printf("(in_cfg2.c): %d\n", (in_cfg2.c)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg2.b)); printf("(in_cfg2.b): %d\n", (in_cfg2.b)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg2.bitdepth)); printf("(in_cfg2.bitdepth): %d\n", (in_cfg2.bitdepth)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg2.loff)); printf("(in_cfg2.loff): %d\n", (in_cfg2.loff)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg2.fmt)); printf("(in_cfg2.fmt): %d\n", (in_cfg2.fmt)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg2.is_comb_img)); printf("(in_cfg2.is_comb_img): %d\n", (in_cfg2.is_comb_img)); } // cfg3 if (argc > idx) { sscanf(argv[idx++], "%s", in_cfg3.input_filename); printf("in_cfg3.input_filename: %s\n", in_cfg3.input_filename); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg3.w)); printf("(in_cfg3.w): %d\n", (in_cfg3.w)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg3.h)); printf("(in_cfg3.h): %d\n", (in_cfg3.h)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg3.c)); printf("(in_cfg3.c): %d\n", (in_cfg3.c)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg3.b)); printf("(in_cfg3.b): %d\n", (in_cfg3.b)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg3.bitdepth)); printf("(in_cfg3.bitdepth): %d\n", (in_cfg3.bitdepth)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg3.loff)); printf("(in_cfg3.loff): %d\n", (in_cfg3.loff)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg3.fmt)); printf("(in_cfg3.fmt): %d\n", (in_cfg3.fmt)); } if (argc > idx) { sscanf(argv[idx++], "%d", &(in_cfg3.is_comb_img)); printf("(in_cfg3.is_comb_img): %d\n", (in_cfg3.is_comb_img)); } } // malloc for g_in & g_net g_in = (NET_IN *)malloc(sizeof(NET_IN)*16); g_net = (NET_PROC *)malloc(sizeof(NET_PROC)*16); if ((g_in == NULL) || (g_net == NULL)) { printf("fail to malloc g_in/g_net\n"); goto exit; } stream[0].in_path = 0; stream[0].net_path = 0; // init hdal if(MPROCESS_FOR_AIISP){ ret = hd_common_init(1); // multi-process for aiisp }else{ ret = hd_common_init(0); } //this is no longer need in 690 /* #if defined(_BSP_NS02201_) || defined(_BSP_NS02302_) // set project config for AI hd_common_sysconfig(0, (1<<16), 0, VENDOR_AI_CFG); //enable AI engine #endif */ // init mem { // config common pool network_mem_config(stream[0].net_path, &mem_cfg, &net_cfg); } #if defined(_BSP_NS02201_) || defined(_BSP_NS02302_) if(MPROCESS_FOR_AIISP){ ret = hd_common_mem_init(NULL); // multi-process for aiisp }else{ ret = hd_common_mem_init(&mem_cfg); } if (HD_OK != ret) { printf("hd_common_mem_init err: %d\r\n", ret); goto exit; } #endif // init all modules ret = init_module(); if (ret != HD_OK) { printf("init fail=%d\n", ret); goto exit; } // set open config for (j=0; j < stream[0].input_blob_num; j++) { if (j == 0) { ret = input_set_config((stream[0].in_path + j), &in_cfg1); } else if (j == 1) { ret = input_set_config((stream[0].in_path + j), &in_cfg2); } else if (j == 2) { ret = input_set_config((stream[0].in_path + j), &in_cfg3); } if (HD_OK != ret) { printf("in_path(%u) input_set_config fail=%d\n", (stream[0].in_path + j), ret); goto exit; } } // open video_liveview modules for(j=0; j < stream[0].input_blob_num; j++) { ret = input_open((stream[0].in_path + j)); if (ret != HD_OK) { printf("in_path(%u) input open fail=%d\n", (stream[0].in_path + j), ret); goto exit; } } ret = open_module(&stream[0]); if (ret != HD_OK) { printf("open fail=%d\n", ret); goto exit; } // start input_start(stream[0].in_path); network_user_start(&stream[0]); allocate_buf_by_out_path_list(stream[0].net_path); do { printf("Enter q to exit, r to run once\n"); key = GETCHAR(); if (key == 'r') { // run once network_user_oneshot(&stream[0]); continue; } if (key == 'q' || key == 0x3) { break; } } while(1); // stop input_stop(stream[0].in_path); network_user_stop(&stream[0]); exit: // close video_liveview modules ret = close_module(&stream[0]); if (ret != HD_OK) { printf("close fail=%d\n", ret); } for(j=0; j < stream[0].input_blob_num; j++) { ret = input_close((stream[0].in_path + j)); if (ret != HD_OK) { printf("in_path(%u) input close fail=%d\n", (stream[0].in_path + j), ret); goto exit; } } // uninit all modules ret = exit_module(); if (ret != HD_OK) { printf("exit fail=%d\n", ret); } #if defined(_BSP_NS02201_) || defined(_BSP_NS02302_) // uninit memory ret = hd_common_mem_uninit(); if (ret != HD_OK) { printf("mem fail=%d\n", ret); } #endif // uninit hdal ret = hd_common_uninit(); if (ret != HD_OK) { printf("common fail=%d\n", ret); } // free g_in & g_net if (g_in) free(g_in); if (g_net) free(g_net); return ret; }
最新发布
11-01
这段代码是一个基于STM32F407的控制循环,用于实现多电机的PID调速控制。以下是对代码的分析及优化建议: ### 代码分析 1. **定时控制**:通过定时器(TIM6)获取当前时间戳,实现10ms的固定间隔控制循环。 2. **速度获取与转换**:从编码器获取原始速度值,并转换为RPM单位。 3. **目标速度设置**:为4个电机(A、B、C、D)分别设置目标速度(A/B为65RPM,C/D为1RPM)。 4. **PID计算与限幅**:对每个电机进行PID计算,并将输出限制在0%~100%范围内。 5. **电机控制**:将计算后的PWM占空比输出到对应电机。 ### 优化建议 1. **硬件定时器配置**: - 确保TIM6已正确配置为1ms中断(或更短),并在中断中递增计数器。 - 示例配置(基于HAL库): ```c TIM_HandleTypeDef htim6; htim6.Instance = TIM6; htim6.Init.Prescaler = 84-1; // 84MHz/84 = 1MHz htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = 1000-1; // 1ms中断 HAL_TIM_Base_Init(&htim6); HAL_TIM_Base_Start_IT(&htim6); ``` 2. **编码器接口配置**: - 使用STM32F407的硬件编码器接口(TIM2-TIM5)直接读取编码器值。 - 示例配置(TIM2作为编码器接口): ```c TIM_Encoder_InitTypeDef encoderConfig; TIM_MasterConfigTypeDef masterConfig; htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 0xFFFF; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; encoderConfig.EncoderMode = TIM_ENCODERMODE_TI12; encoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING; encoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; encoderConfig.IC1Prescaler = TIM_ICPSC_DIV1; encoderConfig.IC1Filter = 0; encoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING; encoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; encoderConfig.IC2Prescaler = TIM_ICPSC_DIV1; encoderConfig.IC2Filter = 0; HAL_TIM_Encoder_Init(&htim2, &encoderConfig); masterConfig.MasterOutputTrigger = TIM_TRGO_RESET; masterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronization(&htim2, &masterConfig); HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL); ``` 3. **PID参数整定**: - 需要根据实际电机特性调整PID参数(比例、积分、微分系数)。 - 建议通过实验法或Ziegler-Nichols方法整定参数。 4. **速度单位转换**: - `Convert_To_RPM()`函数需根据编码器分辨率和电机减速比实现: ```c float Convert_To_RPM(int32_t encoderCount) { static int32_t lastCount = 0; static uint32_t lastTime = 0; uint32_t now = HAL_GetTick(); uint32_t dt = now - lastTime; if (dt == 0) return 0; int32_t delta = encoderCount - lastCount; lastCount = encoderCount; lastTime = now; // 假设编码器每转产生PPR脉冲,电机减速比为GEAR_RATIO const float PPR = 1000.0f; // 编码器每转脉冲数 const float GEAR_RATIO = 50.0f; float rpm = (delta * 60000.0f) / (PPR * GEAR_RATIO * dt); return rpm; } ``` 5. **PWM输出配置**: - 使用TIM1或TIM8的高级定时器(带互补输出)或通用定时器(如TIM3-TIM5)生成PWM。 - 示例配置(TIM3通道1作为PWM输出): ```c TIM_OC_InitTypeDef pwmConfig; htim3.Instance = TIM3; htim3.Init.Prescaler = 84-1; // 1MHz计数频率 htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 1000-1; // 1kHz PWM频率(100% = 1000) htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim3); pwmConfig.OCMode = TIM_OCMODE_PWM1; pwmConfig.Pulse = 0; pwmConfig.OCPolarity = TIM_OCPOLARITY_HIGH; pwmConfig.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim3, &pwmConfig, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); ``` ### 完整优化代码框架 ```c // 全局变量 PID_TypeDef PIDA, PIDB, PIDC, PIDD; void Control_Loop(void) { static uint32_t last_tick = 0; const uint32_t interval = 10; // 10ms uint32_t now = HAL_GetTick(); if (now - last_tick >= interval) { last_tick = now; // 1. 获取并转换速度 float SpeedA = Convert_To_RPM((int32_t)TIM2->CNT); float SpeedB = Convert_To_RPM((int32_t)TIM3->CNT); float SpeedC = Convert_To_RPM((int32_t)TIM4->CNT); float SpeedD = Convert_To_RPM((int32_t)TIM5->CNT); // 2. 设置目标速度 float targetA = 65.0f, targetB = 65.0f; float targetC = 1.0f, targetD = 1.0f; // 3. PID计算与限幅 float outA = clamp_float(pid_calculate(&PIDA, SpeedA, targetA), 0, 100); float outB = clamp_float(pid_calculate(&PIDB, SpeedB, targetB), 0, 100); float outC = clamp_float(pid_calculate(&PIDC, SpeedC, targetC), 0, 100); float outD = clamp_float(pid_calculate(&PIDD, SpeedD, targetD), 0, 100); // 4. 更新PWM输出 __HAL_TIM_SET_COMPARE(&htim_motorA, TIM_CHANNEL_1, (uint16_t)(outA * 10)); __HAL_TIM_SET_COMPARE(&htim_motorB, TIM_CHANNEL_1, (uint16_t)(outB * 10)); __HAL_TIM_SET_COMPARE(&htim_motorC, TIM_CHANNEL_1, (uint16_t)(outC * 10)); __HAL_TIM_SET_COMPARE(&htim_motorD, TIM_CHANNEL_1, (uint16_t)(outD * 10)); } } ``` ### 注意事项 1. 确保所有外设(TIM6、编码器定时器、PWM定时器)已正确初始化。 2. 根据实际硬件连接修改PWM输出的定时器和通道。 3. 在调试阶段,建议通过串口输出实际速度和PWM值,便于监控和调参。 ### 扩展功能建议 1. 添加急停功能(通过检测紧急按钮输入)。 2. 实现速度斜坡功能,避免目标速度突变导致的冲击。 3. 添加通信接口(如UART或CAN)实现动态参数调整。 通过以上优化,可以显著提高控制系统的精度和稳定性。实际实现时需根据具体硬件配置调整参数和接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值