首页 > 其他分享 >基于ucosii的车载电控单元

基于ucosii的车载电控单元

时间:2024-06-30 21:57:54浏览次数:19  
标签:ucosii task 中断 void 车载 STK TIM1 电控 OS

一、项目简介

     通过利用STM32F103C8、直流电机、按键、us015超声波测距模块、MPU6050、蜂鸣器、TFLCD、霍尔传感器等硬件设计一个车载电控单元,实现了手动加档、实时显示车速、超声波避障预警、车身倾斜预警以及更新固件功能,以保证行车安全。

二、项目框架

     

三、硬件选型以及实现思路

        1.电机驱动

                这里我采用的是360°的SG90舵机来模拟车轮电机。其工作原理是靠PWM驱动实现变速。该舵机实际上由一个直流电机和驱动电路组成,它不像180°舵机那样可以实现控制角度,它只能实现控制方向、速度和停止。其对照关系图如下:

因此,根据上述工作原理,我采用了两个按键来分别实现正向的加速过程和反向的加速过程,如果到达最高速度,此时继续按下,会到最低速度。

        2.测速驱动

                这是通过A3144霍尔传感器模块来实现测量电机转速的。A3144只对单磁极有效,其磁场阈值为7mT,这个模块由霍尔传感器和电压比较器组成,其电路图如下所示:

                那么要想了解上图的工作原理,首先我们要知道什么是霍尔效应。霍尔效应是指在一个导体两端,接上电流,此时给这个导体施加垂直与电流的磁场,由于洛伦兹力,电子会往导体一侧偏转,造成导体两侧有电压差,这个电压叫做霍尔电压。因此,只要我们用一个磁铁靠近霍尔传感器,这个传感器就能将磁场的变化转变为电压的变化,而我们的电机里边是有永磁铁的,因此我们就能通过霍尔传感器来检测电机转动时候的磁场变化。而通过官方手册,我们发现A3144霍尔传感器在磁场强度高于本身的磁场阈值时,会输出一个低电平信号。也就是从上图的U2处输出一个低电平,此时经过一个比较器,当这个低电平电压小于2.5v时,会输出0,此时会点亮D3二极管,代表检测了一次磁场。因此,我们只要将这个霍尔传感器靠近电机的最高点,当转动一圈后电机的永磁铁S极经过这个电机最高点的时候,就可以检测到此时电机的磁场变化,并将其转为为低电平,那么我们就可以利用下降沿触发中断,在外部中断里边进行计数,同时通过定时器中断1s去看此时1s有多少个计数值,然后再乘以60,即为一分钟的转速。

        3.us015驱动

                在此处我们选用us015作为避障预警模块,其工作原理是trigger引脚发出一个10us以上的电平。然后此时系统就会发出超声波脉冲,然后系统开始检测回波信号,当检测到了回波信号以后通过echo引脚输出。而根据echo引脚输出的高电平持续时间可计算出距离。其公式为(高电平时间*340)/2。因此,我们从中就可以知道,需要创建一个us015任务来不停发出10us高电平信号。然后通过定时器捕获功能来获得返送回来的高电平脉冲宽度。其中,需要注意的是,对于启动任务,我们至少在该任务中添加1s的延时,这是因为,如果启动信号的频率过快,会导致返回的高电平频率过快,从而导致进入捕获中断的频率过快,会使得CPU资源耗尽导致程序跑飞。

        4.MPU6050驱动

                对于利用MPU6050模块来测量车身倾斜度,我们需要得到欧拉角数据就够了。因此实际上我们只需要移植mpu6050的初始化文件以及DMP的初始化文件就够了,但是,移植过程中需要注意的是,接口问题。由于我们用的是软件来模拟iic,因此我们将输出模式配置成推挽输出就行。其次,有一个坑,就是下载程序的时候记得在DEBUG里边用use stlink模式,而不是用仿真器模式,否则会出现iic时序错误,导致mpu6050初始化失败问题。

       5.IAP的bootloader程序

                最后说一下IAP任务,该任务主要实现三个功能,接收、拷贝、跳转。在此处的接收步骤,我们采用DMA来接收串口数据,从而节省CPU资源。在此处我给出大概的程序框架,因为c8t6的资源受限,已经无法添加IAP的更新任务了。首先是串口以及DMA的初始化。其中,需要注意的是根据手册,要想开启串口的DMA传输,需要使能串口CR3寄存器的DMAR位才能开启DMA接收,因此需要在串口初始化程序中加入以下代码:USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能串口1的DMA接收

