TIM-VX编译体验

TIM-VX是VIP开发维护的开源项目,作用是作为后段将开源框架和VIP的ML加速器进行整合绑定,对VIP 提高其NPU的应用领域,扩大应用生态具有巨大作用,其官方介绍如下:

下载代码:

github仓库地址:GitHub - VeriSilicon/TIM-VX: Verisilicon Tensor Interface Module

实际代码量并不多,包含仓库在内共有87M。

编译

TIM-VX支持BAZEL和CMAKE两种构建系统,先用CMAKE尝试编译一下,编译顺序命令如下:

mkdir host_build
cd host_build
cmake ..
make -j8
make install

首先遇到了编译错误,是CMAKE版本太低导致

升级CMAKE

cmake的下载在这里​​​​​​https://github.com/Kitware/CMake/releases/download/v3.23.0/cmake-3.23.0.tar.gz

首先卸载系统自带CMAKE

sudo apt purge cmake

cmake编译遵照标准的Linux下源码包编译的三部曲

编译TIM-VX

配置成功:

编译:

安装:

sudo make install

安装目录包含两种文件,分别是库和头文件

TIM-VX要基于UNIFY SDK运行,但是X86主机环境下没有NPU,所以为了支撑TIM-VX在系统层面的运行,TIM-VX提供了pre-build的RUNTIME库仿真器件。

编译测试用例:

配置后编译:

cmake -DTIM_VX_ENABLE_TEST=ON ../

导出环境变量

export LD_LIBRARY_PATH=$PWD/../../../prebuilt-sdk/x86_64_linux/lib:/home/caozilong/Workspace/TIM-VX/host_build/lib:$LD_LIBRARY_PATH
export VIVANTE_SDK_DIR=`pwd`/../../../prebuilt-sdk/x86_64_linux/lib
export VSIMULATOR_CONFIG=czl
export DISABLE_IDE_DEBUG=1

之后运行./unit_test,出现段错误:

cl_viv_vx_ext.h是一个在线编译头文件,它的位置在

需要将其拷贝到VIVANTE_SDK_DIR指定的目标地址:

mkdir prebuilt-sdk/x86_64_linux/lib/include
cp prebuilt-sdk/x86_64_linux/include/CL prebuilt-sdk/x86_64_linux/lib/include -fr

再次执行unit_test不再有段错误

编译用例

cmake -DTIM_VX_ENABLE_TEST=ON -DTIM_VX_BUILD_EXAMPLES=ON ../

 编译后生成EXAMPLE目录

 执行LENET用例,打印TOP5输出。


结束

