智能清洁桶项目

硬件需求:
树莓派、L9110模块、OLED显示屏、HC-SR04超声波模块、温度传感器、SG90舵机、马达及轮子、清洁桶。
架构:
远程控制服务端:树莓派。
远程控制客户端:linux虚拟机。
原理:
利用到网络编程、多线程、文件操作–日志模块,通过在linux虚拟机上远程控制小车,实现前进,后退,拐弯,避障等功能,利用超声波模块检测手是否靠近,然后通过sg90舵机模块将盖子打开,手拿开让盖子盖下;通过温度传感器检测温度,将温度显示在led模块上。
模块功能实现:
1.oled模块

const unsigned char zi[];
void oled() {
    int fd;
    unsigned char yi[4][16] = {"                  ",  //第一行
                               "                  ",  //第二行
                               "                  ",  //第三行
                               "made in zyt       "   //第四行
    };                                                //显示内容
    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);  //开显示

    char zt1, zt2;
    for (zt1 = 0; zt1 < 8; zt1++) {
        wiringPiI2CWriteReg8(fd, 0x00, 0xb0 + zt1);
        for (zt2 = 0; zt2 < 128; zt2++) wiringPiI2CWriteReg8(fd, 0x40, 0x00);
    }
    struct tm *ptr;
    time_t lt;
    lt = time(&lt);
    ptr = localtime(&lt);
    sprintf(yi[0], "wendu is %f\n", getwendu());
    strftime(yi[1], 16, "%m/%d %a", ptr);  //月/日 周几
    strftime(yi[2], 16, "%R %p", ptr);     //时:分 am或pm

    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]);
    }
}

2.日志模块

void log_open(char *buf) {
    fd = fopen(buf, "a+");
    if (fd == NULL) {
        printf("打开失败\n");
        exit(-1);
    }
}
void log_write(const char *pszFormat, ...) {
    va_list args;
    va_start(args, pszFormat);
    vfprintf(fd, pszFormat, args);
    va_end(args);
    fflush(fd);
}
void log_close() {
    fclose(fd); 
}

3.超声波模块
原理:通过计算超声波从发射到返回的时间从而得出距离,测试距离=(高电平时间声速(340M/S))/2;。

float getdis()
{
	pinMode(Trig,OUTPUT);
	pinMode(Echo,INPUT);
	struct timeval t1;
	struct timeval t2;
	long start;
	long stop;
	float dis;
	digitalWrite(Trig,LOW);
	digitalWrite(Trig,HIGH);
	delayMicroseconds(10);
	digitalWrite(Trig,LOW);

	while(digitalRead(Echo)!=1)
	{
		gettimeofday(&t1,NULL);
		}
		while(digitalRead(Echo)!=0)
		{
			gettimeofday(&t2,NULL);
			}
	 start = t1.tv_sec * 1000000 + t1.tv_usec;  
     stop  = t2.tv_sec * 1000000 + t2.tv_usec;  
	 dis = (float)(stop - start) / 1000000 * 34000 / 2;
	 return dis;
	}

4.l9110驱动电机模块
原理:4个IO口分别控制两个电机的正反转,若要使小车向前走,即将GPIO1A、2A拉高即可。

void left()
{
	digitalWrite(GPIO1A,HIGH);
	digitalWrite(GPIO1B,LOW);
	digitalWrite(GPIO2A,LOW);
	digitalWrite(GPIO2B,LOW);
	}
void right()
{
	digitalWrite(GPIO1A,LOW);
	digitalWrite(GPIO1B,LOW);
	digitalWrite(GPIO2A,HIGH);
	digitalWrite(GPIO2B,LOW);
	}
void back()
{
	digitalWrite(GPIO1A,LOW);
	digitalWrite(GPIO1B,HIGH);
	digitalWrite(GPIO2A,LOW);
	digitalWrite(GPIO2B,HIGH);
	}
void ahead()
{
	digitalWrite(GPIO1A,HIGH);
	digitalWrite(GPIO1B,LOW);
	digitalWrite(GPIO2A,HIGH);
	digitalWrite(GPIO2B,LOW);
	}
void initxiaoche()
{
	digitalWrite(GPIO1A,LOW);
	digitalWrite(GPIO1B,LOW);
	digitalWrite(GPIO2A,LOW);
	digitalWrite(GPIO2B,LOW);
	}

5.温度传感器
从/sys/bus/w1/devices/28-031697799236/w1_slave 文件中读取温度的值。