将DMA初始化以后,创建IAP任务,并且在任务里边加入等待信号量,开启串口中断,在串口中断函数里边只写入释放信号量。如此,当检测到串口接收到数据时,进入中断,然后切换到IAP任务,此时在IAP任务里边开启一次DMA传输,然后去检测定义的内存变量是否有值,如果有值,代表已经接收到APP程序,此时调用写flash函数将APP程序拷贝到flash区,然后调用跳转函数。

        其他的驱动比较简单,略过。

四、主程序代码

UCOSII任务设置///
//START 任务
//设置任务优先级
#define START_TASK_PRIO                  10 //开始任务的优先级设置为最低
//设置任务堆栈大小
#define START_STK_SIZE                  64
//任务堆栈    
OS_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *pdata);    


//电机正向转动任务
//设置任务优先级
#define PWM_TASK_PRIO                   7
//设置任务堆栈大小
#define PWM_STK_SIZE                      64
//任务堆栈
OS_STK PWM_TASK_STK[PWM_STK_SIZE];
//任务函数
void pwm_task(void *pdata);


//电机反向转动
#define Re_TASK_PRIO                            6
#define    Re_STK_SIZE                                64
OS_STK    Re_TASK_STK[Re_STK_SIZE];
void     reverse_task(void *pdata);


//电机转速显示任务
#define Motoshow_task_prio                   4
#define Motoshow_task_size                    64
OS_STK    Motoshow_task_stk[Motoshow_task_size];
void Motoshow_task(void *pdata);


//us105测量距离任务
#define us105_task_prio                 5    
#define us105_task_size                            128
OS_STK    us105_task_stk[us105_task_size];
void us105_task(void *pdata);

//us_015启动任务
#define st_task_prio                 9
#define st_task_size                                32
OS_STK    st_task_stk[st_task_size];
void st_task(void *pdata);

//MPU6050测量倾斜角度任务                        
#define mpu6050_task_prio                         8
#define    mpu6050_task_size                        512
OS_STK    mpu6050_task_stk[mpu6050_task_size];
void mpu6050_task(void *pdata);


