迪文科技论坛

 找回密码
 立即注册
搜索
查看: 2145|回复: 4

【开源】智能柜设计(包括设计方案与设计资料)

[复制链接]

0

主题

7

回帖

246

积分

中级会员

Rank: 3Rank: 3

积分
246
发表于 2022-8-20 23:24:22 | 显示全部楼层 |阅读模式
本帖最后由 往前走 于 2022-9-17 22:38 编辑

最近帮客户做了一款针对实验柜的舵机控制系统,本着完美主义,我在这里将用T5L屏设计一款高端大气时尚的智能柜管理系统。(资料陆续更新,欢迎大家提出批评建议)(dgus工程所用图片均来自于网络,仅供各位朋友交流参考,请勿商用)

首先说一下本智能的优势
1、兼容性:
   (1)液晶屏(操作面包)兼容性:在设计上采用了T5L标准屏作为主控,直接驱动串行总线舵机,传感器汇总到辅助控制器(如STC系列单片机),再将数据通过串口4发送给液晶屏,在实际开发过程中,只需要根据采用的液晶屏的分辨率改变DGUS工程就行。
   (2)舵机兼容性:采用飞特的STS系列串行总线舵机作为驱动,这类舵机的力矩涵盖了4.5KG到40KG,且它们的协议通用
2、安全性:串行总线舵机具有电流、力矩、温度、电压保护功能,其使用安全性要高于常规的电机。
3、可拓展性:串行总线舵机,理论上来说,一个串口支持同时控制254个舵机,即一块液晶屏作为主控,可以带动254个舵机。

以下是设计资料(资料随时更新)

演示视频:链接: https://pan.baidu.com/s/19_-gfqtCd4SaAHN9-SsLMQ?pwd=4967 提取码: 4967 复制这段内容后打开百度网盘手机App,操作更方便哦
关于演示视频的几点说明:
1.视频中采用的舵机为飞特SCS115型与SCS40两种型号的舵机,电源为24V开关电源,经,降压至8-9V接入舵机
2.DGUS工程为800*480的,但我的80480的屏摔坏了,所以用的7寸1024*600的液晶屏
3.由于论坛里有大神已经做了时间更新与flash操作的代码(迪文温控器代码),所以我就不做演示
4.关于舵机动作顺序,开门:门栓舵机动作完成,开门舵机再动作;关门:开门舵机动作完成,然后门栓舵机再动作

如下图所示,为本文设计的智能柜的框架,迪文屏作为主控制器,通过串口2直接输出指令控制串行总线舵机,串口4与辅助控制器连接,用于拓展传感器,例如用于化学实验柜,可以拓展用以检测温度、气体、火焰检测等传感器。灯光系统用于智能柜内部照明使用,采用行程开关与光耦传感器共同控制,即在照明不良、柜门打开时,点亮照明灯光,电路见下文。


为了防止停电时,智能柜门处于失控状态,本设计采用了双舵机的设计,即开门舵机负责柜门的开关动作,门闩舵机负责门闩动作,停电后,由于门闩的存在,即使开门舵机卸力,智能柜也依然处于上锁状态,当然,如果用户觉得双舵机的成本太高,可以选择不加门闩舵机,对本设计的系统运行并不产生影响。机械结构如图所示:



接下来说明一下本设计的程序框架,程序是C51语音,在液晶屏中运行

电路原理图分为三部分:主电路板(舵机驱动电路+辅助控制器+接口)、降压电路、灯光电路(安装在柜子里边)

我在这里使用STM32F103RCT6作为辅助控制器,单片机的串口1与液晶屏的串口4相连接,液晶屏串口2直接驱动舵机,同时设计有一路输入,一路输出,用于紧急情况

辅助控制器与传感器使用的电压多为5V,而舵机的电压直接与舵机型号相关,例如SCS115型的电压为7-8V,因此本设计采用了LM2596S-5.0输出5V电压,LM2596S-ADJ可调输出7.5V电压用于舵机,不同的电压,调节电阻R_ADJ的阻值即可。
由于使用的降压芯片为LM2596S,支持最大输入电压40V

这里采用了光耦电阻检测亮度,行程开关与柜门相接,当柜门打开时,行程开关导通,如果光线太暗,小灯泡就可以点亮。
降压板与驱动板安装在如下图所示的小盒子里(3D图纸见附件),底层为降压板,上层为主电路板,




