基于树莓派的智能垃圾桶项目
预计所需要实现的功能
通过感应能够实现垃圾桶盖子的自动开关。
垃圾桶上装载OLED屏,屏幕上需要显示,温度,时间。
远程控制通过电脑端实现控制垃圾桶的移动。
功能模块:
1树莓派3B开发板一块
2OLED显示屏一块
3超声波模块
4SG90舵机
5直流电机,轮子,电机驱动板
6清洁桶
关于各种树莓派API可以查看
https://www.cnblogs.com/lulipro/p/5992172.html
程序代码:
服务端程序(写在树莓派上的)
include <stdio.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <pthread.h>
#include <wiringPi.h>
#include "oled.h"
#include "log.h"
#include "chao.h"
#include "xiao.h"
#define echo 27
#define trlg 28
float distant;
#define RANGE 200 // 1 means 100 us , 200 means 20 ms
// 1等于100微妙,200等于20毫秒
void a_open() {
softPwmWrite(3, 5); //将pwm输出复写为使舵机转到0
delay(100);
}
void b_open() {
softPwmWrite(3, 15);
delay(100);
softPwmWrite(3, 15);
}
void *chaoshenbo() {
while (1) {
distant = wiring_distance();
if (distant < 10) {
a_open();
b_open();
}
printf("distance=%.2f\n", distant);
}
return NULL;
}
int main(int a, char *avg[]) {
int sock;
int c_fd;
pthread_t t1;
pthread_t t2;
pthread_t t3;
softPwmCreate(3, 15, RANGE);
wiringPiSetup();
wiring_init();
che_init();
struct Msg *rec = (struct Msg *)malloc(sizeof(struct Msg));
log_creat();
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("socker failed:\n");
exit(-1);
}
struct sockaddr_in addr1;
memset(&addr1, 0, sizeof(addr1));
addr1.sin_family = AF_INET;
addr1.sin_port = htons(atoi(avg[1]));
inet_aton("192.168.43.215", &addr1.sin_addr);
int on = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
int len = sizeof(struct sockaddr_in);
bind(sock, (struct sockaddr *)&addr1, sizeof(struct sockaddr_in));
listen(sock, 10);
c_fd = accept(sock, (struct sockaddr *)&addr1, &len);
if (c_fd == -1) {
printf("accept failed\n");
exit(-1);
}
char *c = (char *)malloc(32);
printf("connect success/n");
pthread_create(&t1, NULL, &oled_display, NULL);
pthread_create(&t2, NULL, chaoshenbo, NULL);
while (1) {
int ret = recv(c_fd, c, 1, 0);
printf("ret=%d\n", ret);
printf("%c\n", *c);
xiaochequdon(c);
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}
OLED模块程序
#include <time.h>
#include <wiringPi.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <wiringPiI2C.h>
#include"oled.h"
int fd;
unsigned char yi[4][16] = {
" ", //第一行
" ", //第二行
" ", //第三行
" made in zcc " //第四行
}; //显示内容
const unsigned char zi[];
void init(void) //初始化
{
wiringPiSetup();
fd = wiringPiI2CSetup(0x3c); // i2c初始化 0x3c是oled的从机地址
wiringPiI2CWriteReg8(fd, 0x00, 0xa1); //图像反了修改成0xa0
wiringPiI2CWriteReg8(fd, 0x00, 0xc8); //行输出反了修改成0xc0
wiringPiI2CWriteReg8(fd, 0x00, 0x8d); //允许电荷泵
wiringPiI2CWriteReg8(fd, 0x00, 0x14);
wiringPiI2CWriteReg8(fd, 0x00, 0xa6); //想反相显示改成0xa7
wiringPiI2CWriteReg8(fd, 0x00, 0x21); //重置列地址
wiringPiI2CWriteReg8(fd, 0x00, 0x00);
wiringPiI2CWriteReg8(fd, 0x00, 0x7f);
wiringPiI2CWriteReg8(fd, 0x00, 0xaf); //开显示
}
void qingping(void) //清屏
{
char zt1, zt2;
for (zt1 = 0; zt1 < 8; zt1++) {
wiringPiI2CWriteReg8(fd, 0x00, 0xb0 + zt1);
for (zt2 = 0; zt2 < 128; zt2++) wiringPiI2CWriteReg8(fd, 0x40, 0x00);
}
}
void ascii(void) //显示ASCII码8*16
{
int zt;
char zt3, zt4;
for (zt3 = 0; zt3 < 4; zt3++) {
wiringPiI2CWriteReg8(fd, 0x00, 0xb0 + (zt3 * 2));
for (zt4 = 0; zt4 < 16; zt4++)
for (zt = 0; zt < 8; zt++)
wiringPiI2CWriteReg8(fd, 0x40, zi[yi[zt3][zt4] * 16 + zt]);
wiringPiI2CWriteReg8(fd, 0x00, 0xb0 + (zt3 * 2) + 1);
for (zt4 = 0; zt4 < 16; zt4++)
for (zt = 0; zt < 8; zt++)
wiringPiI2CWriteReg8(fd, 0x40, zi[yi[zt3][zt4] * 16 + zt + 8]);
}
}
void shijian(void) //当前时间
{
struct tm *ptr;
time_t lt;
lt = time(<);
ptr = localtime(<);
// strftime(yi[1], 16, "%m/%d %a", ptr); //月/日 周几
strftime(yi[1], 16, "%R %p", ptr); //时:分 am或pm
}
void ipdisplay() { **//用于获得当前设备的ip地址**
FILE* fp;
char str[64];
fp = popen("ifconfig wlan0|grep \"inet\"|awk '{print $2}'", "r");
if (NULL == fp) {
printf("-1");
exit(-1);
}
fscanf(fp, "%s", str);
strcpy(yi[2], str);
fclose(fp);
}
void wendu() { **这里使用DS18B20温湿度传感器测量温度,具体操作可以 参考
https://blog.csdn.net/weixuedianzi/article/details/65935296 **
FILE* fp;
char str[64];
char tmp[64];
fp = fopen("/sys/bus/w1/devices/28-0315977961f4/w1_slave",
"r"); //以只读方式打开ds18b20设备文件
if (NULL == fp) {
printf("wendu fopen failed\n");
exit(-1);
}
while (fscanf(fp, "%s", str) != EOF)
;
strtok(str, "=");
char* p = strtok(NULL, "\n");
float temp = (float)atoi(p) / 1000;
sprintf(tmp, "%f", temp);
strcpy(yi[0], tmp);
}
void* oled_display(void* arg)
{
init();
qingping();
while (1) {
shijian();
wendu();
ipdisplay();
ascii();
delay(100);
}
return NULL;
}
超声波模块这里使用的是HC-SR04
#include <wiringPi.h>
#include <stdio.h>
#include <sys/time.h>
#define Trig 28
#define Echo 27
void wiring_init(void) {
wiringPiSetup(); //初始化树莓派的引脚
pinMode(Echo, INPUT); //设置某个引脚的是输入还是输出模式
pinMode(Trig, OUTPUT);
}
float wiring_distance(void) {
struct timeval tv1;
struct timeval tv2;
long start, stop;
float dis;
digitalWrite(Trig, LOW); //digitalWrite这里是给引脚一个低电平
delayMicroseconds(2);
digitalWrite(Trig, HIGH);
delayMicroseconds(10);
digitalWrite(Trig, LOW);
while (!(digitalRead(Echo) == 1))
;
gettimeofday(&tv1, NULL); //获取当前时间
while (!(digitalRead(Echo) == 0))
;
gettimeofday(&tv2, NULL); //获取当前时间
start = tv1.tv_sec * 1000000 + tv1.tv_usec;
stop = tv2.tv_sec * 1000000 + tv2.tv_usec;
dis = (float)(stop - start) / 1000000 * 34000 / 2; //求出距离
return dis;
}
小车驱动程序,这里由于树莓派没有带直流电机的驱动程序,所以使用了L9110S桥两路直流电机驱动板程序如下
#include <wiringPi.h>
#include <softPwm.h>
#include <stdio.h>
#include <stdlib.h>
//定义接口宏
#define PWM1A 22
#define LUN1 23
#define PWM2A 24
#define LUN2 25
//初始化
void che_init() {
softPwmCreate(LUN1, 0, 100); //softPwmCreat创建一个pwm波从既定引脚输出
softPwmCreate(LUN2, 0, 100);
softPwmCreate(PWM1A, 0, 100);
softPwmCreate(PWM2A, 0, 100);
printf("soft pwm create successfully..\n");
}
void go_head() {
softPwmWrite(PWM1A, 70);
softPwmWrite(LUN1, 0);
softPwmWrite(PWM2A, 70);
softPwmWrite(LUN2, 0);
}
void go_back() {
softPwmWrite(PWM1A, 0);
softPwmWrite(LUN1, 70);
softPwmWrite(PWM2A, 0);
softPwmWrite(LUN2, 70);
}
void go_left() {
softPwmWrite(PWM1A, 30);
softPwmWrite(LUN1, 0);
softPwmWrite(PWM2A, 70);
softPwmWrite(LUN2, 0);
}
void go_right() {
softPwmWrite(PWM1A, 70);
softPwmWrite(LUN1, 0);
softPwmWrite(PWM2A, 30);
softPwmWrite(LUN2, 0);
}
void go_quit()
{
softPwmWrite(PWM1A, 0);
softPwmWrite(LUN1, 0);
softPwmWrite(PWM2A, 0);
softPwmWrite(LUN2, 0);
}
void xiaochequdon(char* p) { //通过键盘输入控制方向
switch (*p) {
case 'w':
go_head();
break;
case 's':
go_back();
break;
case 'a':
go_left();
break;
case 'd':
go_right();
break;
case 'q':
go_quit();
break;
default:
break;
}
}
客户端程序
#include <stdio.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
int main(int a, char *avg[]) {
int s_fd;
int c_fd;
log_creat();
char readbuf[128];
struct sockaddr_in addr1;
s_fd = socket(AF_INET, SOCK_STREAM, 0); //配置套接字
if (s_fd == -1) {
perror("socker failed:\n");
exit(-1);
}
memset(&addr1, 0, sizeof(addr1));
addr1.sin_family = AF_INET;
addr1.sin_port = htons(atoi(avg[1]));
// addr1.sin_addr.s_addr = htonl(INADDR_ANY);
inet_aton("192.168.43.215", &addr1.sin_addr);
if(connect(s_fd,(struct sockaddr*)&addr1,sizeof(struct sockaddr_in))==-1)
{
printf("failed\n");
exit(-1);
}
printf("connect success\n");
char* c=(char*)malloc(32);
while(1){ //通过网络控制树莓派
printf("int put \n");
scanf("%c",c);
int ret=send(s_fd,c,1,0);
printf("ret=%d",ret);
ffplush(stdin);
// while(!getchar()=='\0');
}
return 0;
}