//定义需要用到的全局变量
//OS_EVENT *Bsem; 
//OS_EVENT *email;
OS_EVENT *sig1;
OS_EVENT *sig2;
OS_EVENT *sig3;
OS_EVENT *sig4;
led_d led1;
led_d bep;
led_d us;
volatile u8 flag=8;
volatile u8 mark=8;
volatile u32 rate=0;
volatile u32 buff;
volatile u8  STA=0;
volatile u16 PluseWidth;
u32                  num;

 int main(void)
 {    
    delay_init();        //延时函数初始化    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级     
    MPU_Init();
    mpu_dmp_init();
    LED_Init(&led1,GPIOC,GPIO_Pin_13);             //初始化与LED连接的硬件接口
    Beep_Init(&bep,GPIOB,GPIO_Pin_15);
    us105Init(&us,GPIOA,GPIO_Pin_12);
    TIM3_PWM_Init(99,14399);
    TIM2_Int_Init(4999,14399);
    TIM1_Cap_Init(84,71999);//计数频率也不能太高,否则程序也会跑飞,因为会频繁触发中断占用cpu资源
    EXTIX_Init();
    LCD_Init();    
    uart_init(115200);
    OSInit();   
     OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务
    OSStart();           
}
 
      
//开始任务
void start_task(void *pdata)
{
  OS_CPU_SR cpu_sr=0;
    pdata = pdata; 
    //Bsem=OSSemCreate(0);
    sig1=OSSemCreate(0);
    sig2=OSSemCreate(0);
    sig3=OSSemCreate(0);
    sig4=OSSemCreate(0);
    //email=OSMboxCreate((void *)0);
  OS_ENTER_CRITICAL();            //进入临界区(无法被中断打断)                       
     OSTaskCreate(pwm_task,(void *)0,(OS_STK*)&PWM_TASK_STK[PWM_STK_SIZE-1],PWM_TASK_PRIO);    //而R0寄存器是堆栈指针PSP,如果PSP=0,代表任务第一次进行任务切换,所以
    OSTaskCreate(reverse_task,(void *)0,(OS_STK*)&Re_TASK_STK[Re_STK_SIZE-1],Re_TASK_PRIO);
    OSTaskCreate(Motoshow_task,(void *)0,(OS_STK*)&Motoshow_task_stk[Motoshow_task_size-1],Motoshow_task_prio);
    OSTaskCreate(us105_task,(void *)0,(OS_STK*)&us105_task_stk[us105_task_size-1],us105_task_prio);
    OSTaskCreate(st_task,(void *)0,(OS_STK*)&st_task_stk[st_task_size-1],st_task_prio);
    OSTaskCreate(mpu6050_task,(void *)0,(OS_STK*)&mpu6050_task_stk[mpu6050_task_size-1],mpu6050_task_prio);
    OSTaskSuspend(START_TASK_PRIO);    //挂起起始任务.
    OS_EXIT_CRITICAL();                //退出临界区(可以被中断打断)
}

//电机正向转动任务
void pwm_task(void *pdata)
{    u8 err;
    while(1)
    {
        OSSemPend(sig1,0,&err);
        TIM_SetCompare3(TIM3,flag);
    }
}
//电机反转任务
void reverse_task(void *pdata)
{
    u8 err;
    while(1)
    {
        OSSemPend(sig2,0,&err);
        TIM_SetCompare3(TIM3,mark);
    }
}

//电机转速显示任务
void Motoshow_task(void *pdata)
{
    u8 err;
    while(1)
    {
        OSSemPend(sig3,0,&err);
        buff=rate;
        Show_Str(0,80,BLUE,WHITE,"Speed:00r/min",16,0);
        LCD_ShowNum(0+6*8,80,60*buff/2,2,16);
        rate=0;
    }
}


//us105测量距离任务
void us105_task(void *pdata)
{
    u8 err;
    while(1)
    {
        OSSemPend(sig4,0,&err);
        if(STA&0x80)
        {
            num=0.005*340*PluseWidth;
            Show_Str(0,60,BLUE,WHITE,"juli:00cm",16,0);
            LCD_ShowNum(0+5*8,60,num,2,16);
            if(num<=5)
            {
                Beep_on(&bep);
                led_on(&led1);
                TIM_SetCompare3(TIM3,8);
            }    
            else
            {
                led_off(&led1);
                Beep_off(&bep);
            }
            STA=0;
      }
    }
}

//us-015启动任务
void st_task(void *pdata)
{
    while(1)
    {
        us105_Start(&us);
        delay_ms(1000);//这个延时一定要加,因为这是us015的触发信号,但是触发信号的频率越高,输出的脉冲频率也越高,导致进入中断的频率也会越高,会让中断过于频繁,让cpu资源耗尽
//导致程序跑飞,当我延时了1s时,此时显示距离都很正常了。
    }
}
    