float getwendu() {
    FILE *fd;
    float temp;
    char *p;
    char readbuf[256];
    fd = fopen("/sys/bus/w1/devices/28-031697799236/w1_slave", "r");
    if (fd == NULL) {
        printf("fopen wendu failed\n");
        return -1;
    }
    if (fread(readbuf, sizeof(readbuf), 1, fd) < 0) {
        printf("fread wendu failed\n");
        return -1;
    }
    p = strstr(readbuf, "t=");
    if (p == NULL) {
        printf("find \"t=\" failed\n");
        return -1;
    }
    p = p + 2;
    temp = atof(p) / 1000;
    // printf("wendu is %0.3f\n",temp);
    // delay(1000);
    fclose(fd);
    return temp;
}

网络编程相关代码:

	int mark;
    int fd;
    struct sockaddr_in addr;
fd = socket(AF_INET,SOCK_STREAM,0);
    if(fd < 0)
    {
    log_write("server socket failed\n");
    return -1;
    }
     memset(&addr,0,sizeof(addr));
     addr.sin_family = AF_INET;
     addr.sin_port = SERVER_PORT;
     addr.sin_addr.s_addr = htonl(INADDR_ANY);
     int on = 1;
     setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
     int b;
     b = bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
     if(b<0)
     {
        log_write("server bind failed\n");
        return -1;
     }
     listen(fd,10);
     mark = accept(fd,NULL,NULL);
     if(mark < 0)
     {
     log_write("accept failed\n");
     return -1;
     }else{
     log_write("accept success\n");
     }

    struct sockaddr_in addr;
    int mark;
    int fd;
 fd = socket(AF_INET,SOCK_STREAM,0);
    if(fd == -1)
    {
    log_write("cilent socket failed\n");
    }
     memset(&addr,0,sizeof(addr));
     addr.sin_family = AF_INET;
     addr.sin_port = SERVER_PORT;
     inet_aton("172.20.10.11",&addr.sin_addr);
     mark=connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
     if(mark < 0)
     {
     log_write("cilent connect failed\n");
     }

线程创建:

	int crt;
	pthread_t t1;
	pthread_t t2;
	pthread_t t3;
	crt = pthread_create(&t1,NULL,led,(void *)&mark);
	 if(crt < 0)
	 {
		 log_write("create t1 failed\n");
		 return -1;
		 }
	 crt = pthread_create(&t2,NULL,duoji,(void *)&mark);
	 if(crt < 0)
	 {
		 log_write("create t2 failed\n");
		 return -1;
		 }
	 crt = pthread_create(&t3,NULL,dianji,(void *)&mark);
	 if(crt < 0)
	 {
		 log_write("create t3 failed\n");
		 return -1;
		 }
	pthread_join(t1,NULL);	 
	pthread_join(t2,NULL);	 
	pthread_join(t3,NULL);	 
	void *led()
	{
	while(1)
	{
		oled();
		delay(5000);
		}
	}
	void *duoji ()
	{
	  int pin = 1;
 	  int i;
	   			 softPwmCreate (pin, 5, RANGE);
			while(1)
			{
				if(getdis()<10)
				{
					softPwmWrite(pin,25);
				 	delay(1000);				
					}
				if(getdis()>10)
				{
				    softPwmWrite(pin,5);   //将pwm输出复写为使舵机转到0
	    			delay(1000);
					}	
			}
				exit(0);
	}

void *dianji(void *arg)
{
	int data = *(int *)arg;
	char *buf = malloc(32); 
	while(1)
	{
		recv(data,buf,sizeof(buf),0);
		log_write("read a from data :%s",buf);
		switch (*buf)
		{
		case 'w':	ahead();
			break;
		case 's':	back();
			break;
		case 'a':	left();
			break;
		case 'd':	right();
			break;
		case 'q':   initxiaoche();
			break;
		default:
			break;
			}
		memset(buf,0,sizeof(buf));	
			}
	}

遇到的问题:
在编程时,L9110模块驱动电机这一部分给我造成了很大的困扰,即只能驱动两个电机正转反转,而不能驱动单个轮子转动,在排查了一系列问题之后,初步判断是L9110模块的问题。

多线程的原理:
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序的全局内存和堆内存、栈以及文件描述符。 典型的UNIX/Linux进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情。有了多个控制线程后,在程序设计时可以把进程设计成在同一时刻做不止一件事,每个线程各自处理独立的任务。
相关API在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值