小车跟随行驶系统(基于MSP-EXP430F5529LP系统板)

2023-05-16

选用材料:主控板MSP-EXP430F5529LP、陀螺仪、直流减速电机(可以选用光电编码器,霍尔电机不好调节PID)、TB6612电机驱动、超声波测距模块、灰度传感器、无线透传/蓝牙模块(便于两辆小车相互发送信息)、OLED屏等。

总体思路:使用灰度传感器巡线,超声波检测前后车距,通过调节PID的位置环,控制两辆小车前后的距离,运用JY901进行陀螺仪矫正。

2022TI_C1_JY901.c

#include "2022TI_C1_JY901.h"

struct SAngle Mpu_angle;

//串口0初始化
void Usart0Init(void)
{
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3, GPIO_PIN4);
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P3, GPIO_PIN3);

    //Baudrate = 115200, clock freq = 25MHz
    //在线计算器
    //https://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html
    USCI_A_UART_initParam param = {0};
    param.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;
    param.clockPrescalar = 13;
    param.firstModReg = 9;
    param.secondModReg = 0;
    param.parity = USCI_A_UART_NO_PARITY;
    param.msborLsbFirst = USCI_A_UART_LSB_FIRST;
    param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
    param.uartMode = USCI_A_UART_MODE;
    param.overSampling = USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION;


    if (STATUS_FAIL == USCI_A_UART_init(USCI_A0_BASE, &param))
    {
        return;
    }

    //Enable UART module for operation
    USCI_A_UART_enable(USCI_A0_BASE);

    //Enable Receive Interrupt
    USCI_A_UART_clearInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
    USCI_A_UART_enableInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(USCI_A0_VECTOR)))
#endif
void USCI_A0_ISR (void)
{
//    uint8_t receivedData = 0;

    switch (__even_in_range(UCA0IV,4))
    {
        //Vector 2 - RXIFG
        case 2:
            CopeSerial2Data(USCI_A0_BASE);
//            receivedData = USCI_A_UART_receiveData(USCI_A0_BASE);
            break;
        default: break;
    }
}

//发送N个字节长度的数据
void USART0_Send(uint8_t *pui8Buffer, uint32_t ui32Count)
{
  while(ui32Count--)
  {
      USCI_A_UART_transmitData(USCI_A0_BASE, *pui8Buffer++);
  }
}

void CopeSerial2Data(uint16_t baseAddress)
{
    static unsigned char ucRxBuffer[250];
    static unsigned char ucRxCnt = 0;
    unsigned char i,sum;

    ucRxBuffer[ucRxCnt++]=USCI_A_UART_receiveData(baseAddress);;   //将收到的数据存入缓冲区中

    if (ucRxBuffer[0]!=0x55) //数据头不对,则重新开始寻找0x55数据头
    {
        ucRxCnt=0;
        return;
    }
    if (ucRxCnt<11) {return;}//数据不满11个,则返回
    else
    {
        switch(ucRxBuffer[1])//三轴角度
        {
            case 0x53:
                memcpy(&Mpu_angle,&ucRxBuffer[2],8);
                for(i=0; i<10; i++)
                    sum += ucRxBuffer[i];

                if(sum == ucRxBuffer[10])
                {
                    Mpu_angle.angle_z=  (float)Mpu_angle.Angle[2]/32768*180;//Z
                    Mpu_angle.angle_y = (float)Mpu_angle.Angle[0]/32768*180;//Y
                    Mpu_angle.angle_x = (float)Mpu_angle.Angle[1]/32768*180;//X

                }
//                memcpy(&Mpu_angle,&ucRxBuffer[2],8);
//                Mpu_angle.angle_z=  (float)Mpu_angle.Angle[2]/32768*180;//Z
//                Mpu_angle.angle_y = (float)Mpu_angle.Angle[0]/32768*180;//Y
//                Mpu_angle.angle_x = (float)Mpu_angle.Angle[1]/32768*180;//X
            break;
            default:break;
        }
        ucRxCnt=0;//清空缓存区
    }
}