//mpu6050测量倾斜角度任务
void mpu6050_task(void *pdata)
{
    float pitch,roll,yaw; 
    int tmp;
    while(1)
    {
        if(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0)//防止FIFO队列溢出,队列溢出是指你处理的速度过慢,导致你处理的跟不上人家发送过来的速度,就会堆积在缓冲区,造成缓冲区堵塞
        {//因此建议把延时弄低一些,加快处理速度。
            tmp = roll * 10;
            if (tmp < 0)
            {
                    tmp = -tmp;
                    Show_Str(0,40,BLUE,WHITE,"angle:-00.00d",16,0);
                    LCD_ShowNum(0+7*8,40,tmp/10,2,16);
                    LCD_ShowNum(0+10*8,40,tmp%10,2,16);
            }
            else
            {
                    Show_Str(0,40,BLUE,WHITE,"angle:00.00d",16,0);
                    LCD_ShowNum(0+6*8,40,tmp/10,2,16);
                    LCD_ShowNum(0+9*8,40,tmp%10,2,16);
            }
            if(tmp>45)
            {
                    TIM_SetCompare3(TIM3,8);
                    Show_Str(0,20,BLUE,WHITE,"Cuation!",16,0);
            }
            else     LCD_Fill(0,0,128,35,WHITE);
            delay_ms(300);//延时尽量短,保证读取数据的频率足够高,否则时间长了会看不到数据变化和FIFO溢出,最高延时不能超过300ms
        }
    }
}

void EXTI1_IRQHandler(void)//外部中断1,对应蜂鸣器按键,按下加速
{
        OSIntEnter();
        delay_ms(10);
        if(KEY0==0)
            {
                flag-=1;
                if(flag<3)
                {
                    flag=8;
                }
                Show_Str(0,100,BLUE,WHITE,"Gear:",16,0);
                LCD_ShowNum(0+5*8,100,flag,2,16);
                OSSemPost(sig1);
            }
        EXTI_ClearITPendingBit(EXTI_Line1);
        OSIntExit();
}


void EXTI15_10_IRQHandler(void)//外部中断PB12,PC14用于控制电机反转/电机转速计数
{
        OSIntEnter();
        delay_ms(10);
    if(EXTI_GetITStatus(EXTI_Line12)!=RESET)
    {
      if(KEY1==0)
        {
                mark+=1;
                if(mark>13)
                {
                    mark=8;
                }
                Show_Str(0,120,BLUE,WHITE,"Gear:",16,0);
                LCD_ShowNum(0+5*8,120,mark,2,16);
                OSSemPost(sig2);
        }
        EXTI_ClearITPendingBit(EXTI_Line12);
    }
    if(EXTI_GetITStatus(EXTI_Line14)!=RESET)
    {
        if(KEY2==0)
        {
            rate++;
        }
        EXTI_ClearITPendingBit(EXTI_Line14);
    }
        OSIntExit();
}


void TIM2_IRQHandler(void)//定时器中断函数,定时1s计算此时的转速,需要注意的是中断函数里边不能写太复杂的东西,不然就会被卡住
{
    OSIntEnter();
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查 TIM2 更新中断发生与否
    {
            TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除 TIM2 更新中断标志
            OSSemPost(sig3);
    }
    OSIntExit();
}