1.温湿度检测与刷新,时间更新(由辅助控制器驱动AHT21,将温湿度数据写入迪文屏)
/*****************温湿度更新**********************/
void dwin_Tempe_humi_update( void)
{
        uint8_t  Tempe_humi_date[20];  //发送给液晶屏的指令
        AHT20_Read_CTdata(CT_data);  //读取温度和湿度
        
        Tempe_humi_date[0]=0x5A;
        Tempe_humi_date[1]=0xA5;
        Tempe_humi_date[2]=0x07;
        Tempe_humi_date[3]=0x82;
        Tempe_humi_date[4]=(ADDR_TEMP_HUMI>>8)&0xff;
        Tempe_humi_date[5]=ADDR_TEMP_HUMI&0xff;
        Tempe_humi_date[6]=((CT_data[1] *200*10/1024/1024-500)>>8)&0xff;
        Tempe_humi_date[7]=((CT_data[1] *200*10/1024/1024-500))&0xff;//计算得到温度值(放大了10倍,如果t1=245,表示现在温度为24.5℃)
        Tempe_humi_date[8]=((CT_data[0]*1000/1024/1024)>>8)&0xff;
        Tempe_humi_date[9]=((CT_data[0]*1000/1024/1024))&0xff;  //计算得到湿度值(放大了10倍,如果c1=523,表示现在湿度为52.3%)
        Usart_SendString( USART_DWIN,Tempe_humi_date,10);

}

/*****************时间更新**********************/

uint8_t  DGUS_RTC_date[40];  
void dwin_time_update( u32 time_value)
{
        struct rtc_time time;
        unsigned int days,hour_min_sec;
        unsigned int i;
        
        days = time_value / 86400;//一天有86400秒
        hour_min_sec = time_value % 86400;//一天有86400秒
        
        time.hour = hour_min_sec / 3600;//一小时有3600秒
        time.mintute =( hour_min_sec % 3600 ) / 60;//一分钟有60秒
        time.second =( hour_min_sec % 3600 ) % 60;
        
        //年份判断,从1970年开始
        for ( i=1970;days>=days_in_years(i);i++)
        {
                days-=days_in_years(i);
        }
        time.year=i;
        //判断月份
        if (leapyear(i))
                days_in_month[2]=29;
        else
                days_in_month[2]=28;
                for ( i=1;days>=days_in_month;i++)
        {
                days-=days_in_month;
        }
        time.month = i;
        //日期计算
        time.day = days + 1 ;
        
        time.week=RTC_Get_Week(time.year,time.month, time.day);

        DGUS_RTC_date[0]=0x5A;
        DGUS_RTC_date[1]=0xA5;
        DGUS_RTC_date[2]=0x18;
        DGUS_RTC_date[3]=0x82;
        DGUS_RTC_date[4]=(ADDR_RTC_TIME>>8)&0xff;
        DGUS_RTC_date[5]=ADDR_RTC_TIME&0xff;
        DGUS_RTC_date[6]=0x00;
        DGUS_RTC_date[7]=time.hour;//时
        DGUS_RTC_date[8]=0x00;
        DGUS_RTC_date[9]=time.mintute;//分
        DGUS_RTC_date[10]=00;
        DGUS_RTC_date[11]=time.second;//秒
        DGUS_RTC_date[12]=(time.year>>8)&0xff;//年
        DGUS_RTC_date[13]=time.year&0xff;//年
        DGUS_RTC_date[14]=00;
        DGUS_RTC_date[15]=time.month;//月
        DGUS_RTC_date[16]=00;
        DGUS_RTC_date[17]=time.day;//日
        
        DGUS_RTC_date[18]=ascii_8hex[2*weeks(time.week)+0];//(time.week>>8)&0xff;//ascii_8hex[];//
        DGUS_RTC_date[19]=ascii_8hex[2*weeks(time.week)+1];// time.week&0xff;//当前星期
        

        Usart_SendString( USART_DWIN,DGUS_RTC_date,26);
        

}
//星期运算


uint16_t weeks(int weekday)
{
//        uint16_t asic_2_h;
        if(weekday>6)
                weekday-=7;

        return weekday;
}