2022TI_C1_JY901.h

#ifndef __2022TI_C1_JY901_H_
#define __2022TI_C1_JY901_H_

#include <includes.h>


struct SAngle
{
    short Angle[3];
    short T;
    float angle_x;
    float angle_y;
    float angle_z;
};

extern struct SAngle Mpu_angle;

//串口0初始化
void Usart0Init(void);
void USART0_Send(uint8_t *pui8Buffer, uint32_t ui32Count);

void CopeSerial2Data(uint16_t baseAddress);

#endif /* JY901_H_ */

2022TI_C1_SR04.c

#include "2022TI_C1_SR04.h"

float sr04_dist = 0.0;
uint32_t Sign_Counts = 0;//脉冲宽度(高) us

//启动测量
void SR04_Start(void)
{
    GPIO_setOutputHighOnPin(GPIO_PORT_P7, GPIO_PIN4);
    delay_us(50);
    GPIO_setOutputLowOnPin(GPIO_PORT_P7, GPIO_PIN4);
}

//SR04 trig p7.4
//SR04 echo p2.5
void Timer_A2_Capture_Init(void)
{
    Timer_A_initContinuousModeParam htim = {0};
    htim.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
    htim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
    htim.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;
    htim.timerClear = TIMER_A_DO_CLEAR;
    htim.startTimer = true;
    Timer_A_initContinuousMode(TIMER_A2_BASE, &htim);

    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2, GPIO_PIN5);
    Timer_A_initCaptureModeParam capture_htim = {0};
    capture_htim.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;
    capture_htim.captureMode = TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE;
    capture_htim.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;
    capture_htim.synchronizeCaptureSource = TIMER_A_CAPTURE_SYNCHRONOUS;
    capture_htim.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;
    capture_htim.captureOutputMode = TIMER_A_OUTPUTMODE_OUTBITVALUE;
    Timer_A_initCaptureMode(TIMER_A2_BASE,&capture_htim);

    GPIO_setAsOutputPin(GPIO_PORT_P7, GPIO_PIN4);
    GPIO_setOutputLowOnPin(GPIO_PORT_P7, GPIO_PIN4);
    GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN5);
}

#pragma vector=TIMER2_A1_VECTOR
__interrupt
void TIMER2_A1_ISR (void)
{
    static uint16_t Overflow_Times = 0;
    static uint16_t Sign_Begin = 0, Sign_End = 0;

    switch(TA2IV)
    {
        case TA2IV_TACCR2:
            if(GPIO_getInputPinValue(GPIO_PORT_P2,GPIO_PIN5))
            {
                Sign_Begin = Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);
            }
            else
            {
                Sign_End = Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);
                if(!Overflow_Times)
                    Sign_Counts = Sign_End - Sign_Begin;
                else
                {
                    Sign_Counts = (uint32_t)65536 * Overflow_Times + Sign_End - Sign_Begin;
                    Overflow_Times = 0;
                }

                //25MHZ
                //计数周期 1/25 us 340M/S
                sr04_dist = 0.04 *0.34 * Sign_Counts / 2.0;//mm
            }
            Timer_A_clearCaptureCompareInterrupt(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);
            break;
        case TA2IV_TAIFG:
            if(GPIO_getInputPinValue(GPIO_PORT_P2,GPIO_PIN5))
            {
                ++Overflow_Times;
            }
            else
                Overflow_Times = 0;
            Timer_A_clearTimerInterrupt(TIMER_A2_BASE);
            break;
        default:
            break;
    }
}

2022TI_C1_SR04.h

#ifndef __2022TI_C1_SR04__H
#define __2022TI_C1_SR04__H

#include <includes.h>

extern float sr04_dist;
extern uint32_t Sign_Counts;

void SR04_Start(void);

void Timer_A2_Capture_Init(void);