//以下是us105测距模块,捕获传回来的高电平脉冲,捕获中断
void TIM1_CC_IRQHandler(void)

    OSIntEnter();
     if((STA&0X80)==0)//还未成功捕获    
    {      
        if (TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
            {    
                if(STA&0X40)        //捕获到一个下降沿         
                {                  
                    STA|=0X80;        //标记成功捕获到一次高电平脉宽
                    PluseWidth=TIM_GetCapture1(TIM1);
                    TIM_OC1PolarityConfig(TIM1,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
                }else                                  //还未开始,第一次捕获上升沿
                {
                    STA=0;            //清空
                    PluseWidth=0;
                    TIM_SetCounter(TIM1,0);
                    STA|=0X40;        //因此程序实际上是等到上升沿中断的时候,在此处主动把这个比寄存器的值变成不是0的
                    TIM_OC1PolarityConfig(TIM1,TIM_ICPolarity_Falling);        //CC1P=1 设置为下降沿捕获
                }            
            }                                                
     }
     OSSemPost(sig4);
   TIM_ClearITPendingBit(TIM1, TIM_IT_CC1); //清除中断标志位
     OSIntExit();
}

五、调试记录

  1. 转速显示功能不能放在定时器中断函数里执行,因为太过复杂,会导致程序卡住。
  2. 针对转速实时显示,在进入定时器中断函数以后,此时电机持续转动,但是由于在定时器中断函数里边加入了清零计数器操作,会导致转速数据丢失,因此采用双缓冲技术,此时引入另外一个缓冲变量buffer,用于保存当前计数值,再将当前计数值清零,显示buffer。并且需要注意,buffer和计数器都应该用volatile关键字声明,这是因为计数器属于中断函数中的非自动变量,需要重新取值。再加入双缓冲技术以后,还是会出现变成0的情况,因此我在硬件上再加入一块磁铁,计算的时候除以2,这样既保证了实时更新,也变得稳定了许多,但是目前还是会出现速度会跳变的情况,原因估计是抖动问题,我已经加了消抖功能,但是好像不能完全消抖。
  3. 针对us105模块的使用,不存在定时器溢出的情况,因为根据其手册,最长距离也就80ms的高电平脉冲,因此不用在捕获中断函数中添加定时器中断溢出的情况。
  4. 在us015中,使用的是TIM1高级定时器来进行输入捕获,但是当我开启TIM1的中断时,输入TIM1_IRQn却出现了报错,这是由于TIM1是高级定时器,因此不像普通定时器那样只有一个普通中断,高级定时器分为四个中断:TIM1_BRK_IRQn               = 24,     /*!< TIM1 Break Interrupt                                 */

  TIM1_UP_IRQn                = 25,     /*!< TIM1 Update Interrupt                                */

  TIM1_TRG_COM_IRQn           = 26,     /*!< TIM1 Trigger and Commutation Interrupt               */

  TIM1_CC_IRQn                = 27,     /*!< TIM1 Capture Compare Interrupt                       */此处我们只用到捕获中断,因此只需要开启捕获中断即可。

  1. 首先是us015没有工作,然后在线调试利用逻辑分析仪发现triger引脚没有重复输出10us以上的电平,随后新创建一个任务重复输出高低电平,接下来发现程序能正常运行,但是程序很容易跑飞,需要复位才能正常运行。查了一下结果发现,是中断触发太平繁,计数频率太高,与霍尔传感器的计数频率一致,导致cpu资源耗尽,而且lcd屏幕显示数字过快,此时我降低输入捕获计数频率为1000hz,此时依然会让程序跑飞,捕获中断触发的还是过于频繁,在lcd屏幕上显示的距离数字跳动的都看不清也能说明这一点,最后我发现是由于us015触发任务的问题,原因就是我在这个任务里没有添加延时,导致触发信号的发送频率过高,由此会引起输出回冲波的频率过快,从而导致捕获回冲波频率过快,由此引起中断进入频繁,最后导致CPU资源耗尽,程序跑飞。因此,我们只需要在us015触发任务里加入1s的延时,降低触发信号的输入频率,即可解决上述问题。
  2. 关于MPU6050倾斜测量功能,当我将mpu6050焊接好了以后,移植iic以及dmp的代码进去以后,发现没有iic信号,mpu初始化失败。首先检查接口的问题,我用的是PB11,PB10接口,这是用软件iic来进行模拟,因此,只需配置成推挽输出模式即可,其他方式不能出iic信号。其次是头文件,因为SDA线,在读和写情况下,io口模式不同,因此这都是在头文件中对其寄存器进行更改的,我们可以看到io口的寄存器由于是8-15接口,因此寄存器是CRH,注意一个io口为4位,因此配置成GPIOB->CRH&=0Xffff0FFF,GPIOB->CRH|=3<<12就是将其配置成推挽输出模式,具体可以看手册。其次,再弄好接口以后,烧录进去还是初始化失败,这个问题卡了一两天,才发现是调试的问题,也就是说如果在keil中的Debug菜单下选择的是use simulator的方式,此时会导致初始化失败,如果你选择的是use stlink的方式。此时程序会正常运行,这里一定要注意这个坑。查了一下,这是因为软件模拟没法完成的模拟出iic时序,但是我们遇到问题的时候又得用软件模拟得方式去看逻辑分析仪的iic波形,因此导致了这样的结果。因此当我们用iic接口的时候,一定要注意debug下用stlink而不是simulator!最后,在所有初始化成功以后,dmp还是没有检测到欧拉角,数字一直为0,去百度了一下,发现是FIFO溢出导致的,也就是说你处理数据的速度赶不上发送速度,会导致FIFO缓冲区堵塞,接收不到新数据。因此需要将延时缩短,增加处理数据的频率,并且如果你延时大于300ms,此时无论你怎么倾斜,也看不到角度的变化。

六、运行效果

<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="Hyznyw3O-1719755450417" src="https://live.csdn.net/v/embed/404944"></iframe>

ECU

标签:ucosii,task,中断,void,车载,STK,TIM1,电控,OS
From: https://blog.csdn.net/weixin_52247452/article/details/140084582

相关文章

  • 【车载网络协议】【Ethernet】【ARP】【第二章-字段介绍】
    一、报文类型ARP协议中的请求(Request)和响应(Reply)是通过特定的字段来进行交换信息的。下面是对ARP请求和响应字段的详细介绍。二、请求报文硬件类型(HardwareType):指定网络接口的硬件类型,例如以太网通常使用1表示以太网。协议类型(ProtocolType):指定网络层协议类型,例如IPv4......
  • 【车载网络协议】【Ethernet】【ARP】【第三章-缓存介绍】
    一、概念简介ARP(AddressResolutionProtocol)是一种用于将网络层地址(IP地址)解析为数据链路层地址(MAC地址)的协议。ARPCache是ARP协议在计算机或网络设备上维护的一个重要数据结构,用于存储IP地址与对应的MAC地址之间的映射关系。本文将介绍ARPCache的作用、工作原理......
  • 【车载开发系列】NM网络管理基础知识
    【车载开发系列】NM网络管理基础知识【车载开发系列】NM网络管理基础知识【车载开发系列】NM网络管理基础知识一.NM网络管理的作用二.网络管理如何实现省电三.什么是ECU的睡眠唤醒四.关于唤醒请求五.总线唤醒(Buswakeup)六.直接间接网络管理七.网络管理的目标......
  • 【车载开发系列】各类总线介绍
    【车载开发系列】各类总线介绍【车载开发系列】各类总线介绍【车载开发系列】各类总线介绍一、为什么需要总线二、车载总线的种类三、CAN总线1)CAN协议简介2)CAN协议特点四、CANFD总线1)CANFD协议简介2)CANFD协议特点五.LIN总线1)LIN总线简介2)LIN总线特点3)为什么要LIN......
  • 车载android开发 carservice(一)
    车载android开发carservice是什么?车载Android开发中的CarService是一个专门为汽车环境设计的系统服务。CarService通常是AndroidAutomotiveOS的一部分,提供一系列API和框架,允许开发人员构建与汽车相关的应用和服务。以下是CarService的一些主要功能和作用:车辆数据访问:C......
  • 电子电气架构 ---车载安全防火墙
    我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师:屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节能减排。无......
  • 关于ucosii操作系统原理------(三)内存管理
    目录一、引言二、内存控制块三、内存管理的实现源码1.动态内存分区创建函数2.获得一个内存块函数3.释放内存块函数一、引言   接下来说一下实时操作系统的动态内存管理。对于实时操作系统来说,动态内存分配的执行时间必须是可确定的。ucosii对malloc()函数和fre......
  • 车载电子电器架构 —— 智能座舱技术范围(万字长文精讲)
    车载电子电器架构——智能座舱技术范围我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师:屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利......
  • 车载诊断内容汇总(培训+视频)
    车载诊断内容汇总我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师:屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神......
  • 车载监控解决方案在工程机械行业的应用
    随着科技的快速发展,现代工程机械行业正迎来一场智能化、信息化的革命。GPS、4G通信、车载监控以及车载智能应用等技术的综合运用,为工程机械的安全作业提供了全方位、全时段的保障。本文以挖掘机为例,探讨车载监控解决方案在工程机械行业的广泛应用及其带来的安全效益。一、GPS......