(上传空间有限,需要详细资料的请邮箱联系1462818330@qq.com





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0

主题

7

回帖

246

积分

中级会员

Rank: 3Rank: 3

积分
246
 楼主| 发表于 2022-8-20 23:54:22 | 显示全部楼层
本节主要是简单说一下飞特舵机指令协议,供大家做个参考。
飞特舵机STS系列采用TTL通信,指令格式为8-N-1,波特率默认1000000,可以更改为1000000,500000,250000,128000,115200,76800,57600,38400
1.指令
     字头     ID号 数据长度 指令    参数                                 校验和
0XFF 0XFF ID Length Instruction Parameter1 ...Parameter N Check Sum
字头:连续收到两个 0XFF ,表示有数据包到达。
ID: 每个舵机都有一个 ID 号。 ID 号范围 0~253,转换为十六进制 0X00~0XFD。
广播 ID: ID 号 254 为广播 ID,若控制器发出的 ID 号为 254(0XFE),所有的舵机均接收指令,除 PING 指令外其它指令均不返回应答信息(多个舵机连接在总线上不能使用广播 PING指令)。
数据长度:等于待发送的参数长度 N 加上 2,即“N+2”。
参数:除指令外需要补充的控制信息,参数最大支持双字节参数表示一个内存值,字节顺序参考舵机使用手册(不同型号舵机字节顺序不一样)。
校验和:校验和 Check Sum,计算方法如下:Check Sum = ~ (ID + Length + Instruction + Parameter1 + ... Parameter N)
若括号内的计算和超出 255,则取最低的一个字节,“~”表示取反。
例如,控制舵机转到1500位置,则指令为FF FF 01 0A 03 29 32 E8 03 00 00 E8 03 C0 ,该指令控制舵机位置与转动速度、加速度
2.应答
    字头      ID 数据长度 当前状态 参数                         校验和
0XFF 0XFF ID Length ERROR Parameter1 ...Parameter N Check Sum
返回的应答包包含舵机的当前状态 ERROR,若舵机当前工作状态不正常,会通过这个字节反映出来,若 ERROR 为 0,则舵机无报错信息。
若指令是读指令 READ DATA,则 Parameter1 ...Parameter N 是读取的信息。

详细舵机指令说明,大家可以自行查找官网。
回复

使用道具 举报

0

主题

7

回帖

246

积分

中级会员

Rank: 3Rank: 3

积分
246
 楼主| 发表于 2022-8-26 22:36:36 | 显示全部楼层
本帖最后由 往前走 于 2022-8-28 22:48 编辑

主要功能程序说明:2.舵机内存表宏定义(节选)
#define SCSCL_ID 5
#define SCSCL_BAUD_RATE 6
#define SCSCL_RETURN_DELAY_TIME 7
#define SCSCL_RETURN_LEVEL 8
#define SCSCL_MIN_ANGLE_LIMIT_L 9
#define SCSCL_MIN_ANGLE_LIMIT_H 10
#define SCSCL_MAX_ANGLE_LIMIT_L 11
#define SCSCL_MAX_ANGLE_LIMIT_H 12
#define SCSCL_LIMIT_TEMPERATURE 13
#define SCSCL_MAX_LIMIT_VOLTAGE 14
#define SCSCL_MIN_LIMIT_VOLTAGE 15
#define SCSCL_MAX_TORQUE_L 16
#define SCSCL_MAX_TORQUE_H 17
#define SCSCL_ALARM_LED 19
#define SCSCL_ALARM_SHUTDOWN 20
#define SCSCL_COMPLIANCE_P 21
#define SCSCL_COMPLIANCE_D 22
#define SCSCL_COMPLIANCE_I 23
#define SCSCL_PUNCH_L 24
#define SCSCL_PUNCH_H 25
#define SCSCL_CW_DEAD 26
#define SCSCL_CCW_DEAD 27
#define SCSCL_PROTECT_TORQUE 37
#define SCSCL_PROTECT_TIME 38
#define SCSCL_OVLOAD_TORQUE 39
#define SCSCL_TORQUE_ENABLE 40
#define SCSCL_GOAL_POSITION_L 42
#define SCSCL_GOAL_POSITION_H 43
#define SCSCL_GOAL_TIME_L 44
#define SCSCL_GOAL_TIME_H 45
#define SCSCL_GOAL_SPEED_L 46
#define SCSCL_GOAL_SPEED_H 47
#define SCSCL_LOCK 48


3.舵机服务子程序(其他子程序,由于篇幅有限,这里就不写)
int writePos(uint8_t ID, uint16_t Position, uint16_t Time, uint16_t Speed, uint8_t Fun)
{
        uint8_t buf[6];
        flushSCS();//清空缓冲区

        u16_to_u8(buf+0, buf+1, Position);
        u16_to_u8(buf+2, buf+3, Time);
        u16_to_u8(buf+4, buf+5, Speed);
        writeBuf(ID, SCSCL_GOAL_POSITION_L, buf, 6, Fun);
        return Ack(ID);
}

//写位置指令
//舵机ID,Position位置,运行时间Time,速度Speed
int WritePos(uint8_t ID, uint16_t Position, uint16_t Time, uint16_t Speed)
{
        return writePos(ID, Position, Time, Speed, INST_WRITE);
}

//异步写位置指令
//舵机ID,Position位置,运行时间Time,速度Speed
int RegWritePos(uint8_t ID, uint16_t Position, uint16_t Time, uint16_t Speed)
{
        return writePos(ID, Position, Time, Speed, INST_REG_WRITE);
}

void RegWriteAction(void)
{
        writeBuf(0xfe, 0, NULL, 0, INST_ACTION);
}

//写位置指令
//舵机ID[]数组,IDN数组长度,Position位置,运行时间Time,速度Speed
void SyncWritePos(uint8_t ID[], uint8_t IDN, uint16_t Position, uint16_t Time, uint16_t Speed)
{
        uint8_t buf[6];

        u16_to_u8(buf+0, buf+1, Position);
        u16_to_u8(buf+2, buf+3, 0);
        u16_to_u8(buf+4, buf+5, Speed);
        snycWrite(ID, IDN, SCSCL_GOAL_POSITION_L, buf, 6);
}

//读位置,超时返回-1
int ReadPos(uint8_t ID)
{
        return readWord(ID, SCSCL_PRESENT_POSITION_L);
}

//速度控制模式
int WriteSpe(uint8_t ID, int16_t Speed)
{
        if(Speed<0){
                Speed = -Speed;
                Speed |= (1<<10);
        }
        return writeWord(ID, SCSCL_GOAL_TIME_L, Speed);
}

//读负载,超时返回-1
int ReadLoad(uint8_t ID)
{      
        return readWord(ID, SCSCL_PRESENT_LOAD_L);
}

//读电压,超时返回-1
int ReadVoltage(uint8_t ID)
{      
        return readByte(ID, SCSCL_PRESENT_VOLTAGE);
}

//读温度,超时返回-1
int ReadTemper(uint8_t ID)
{      
        return readByte(ID, SCSCL_PRESENT_TEMPERATURE);
}

//Ping指令,返回舵机ID,超时返回-1
int Ping(uint8_t ID)
{
        int Size;
        uint8_t bBuf[6];
        flushSCS();
        writeBuf(ID, 0, NULL, 0, INST_PING);
        Size = readSCS(bBuf, 6);
        if(Size==6){
                return bBuf[2];
        }else{
                return -1;
        }
}

void writeBuf(uint8_t ID, uint8_t MemAddr, uint8_t *nDat, uint8_t nLen, uint8_t Fun)
{
        uint8_t i;
        uint8_t msgLen = 2;
        uint8_t bBuf[6];
        uint8_t CheckSum = 0;
        bBuf[0] = 0xff;
        bBuf[1] = 0xff;
        bBuf[2] = ID;
        bBuf[4] = Fun;
        if(nDat){
                msgLen += nLen + 1;
                bBuf[3] = msgLen;
                bBuf[5] = MemAddr;
                writeSCS(bBuf, 6);//MemAddr保存的是目标位置在舵机SRAM中的保存地址,如果有目标参数(判断nDat==1),则会从这一位开始输出

        }else{
                bBuf[3] = msgLen;
                writeSCS(bBuf, 5);//如果没有目标参数(判断nDat==0)则不输出目标地址,也就只有五位数
        }
        CheckSum = ID + msgLen + Fun + MemAddr;
        if(nDat){
                for(i=0; i<nLen; i++){
                        CheckSum += nDat;
                }
                writeSCS(nDat, nLen);
        }
        CheckSum = ~CheckSum;
        writeSCS(&CheckSum, 1);
}

//普通写指令
//舵机ID,MemAddr内存表地址,写入数据,写入长度
int genWrite(uint8_t ID, uint8_t MemAddr, uint8_t *nDat, uint8_t nLen)
{
        flushSCS();
        writeBuf(ID, MemAddr, nDat, nLen, INST_WRITE);
        return Ack(ID);
}
//读指令
//舵机ID,MemAddr内存表地址,返回数据nData,数据长度nLen
int Read(uint8_t ID, uint8_t MemAddr, uint8_t *nData, uint8_t nLen)
{
        int Size;
        uint8_t bBuf[5];
        flushSCS();
        writeBuf(ID, MemAddr, &nLen, 1, INST_READ);
        if(readSCS(bBuf, 5)!=5){
                return 0;
        }
        Size = readSCS(nData, nLen);
        if(readSCS(bBuf, 1)){
                return Size;
        }
        return 0;
}



回复

使用道具 举报

0

主题

2

回帖

845

积分

高级会员

Rank: 4

积分
845
发表于 2022-10-9 09:06:57 | 显示全部楼层
太棒了,顶顶顶!!!
回复

使用道具 举报

6

主题

25

回帖

177

积分

注册会员

Rank: 2

积分
177
发表于 2023-12-29 09:10:49 | 显示全部楼层
你的3d模型用什么画的
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|迪文科技论坛 ( 京ICP备05033781号-1 )

GMT+8, 2024-11-22 07:46 , Processed in 0.075875 second(s), 22 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表