#include "app_motor.h" extern volatile int32_t gEncoderCount_L,gEncoderCount_R; pid_t pid_motor[2]; int Encoder_speed_offset[2] = {0}; int Encoder_speed_last[2] = {0}; int Encoder_speed_now[2] = {0}; uint8_t g_start_ctrl = 0; car_data_t car_data; motor_data_t motor_data; // 获取开机到现在总共的四路编码器计数。 void Encoder_Get_ALL(int* Encoder_all) { Encoder_all[0] -= gEncoderCount_L; Encoder_all[1] += gEncoderCount_R; gEncoderCount_L = 0;//清0 gEncoderCount_R = 0;//清0 } // 获取编码器数据,并计算偏差脉冲数 void Motion_Get_Encoder(void) { Encoder_Get_ALL(Encoder_speed_now); for(uint8_t i = 0; i < Motor_MAX; i++) { // 记录两次测试时间差的脉冲数 Encoder_speed_offset[i] = Encoder_speed_now[i] - Encoder_speed_last[i]; // 记录上次编码器数据 Encoder_speed_last[i] = Encoder_speed_now[i]; } } //返回编码器脉冲 static float Motion_Get_Circle_Pulse(void) { return ENCODER_CIRCLE_450; } // 返回当前小车轮子轴间距和的一半 static float Motion_Get_APB(void) { return STM32Car_APB; } // 返回当前小车轮子转一圈的多少毫米 static float Motion_Get_Circle_MM(void) { return WHEEL_CIRCLE_MM; } void Motor_PID_Init(void) { for (int i = 0; i < Motor_MAX; i++) { pid_motor[i].target_val = 0.0; pid_motor[i].pwm_output = 0.0; pid_motor[i].err = 0.0; pid_motor[i].err_last = 0.0; pid_motor[i].err_next = 0.0; pid_motor[i].integral = 0.0; pid_motor[i].Kp = MOTOR_P; pid_motor[i].Ki = MOTOR_I; pid_motor[i].Kd = MOTOR_D; } } // 设置PID目标速度,单位为:mm/s void PID_Set_Motor_Target(uint8_t motor_id, float target) { if (motor_id > Motor_MAX) return; if (motor_id == Motor_MAX) { for (int i = 0; i < Motor_MAX; i++) { pid_motor[i].target_val = target; } } else { pid_motor[motor_id].target_val = target; } } // 清除PID数据 void PID_Clear_Motor(uint8_t motor_id) { if (motor_id > Motor_MAX) return; if (motor_id == Motor_MAX) { for (int i = 0; i < Motor_MAX; i++) { pid_motor[i].pwm_output = 0.0; pid_motor[i].err = 0.0; pid_motor[i].err_last = 0.0; pid_motor[i].err_next = 0.0; pid_motor[i].integral = 0.0; } } else { pid_motor[motor_id].pwm_output = 0.0; pid_motor[motor_id].err = 0.0; pid_motor[motor_id].err_last = 0.0; pid_motor[motor_id].err_next = 0.0; pid_motor[motor_id].integral = 0.0; } } // 增量式PID计算公式 float PID_Incre_Calc(pid_t *pid, float actual_val) { /*计算目标值与实际值的误差*/ pid->err = pid->target_val - actual_val; /*PID算法实现*/ pid->pwm_output += pid->Kp *(pid->err - pid->err_next) + pid->Ki * pid->err + pid->Kd *(pid->err - 2 * pid->err_next + pid->err_last); /*传递误差*/ pid->err_last = pid->err_next; pid->err_next = pid->err; /*返回PWM输出值*/ if (pid->pwm_output > (MOTOR_MAX_PULSE-MOTOR_IGNORE_PULSE)) pid->pwm_output = (MOTOR_MAX_PULSE-MOTOR_IGNORE_PULSE); if (pid->pwm_output < (MOTOR_IGNORE_PULSE-MOTOR_MAX_PULSE)) pid->pwm_output = (MOTOR_IGNORE_PULSE-MOTOR_MAX_PULSE); return pid->pwm_output; } // PID计算输出值 void PID_Calc_Motor(motor_data_t* motor) { int i; for (i = 0; i < Motor_MAX; i++) { motor->speed_pwm[i] = PID_Incre_Calc(&pid_motor[i], motor->speed_mm_s[i]); } } void Motion_Set_Speed(int16_t speed_m1, int16_t speed_m2) { if(speed_m1 == 0 && speed_m2 == 0) { Motion_Stop(); } else { //因为有毛刺,编码器不一定为0,根据pid会进行控制,会导致停止不了。 //所以产生if g_start_ctrl = 1; } motor_data.speed_set[0] = speed_m1; motor_data.speed_set[1] = speed_m2; for (uint8_t i = 0; i < Motor_MAX; i++) { PID_Set_Motor_Target(i, motor_data.speed_set[i]*1.0); } } // 从编码器读取当前各轮子速度,单位mm/s void Motion_Get_Speed(car_data_t* car) { int i = 0; float speed_mm[Motor_MAX] = {0}; float circle_mm = Motion_Get_Circle_MM(); float circle_pulse = Motion_Get_Circle_Pulse(); float robot_APB = Motion_Get_APB(); Motion_Get_Encoder(); // 计算轮子速度,单位mm/s。 for (i = 0; i < 2; i++) { speed_mm[i] = (Encoder_speed_offset[i]) * 100 * circle_mm / circle_pulse; } car->Vx = (speed_mm[0] + speed_mm[1]) / 2.0f; car->Vy = 0; car->Vz = -(speed_mm[0] - speed_mm[1] ) / 2.0f / robot_APB * 1000; if (g_start_ctrl) { PID_Calc_Motor(&motor_data); } } // 小车停止 void Motion_Stop(void) { Motion_Set_Speed(0,0); PID_Clear_Motor(Motor_MAX); g_start_ctrl = 0; Motion_Set_Pwm(0,0); } static float speed_lr = 0; static float speed_fb = 0; static float speed_spin = 0; static int speed_L1_setup = 0; static int speed_L2_setup = 0; static int speed_R1_setup = 0; static int speed_R2_setup = 0; void wheel_Ctrl(int16_t V_x, int16_t V_y, int16_t V_z) //巡线PID直接输出此值 { float robot_APB = Motion_Get_APB(); // speed_lr = -V_y; speed_lr = 0; speed_fb = V_x; speed_spin = (V_z / 1000.0f) * robot_APB; if (V_x == 0 && V_y == 0 && V_z == 0) { Motion_Stop(); return; } speed_L1_setup = speed_fb + speed_lr + speed_spin; speed_R1_setup = speed_fb - speed_lr - speed_spin; if (speed_L1_setup > 1000) speed_L1_setup = 1000; if (speed_L1_setup < -1000) speed_L1_setup = -1000; if (speed_R1_setup > 1000) speed_R1_setup = 1000; if (speed_R1_setup < -1000) speed_R1_setup = -1000; //printf("%d\t,%d\t,%d\t,%d\r\n",speed_L1_setup,speed_L2_setup,speed_R1_setup,speed_R2_setup); Motion_Set_Speed(speed_L1_setup, speed_R1_setup); } // 运动控制句柄,每10ms调用一次,主要处理速度相关的数据 void Motion_Handle(void) { Motion_Get_Speed(&car_data); if (g_start_ctrl) { Motion_Set_Pwm(motor_data.speed_pwm[0], motor_data.speed_pwm[1]); } } //直接控制pwm void motion_car_control(int16_t V_x, int16_t V_y, int16_t V_z) { float robot_APB = Motion_Get_APB(); speed_lr = 0; speed_fb = V_x; speed_spin = (V_z / 1000.0f) * robot_APB; if (V_x == 0 && V_y == 0 && V_z == 0) { Motion_Set_Pwm(0,0); return; } speed_L1_setup = speed_fb + speed_spin; speed_R1_setup = speed_fb - speed_spin; if (speed_L1_setup > 1000) speed_L1_setup = 1000; if (speed_L1_setup < -1000) speed_L1_setup = -1000; if (speed_R1_setup > 1000) speed_R1_setup = 1000; if (speed_R1_setup < -1000) speed_R1_setup = -1000; //printf("%d\t,%d\t,%d\t,%d\r\n",speed_L1_setup,speed_L2_setup,speed_R1_setup,speed_R2_setup); Motion_Set_Pwm(speed_L1_setup, speed_R1_setup); } 帮我看看哪儿错了,并在此基础上修改
最新发布
07-26
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

papaofdoudou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值