#endif 

2022TI_C1_PID.c

#include "2022TI_C1_PID.h"

PID M3508_spid[2];
PID ANGLE;
PID distance;
float abs_limit(float a, float ABS_MAX)
{
	if(a > ABS_MAX)
		a = ABS_MAX;

	if(a < -ABS_MAX)
		a = -ABS_MAX;
	return a;
}

void PID_Position_Calc( PID *pp,  float  CurrentPoint,  float NextPoint )  
{   
	pp->Error =  NextPoint -  CurrentPoint;          
	pp->SumError += pp->Error;                      
	pp->DError = pp->Error - pp->LastError;

	pp->output =  pp->Proportion * pp->Error +   \
								abs_limit(pp->Integral * pp->SumError, pp->Integralmax ) +   \
								pp->Derivative * pp->DError ;  

	if(pp->output > pp->outputmax )  pp->output = pp->outputmax;
	if(pp->output < - pp->outputmax )  pp->output = -pp->outputmax;
//	pp->PrevError = pp->LastError;  
	pp->LastError = pp->Error;
}

void PID_Incremental_Calc( PID *pp,  float  CurrentPoint,  float NextPoint )  
{  
	pp->Error =  NextPoint -  CurrentPoint;          
	pp->SumError += pp->Error;                      
	pp->DError = pp->Error - pp->LastError;

	pp->output +=  pp->Proportion * ( pp->Error - pp->LastError )+   \
								 abs_limit(pp->Integral * pp->Error, pp->Integralmax ) +   \
								 pp->Derivative * ( pp->Error +  pp->PrevError - 2*pp->LastError);  

	if(pp->output > pp->outputmax )  pp->output = pp->outputmax;
	if(pp->output < - pp->outputmax )  pp->output = -pp->outputmax;
	pp->PrevError = pp->LastError;  
	pp->LastError = pp->Error;
}

void PIDInit(PID *pp, float Kp , float Ki , float Kd ,  float outputmax, float Integralmax)  
{  
	pp->Integralmax = Integralmax;
	pp->outputmax  = outputmax;
	pp->Proportion = Kp;
	pp->Integral   = Ki;
	pp->Derivative = Kd;
	pp->DError = pp->Error = pp->output = pp->LastError = pp->PrevError = 0; 
}  

2022TI_C1_PID.h

#ifndef __2022TI_C1_PID_H
#define __2022TI_C1_PID_H

typedef struct PID {
  float  Proportion;         //  Proportional Const  
  float  Integral;           //  Integral Const  
  float  Derivative;         //  Derivative Const  
	float  PrevError;          //  Error[-2]
  float  LastError;          //  Error[-1]  
	float  Error;
	float  DError;
  float  SumError;           //  Sums of Errors  
	float  Integralmax;
	float  output;
	float  outputmax;
} PID;

extern PID M3508_spid[2];
extern PID ANGLE;
extern PID distance;

float abs_limit(float a, float ABS_MAX);
void PID_Position_Calc( PID *pp,  float  CurrentPoint,  float NextPoint);
void PID_Incremental_Calc( PID *pp,  float  CurrentPoint,  float NextPoint);
void PIDInit(PID *pp, float Kp , float Ki , float Kd ,  float outputmax, float Integralmax);

#endif

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

小车跟随行驶系统(基于MSP-EXP430F5529LP系统板) 的相关文章

  • Logidim中异或的符号表示

    logisim中的表达式以 代表异或
  • 本人开发环境基本配置一览 ~/.bashrc

    系统 xff1a ubuntu18 04 xff0c bashrc环境文件 1 配置CUDA路径 xff1b cudnn用deb包安装的 xff0c 会直接被装到系统相应路径 xff0c 不需要手动添加路径引用 2 ROS CUDA exp
  • QT笔记(一)

    学习目标 xff1a 总结学习的QT 学习内容 xff1a 1 QT的一些固定格式 2 控件和事件 3 信号和槽 记录内容 xff1a 1 QT的固定格式 1 引用头文件 自己创建的头文件用 34 34 括起 xff0c eg 96 inc
  • 17 C++11常用语法

    文章目录 一 C 43 43 11简介二 列表初始化2 1 容器如何支持花括号初始化 三 变量类型的推导3 1 编译时类型推导 xff1a auto3 2 decltype类型推导3 3 运行时类型推导 typeid 四 final ove
  • Git小乌龟(TortoiseGit)使用详情

    项目可能大概也许maybe要用到Git小乌龟 xff0c 正好水篇文章 下载及安装 首先没有下载Git的先下载 xff0c 官网下载地址 xff0c 安装时直接一直next就行 然后是小乌龟的下载 xff0c 官网下载地址 xff0c 不知
  • 一张图阐述UML状态图的画法【软件工程】

    文章目录 I 介绍状态图II 一图搞定状态图画法 I 介绍状态图 状态图展示了一个特定对象的所有可能状态以及由于各种事件的发生而引起的状态间的转移 它有两大特征 xff1a 1 所有的变化都是针对某一个特定的对象 xff0c 这个对象会触发
  • 虚拟机中Ubuntu与主机共享文件夹

    虚拟机中Ubuntu与主机共享文件夹 xff0c 以及 mnt目录为空 xff0c 没有共享文件夹时的解决方案 1 启用共享文件夹 首先将虚拟机关机 xff0c 在虚拟机设置中 xff0c 选择选项面板 xff0c 选择共享文件夹 xff0
  • 【ROS】中级操作学习整理-TF坐标变换

    系列文章目录 ROS 中级操作学习整理 gazebo机器人仿真 ROS 中级操作学习整理 TF坐标变换 ROS 中级操作学习整理 传感器建模 ROS 中级操作学习整理 激光SLAM 文章目录 目录 目录 系列文章目录 文章目录 前言 一 R
  • STM32 芯片锁死无法烧录问题解决

    芯片锁死原因 xff1a 1 烧进去的工程对应器件与目标器件不一致 xff1b 2 烧进去的工程HSE VALUE与目标板上晶振频率不一致 xff1b 3 将烧录引脚烧录 本人在使用F411时犯下了 比较愚蠢的错误 xff0c 因为PB3引
  • 【TPMS】 - 发射端2

    TPMS项目 发射端SP370 目录章节介绍 一 SP370数据手册浏览二 源码学习三 SP370的RF的部分详解四 RF数据包的发送和数据包格式解析1 目录 章节介绍 1 SP370数据手册浏览 浏览SP370的数据手册 xff0c 看一
  • 【TPMS】 -接收端1

    TPMS项目 接受端TDA5235 目录章节介绍 一 TPMS接收板概况介绍二 TDA5235的专业知识1三 寄存器配置工具 目录 章节介绍 1 TPMS接收板概况介绍 本节开始接收板部分的课程 xff0c 先对接收板的整体情况 xff0c
  • ST_link突然不能使用了

    一 发现问题 今天 xff0c 我使用st link烧写程序时突然不能用了 xff0c 我昨天都还可以正常使用 我用手摸仿真器时很热 我意识到可能坏了 二 解决过程 xff08 1 xff09 用keil5查看debug设置时就能找到ST
  • OpenCV 读取视频并保存为另一个视频

    测试代码如下 xff1a 功能 xff1a 读取视频 xff0c 缩小处理后再存为另一个视频 方法1 include lt opencv2 opencv hpp gt include lt opencv2 highgui highgui c
  • XML和JSON

    XML 简介 xml是什么 XML是一种可扩展标记语言 Extensible Markup Language xff0c 它是一种用于在计算机网络上进行数据传输的标准格式 XML使用标记来标识数据 xff0c 并且可以自定义标记 xff0c
  • STM32单片机蜂鸣器实验

    蜂鸣器可以分为两种 xff1a 有源蜂鸣器与无源蜂鸣器 xff0c 这里的 源 指的是有没有自带震荡电路 xff0c 有源的蜂鸣器自带有震荡电路 xff0c 通电的瞬间就会发出声音 xff1b 而无源的蜂鸣器 xff0c 需要提供一个2 5
  • JVM虚拟机

    JVM 1 JVM 概述 x1f6b4 x1f6b4 x1f6b2 x1f6b4 虚拟机 xff08 Virtual Machine xff09 是一台虚拟的计算机 VMware属于系统虚拟机 xff0c 是对物理计算机的仿真 Java虚拟
  • 树莓派桌面WIFI图标消失,树莓派黑屏can‘t currently show the desktop

    方法一 xff1a 重装镜像 方法二 xff1a 找个树莓派显示器终端输入这行代码 sudo apt install wpasupplicant wpagui libengine pkcs11 openssl 转载B站视频 xff1a 完美
  • cuda10.1+cudnn10.1+tensorflow2.2.0+pytorch1.7.1下载安装及配置

    一 cuda及cudnn下载 1 查看自己电脑是否支持GPU 方法 xff1a 鼠标移动到此电脑 xff0c 点击鼠标右键 xff0c 依次选择属性 设备管理器 显示适配器有以下图标 xff08 NVIDIA xff09 即可安装GPU x
  • C语言:strtok()函数简单用法

    strtok函数 切割字符串 第一个参数指定一个字符串 xff0c 它包含了0个或者多个由第二个参数 xff08 字符串 xff09 中的一个或多个分隔符分割的标记 strtok函数找到第一个参数中的下一个标记 xff0c 并将其用 39
  • ESP32之FreeRTOS--任务的创建和运行

    文章目录 前言一 创建任务和删除函数1 xTaskCreate 2 xTaskCreateStatic 3 xTaskCreateRestricted 4 vTaskDelete 二 任务函数和任务控制块TCB1 任务函数模板2 TCB 三

随机推荐

  • 如何将本地项目上传到gitee

    如何将本地项目上传到gitee 第一步 xff1a 首先你要有一个gitee仓库 新建仓库 填写仓库信息 xff1a 如图 第二步 xff1a 将创建好的仓库 xff0c pull xff08 拉取 xff09 到本地 通过git 命令 把
  • go语言操作es

    目录 go语言操作es解决golang使用elastic连接elasticsearch时自动转换连接地址初始化数据创建结构体方式字符串方式 xff1a 查找修改删除查找 集群搭建配置文件修改 go语言操作es go get github c
  • Context介绍

    目录 Context设计原理默认上下文取消信号传值方法小结 Context 上下文 context Context Go 语言中用来设置截止日期 同步信号 xff0c 传递请求相关值的结构体 上下文与 Goroutine 有比较密切的关系
  • 将视频转成ROS的bag包

    执行转化命令 python2 mp4 2 bag py lane video3 mp4 out camera bag 循环播放图片 xff0c 并重命名成自己需要的话题名 rosbag play l out camera bag camer
  • beego介绍(一)

    目录 beego 的 MVC 架构介绍参数配置默认配置解析不同级别的配置多个配置文件支持环境变量配置系统默认参数基础配置App 配置Web配置监听配置Session配置Log配置 路由设置基础路由基本 GET 路由基本 POST 路由注册一
  • TCP如何保证可靠性?

    TCP如何保证可靠性 xff1f TCP协议保证数据传输可靠性的方式主要有 xff1a 校验和 序列号 确认应答 超时重传 连接管理 流量控制 拥塞控制 1 校验和 计算方式 xff1a 在数据传输的过程中 xff0c 将发送的数据段都当做
  • 仿照java的jdk动态代理实现go语言动态代理

    仿照java的jdk动态代理实现go语言动态代理 通过学习java的jdk动态代理和Cglib动态代理 xff0c 仿照jdk动态代理用go实现了一个简单的动态代理 结构型模式 代理模式 代理模式中分为静态代理和动态代理 静态代理需要在编译
  • golang设计模式——装饰器模式

    装饰器模式 装饰器模式 xff1a 动态地给一个对象添加一些额外的职责 xff0c 就增加功能来说 xff0c 装饰模式比生成子类更为灵活 UML类图 xff1a 分析 首先我们需要理解 xff0c 为什么组合优于继承 xff1f 继承有诸
  • GoLang之unsafe分析

    GoLang之unsafe 目录 GoLang之unsafe1 前言2 指针类型转换3 指针运算4 获取大小和偏移5 关于string 1 前言 开发中 xff0c byte类型和string类型需要互相转换的场景并不少见 xff0c 直接
  • Go实现分布式锁

    Go分布式锁 目录 Go分布式锁进程内加锁trylock基于 redis 的 setnx基于 zk基于 etcdredlock如何选择 在单机程序并发或并行修改全局变量时 xff0c 需要对修改行为加锁以创造临界区 为什么需要加锁呢 xff
  • Golang实习蓝湖二面

    蓝湖二面 自我介绍 问题 casbin的策略 ACL RBAB ABAC 他们的区别和应用 JWT的实现 JWT和传统的token有什么区别 三次握手和四次挥手 time wait 为什么需要等待2MSL 什么是完全二叉树 完全二叉树有什么
  • export、import、commit、save、load的区别

    目录 1 docker export 和 docker import2 docker commit3 docker save 和 docker load 1 docker export 和 docker import docker expo
  • docker搭建redis集群模式

    目录 docker 安装redis1 创建redis conf开启redis验证 开启密码 允许redis外地连接后台启动开启redis持久化 2 启动redis容器3 进入容器 redis集群3主3从1 新建6个redis容器2 构建主从
  • SONiC+P4实践——P4Runtime下发ACL表项

    转载请表明出处 注 xff1a SONiC系统为vs版本 Part1 xff1a 实现外部宿主机与SONiC的网络连通 步骤 1 xff1a 打开一个ubuntu系统安装kvm及其依赖 xff08 1 xff09 查看CPU是否支持虚拟化
  • BDD100K自动驾驶数据集格式转YOLO格式

    说明 xff1a 为了用BDD100K数据集训练YOLOV5模型 xff0c 首先需要将BDD100K数据集格式转成YOLOV5支持的输入格式 转换代码如下 xff1a 一 BDD100K转YOLO格式 usr bin env python
  • 全局代理-WINDOWS怎么设置全局代理?

    https blog 51cto com u 15275599 2923545 WINDOWS设置全局代理可以通过以下4个步骤操作来实现 xff1a 1 点击开始菜单 xff0c 然后点击setting xff08 设置 xff09 xff
  • Easyexcle导入导出

    一 导入 1 依赖 lt excel gt lt dependency gt lt groupId gt com alibaba lt groupId gt lt artifactId gt easyexcel lt artifactId
  • Springboot+(linux)redis哨兵模式实现

    下面是主从redis服务 6379主6380从16381从2 下面是多个哨兵 26379哨兵126380哨兵226381哨兵3 windows下redis压缩包 xff08 本文使用的是5 0 13 xff09 Redis xff08 点我
  • 记一次springboot2.1.6配置(mysql)多数据源

    pom xml lt xml version 61 34 1 0 34 encoding 61 34 UTF 8 34 gt lt project xmlns 61 34 http maven apache org POM 4 0 0 34
  • 小车跟随行驶系统(基于MSP-EXP430F5529LP系统板)

    选用材料 xff1a 主控板MSP EXP430F5529LP 陀螺仪 直流减速电机 xff08 可以选用光电编码器 xff0c 霍尔电机不好调节PID xff09 TB6612电机驱动 超声波测距模块 灰度传感器 无线透传 蓝牙模块 xf