Arduino+Python 测距雷达

舵机效果演示视频

目录

1 Arduino 舵机

2 Arduino 超声波传感器

3 舵机+测距传感器

4 Python 绘制动态雷达


1 Arduino 舵机

接线图:

 执行代码:

#include <Servo.h>

#define  ServoPin  3
Servo baseServo;
int angle_s;

int sign;


void setup() {
  baseServo.attach(ServoPin); // 初始化舵机
  angle_s = 180;
  baseServo.write(angle_s);

  sign=1;
}

void loop() {
  while(true){
    baseServo.write(angle_s);
    angle_s+=1;
  }

  while (true) {
    baseServo.write(angle_s);     // 舵机转动到angle角度
    Serial.print("angle: ");   // 在控制台打印出 angle: 180\n
    Serial.println(angle_s);
    
    angle_s += sign;               // 角度增加或减少
    if (angle_s >= 180 || angle_s <= 0) {     // 当angle转到180°时,i=-1,开始递减; 
      sign *= -1; //sign=sign*-1              // 当angle转到0°时,  i=1, 开始递增;
    }
  }


}

2 Arduino 超声波传感器


#include <SPI.h>
#define  trigPin   6  //超声波模块的Trig 6#
#define  echoPin   5  //超声波模块的echo 5#

// 超声波模块
long duration;
int distance;

int calculateDistance(){ 
 //超声波测距后,将距离换算成厘米数,反回。
 digitalWrite(trigPin, LOW); 
 delayMicroseconds(2);
 digitalWrite(trigPin, HIGH); 
 delayMicroseconds(10);
 digitalWrite(trigPin, LOW);
 duration = pulseIn(echoPin, HIGH); 
 distance= duration*0.034/2;
 return distance;
}


void setup() {
 pinMode(trigPin, OUTPUT); //超声波模块发射
 pinMode(echoPin, INPUT); //超声波模块接收 
 Serial.begin(9600);

}

void loop() {
 distance = calculateDistance();
 Serial.println(distance); 

}

3 舵机+测距传感器

//#include <SPI.h>
#include <Servo.h>

// 超声波模块
#define  trigPin   6  //超声波模块的Trig 6#
#define  echoPin   5  //超声波模块的echo 5#
long duration;
int d;

// 舵机模块
#define  ServoPin  3  //底座舵机端口 3#
Servo myServo;
int angle_;
int i = 1;

void setup() {
 Serial.begin(9600);
 myServo.attach(ServoPin); //初始化舵机
 pinMode(trigPin, OUTPUT); //超声波模块发射
 pinMode(echoPin, INPUT); //超声波模块接收
 


}

void loop() {

 while (1) {
   delay(300);
   // 开启舵机
   myServo.write(angle_);
   Serial.print("a:");
   Serial.print(angle_);
   Serial.print(";");
   

   // 计算距离
   d = calculateDistance();
   Serial.print("d:");
   Serial.println(d);
   
   angle_ += i;
   if (angle_ >= 180 || angle_ <= 0) {
     i *= -1;
   }

 }

}


int calculateDistance() {
//超声波测距后,将距离换算成厘米数,反回。
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
d = duration * 0.034 / 2;
return d;
}

4 Python 绘制动态雷达

from plot8 import sub_plot_c
import random

pl = sub_plot_c()

for i in range(0,180):
    d = random.randint(0, 40)
    pl.update(angle=i, c=45, Clockwise=False, alpha=0.1, distance=d)
    pl.draw_img()
    pl.clear()

for i in range(180,0,-1):
    d = random.randint(0, 40)
    pl.update(angle=i, c=45, Clockwise=True, alpha=0.1, distance=d)
    pl.draw_img()
    pl.clear()


from matplotlib import colors, pyplot as plt
import math
import numpy as np
import random

# 目标:每扫描一个角度的点, 替换该点, 其他的保留

class sub_plot_c:
    	
	def __init__(self):
		self.x = 0
		self.x_list = []
		self.y_list = []

		# 底线高度
		self.base_height = 0
		# 雷达图半径长度
		self.r_length = 800

		self.fig = plt.figure(figsize=(16, 10))    # 1500 * 1000    w = 1.5h
		self.n = 1500 / 1000

		self.angle = 20
		self.c = 30
		self.Clockwise = False     # 逆时针 pre在左, 顺时针 pre在右


		# 扫描透明度
		self.alpha = 1.0

		# 图像背景
		self.backgroud_inside = "#0A2B56"
		self.backgroud_outside = "#1675CC"
		self.line_color = 'white'
		self.sector = 'white'

		# 标记点类型
		self.mark_s = ['o','<','>','s','p','*','+','D','d']
		self.mark_col = ['#E9E7D0', '#49AED5', 'blue']

		# 每个角度上存储一种标记
		self.mark_dict = {}     #[angle, [distance, mark_s, mark_c,]]
		self.current_distance = 30
		self.max_distance = 30
		self.mark_scale = self.r_length / self.max_distance

		self.count = 0




		self.ax = self.fig.add_subplot()
		plt.ion()





	def update(self, angle, c, Clockwise, alpha, distance):
		self.angle = angle
		self.c = c
		self.Clockwise = Clockwise
		self.alpha = alpha
		self.current_distance = distance

	# 交由外部清空
	def clear(self):
		plt.pause(0.1)         # 动画延迟
		plt.ioff()             # 关闭画图的窗口
		plt.clf() 


	def draw_img(self):     
		
		# 画固定图形
		# 底线
		plt.plot([-self.r_length, self.r_length], [self.base_height, self.base_height], color=self.line_color)    # x1,x2  y1,y2
        

		# 半圆, 弧度0-pi, 整圆, 弧度0-2*pi
		theta = np.linspace(0, math.pi,180*3)
		# 2*pi*r, x,y为数组
		x,y = np.cos(theta)*self.r_length, np.sin(theta)*self.r_length
		y += self.base_height
        
		# plt.plot(x, y, color='black')

		# 画外部背景
		x_bg = np.linspace(-self.r_length, self.r_length, 100)
		y_circle_bg = np.sqrt(1-(x_bg/self.r_length)*(x_bg/self.r_length)) * self.r_length
		y_circle_bg += self.base_height

		# 画内圆背景
		plt.fill_between(x_bg, self.base_height, y_circle_bg, facecolor=self.backgroud_inside, interpolate=True)


		# 画外圆线1
		plt.plot(x, y, color=self.line_color, linewidth=1)

		# 画外圆线2	
		x_2,y_2 = np.cos(theta)*self.r_length*0.8, np.sin(theta)*self.r_length*0.8
		y_2 += self.base_height

		plt.plot(x_2, y_2, color=self.line_color, linewidth=1)

		# 画外圆线3	
		x_3,y_3 = np.cos(theta)*self.r_length*0.6, np.sin(theta)*self.r_length*0.6
		y_3 += self.base_height

		plt.plot(x_3, y_3, color=self.line_color, linewidth=1)


		# 画外圆线4	
		x_4,y_4 = np.cos(theta)*self.r_length*0.4, np.sin(theta)*self.r_length*0.4
		y_4 += self.base_height

		plt.plot(x_4, y_4, color=self.line_color, linewidth=1)


		# 画外圆线5	
		x_5,y_5 = np.cos(theta)*self.r_length*0.4, np.sin(theta)*self.r_length*0.4
		y_5 += self.base_height

		plt.plot(x_5, y_5, color=self.line_color, linewidth=1)


	

        

		########################################   画扇形 start  ###################################################

		# pre, end两条线, 前后线在来回摆动的过程中会发生位置的互换,   # 图示标出

		x_pre_angle = round(math.cos(math.radians(self.angle)),2)
		y_pre_angle = round(math.sin(math.radians(self.angle)),2)

		# 扇形角度
		angle_sec = self.angle + self.c if  self.Clockwise else self.angle - self.c
		x_end_angle = round(math.cos(math.radians(angle_sec)),2) 
		y_end_angle = round(math.sin(math.radians(angle_sec)),2) 

		# 五种状态: 
		# 1. pre在第二象限, end在第一象限, 扇形面积 = (圆-pre) - (end-base_height);
		# 2. pre,end都在第二象限, 扇形面积 = (圆-pre) - (圆-end);
		# 3. pre,end都在第一象限, 扇形面积 = (圆-pre) - (圆-end);
		# 4. end 与 90°重合, 扇形面积 = (圆-pre)
		# 5. pre 与 90°重合, 扇形面积 = (圆-end)

		x_pre = x_pre_angle * self.r_length
		y_pre = y_pre_angle * self.r_length

		x_end = x_end_angle * self.r_length
		y_end = y_end_angle * self.r_length


		# 构建填充数据集
		if self.Clockwise :
			if self.angle + self.c <= 180:             # 解决夹角过小,无法填充满的问题
				x_left = x_end
				x_right = x_pre
			else:
				x_left = -self.r_length
				x_right = x_pre
		else:
			if self.angle >= self.c:
				x_left = x_pre
				x_right = x_end
			else:
				x_left = x_pre
				x_right = self.r_length


		if max([x_pre, x_end]) < 0:
			x_right = 0
		elif min([x_pre, x_end]) > 0:
			x_left = 0

		x = np.linspace(x_left, x_right, 100)

		# x=sqrt(1-sin(theta)^2)*r   (x/r)^2 = 1 - sin(theta)^2    sin(theta)^2 = 1-(x/r)^2    sin(theta) = sqrt(1-(x/r)^2)  y=sqrt(1-(x/r)^2)*r

		# pre边的斜率
		if x_pre != 0:
			k_pre_line = ((y_pre + self.base_height) -(0 + self.base_height)) / (x_pre-0)
			y_pre_line = k_pre_line * x 

			y_pre_line += self.base_height


		# 圆周的描点
		# x=sqrt(1-sin(theta)^2)*r   (x/r)^2 = 1 - sin(theta)^2    sin(theta)^2 = 1-(x/r)^2    sin(theta) = sqrt(1-(x/r)^2)  y=sqrt(1-(x/r)^2)*r
		y_circle = np.sqrt(1-(x/self.r_length)*(x/self.r_length)) * self.r_length


		# end边的斜率
		if x_end != 0:
			k_end_line = ((y_end+self.base_height) -(0+self.base_height)) / (x_end-0)
			y_end_line = k_end_line * x 

			y_end_line += self.base_height


		# 加上向上偏移
		y_circle += self.base_height


		x_temp = x - 1 if self.Clockwise else  x + 1
		# 1.
		if (x_pre_angle < 0 and x_end_angle > 0) or (x_pre_angle > 0 and x_end_angle < 0):
			
			plt.fill_between(x, y_pre_line, y_circle, facecolor=self.sector, interpolate=True, alpha = self.alpha)
			
			plt.fill_between(x_temp, self.base_height, y_end_line, facecolor=self.backgroud_inside,interpolate=True)


		# 2. 

		elif x_pre_angle < 0 and x_end_angle < 0:

			plt.fill_between(x, self.base_height, y_circle, facecolor=self.sector, interpolate=True, alpha = self.alpha)

			if self.Clockwise:
				x_temp_2 =   x + 1
				plt.fill_between(x_temp_2, y_pre_line, y_circle, facecolor=self.backgroud_inside,interpolate=True)
				plt.fill_between(x_temp, self.base_height, y_end_line, facecolor=self.backgroud_inside,interpolate=True)
			
			else:
				x_temp_2 =   x - 1
				plt.fill_between(x_temp, y_end_line, y_circle, facecolor=self.backgroud_inside,interpolate=True)
				plt.fill_between(x_temp_2, self.base_height, y_pre_line, facecolor=self.backgroud_inside,interpolate=True)

		# 3.
		elif x_pre_angle > 0 and x_end_angle > 0:

			plt.fill_between(x, self.base_height, y_circle, facecolor=self.sector, interpolate=True, alpha = self.alpha)

			if self.Clockwise:
				x_temp_2 =   x + 1
				plt.fill_between(x_temp_2, self.base_height, y_pre_line, facecolor=self.backgroud_inside,interpolate=True)
				plt.fill_between(x_temp, y_end_line, y_circle, facecolor=self.backgroud_inside,interpolate=True)
			
			else:
				x_temp_2 =   x - 1
				plt.fill_between(x_temp, self.base_height, y_end_line, facecolor=self.backgroud_inside,interpolate=True)
				plt.fill_between(x_temp_2, y_pre_line, y_circle, facecolor=self.backgroud_inside,interpolate=True)

		# 4.
		elif x_end_angle == 0:
			plt.fill_between(x, y_pre_line, y_circle, facecolor=self.sector, interpolate=True, alpha = self.alpha)

		# 5.
		elif x_pre_angle == 0:
			plt.fill_between(x, y_end_line, y_circle, facecolor=self.sector, interpolate=True, alpha = self.alpha)


		print(x_pre_angle, x_end_angle, )


		plt.fill_between(x, 0, self.base_height, facecolor=self.backgroud_outside, interpolate=True)





		########################################   画扇形 end  ###################################################




		# 画外圆背景
		plt.fill_between(x_bg, y_circle_bg, 1000, facecolor=self.backgroud_outside, interpolate=True)

		# 画下面的背景
		plt.fill_between(x_bg, 0, self.base_height, facecolor=self.backgroud_outside, interpolate=True)



		# 画刻度表示
		plt.fill_between(x_bg, y_circle_bg, 1000, facecolor=self.backgroud_outside, interpolate=True)

		# 画数据标识
		plt.fill_between(x_bg, 0, self.base_height, facecolor=self.backgroud_outside, interpolate=True)

		# 画刻度线标识 从0到180度, 每20°标记一下
		for angle_text in range(0, 181, 20):
			x_text = round(math.cos(math.radians(angle_text)),2) * self.r_length
			y_text = round(math.sin(math.radians(angle_text)),2) * self.r_length

			x_text -= 8
			y_text += self.base_height + 2
			plt.text(x_text, y_text, str(angle_text),fontsize=12, color = '#38C0B0')

		
		# 记录数据
		plt.text(-self.r_length, 950, 'Randar Scan: ',fontsize=25, color = 'white')
		plt.text(-self.r_length + 340, 950, 'ON',fontsize=25, color = 'white')

		plt.text(-self.r_length, 900, 'Pluse: ',fontsize=20, color = 'white')
		plt.text(-self.r_length + 160, 900, 'S2',fontsize=20, color = 'white')


		plt.text(-self.r_length, 860, 'current_angle: ',fontsize=15, color = 'white')
		plt.text(-self.r_length + 270, 860, str(self.angle),fontsize=15, color = 'white')

		plt.text(-self.r_length, 820, 'current_distance: ',fontsize=15, color = 'white')
		plt.text(-self.r_length + 270, 820, str(self.current_distance),fontsize=15, color = 'white')

		plt.text(-self.r_length, 780, 'current_count: ',fontsize=15, color = 'white')
		plt.text(-self.r_length + 270, 780, str(self.angle),fontsize=15, color = 'white')



		# 画标记点
		s = random.randint(0, len(self.mark_s)-1)
		c = random.randint(0, len(self.mark_col)-1)
		# plt.plot(100, 100, self.mark_s[s], color=self.mark_col[c])


        #############################  根据距离画点 start  ######################################
        # 如果当前点的距离没发生变化, 则不更新
        # 如果当前点的距离大于30,则画空值, 如果小于30,则位置信息全部更新

        #[angle, [distance, mark_s, mark_c,]]
        
		if self.angle not in self.mark_dict.keys():
			if self.current_distance <= self.max_distance:
				self.mark_dict[self.angle] = [self.current_distance, self.mark_s[s], self.mark_col[c]]
				self.count += 1
			else:
				self.mark_dict[self.angle] = [0, self.mark_s[s], self.mark_col[c]]

		
		if self.mark_dict[self.angle][0] != self.current_distance:
			if self.current_distance > self.max_distance:
				self.mark_dict[self.angle] = [self.current_distance, "", self.mark_col[c]]
				self.count -= 1
			else:
				self.mark_dict[self.angle] = [self.current_distance, self.mark_s[s], self.mark_col[c]]
				if self.mark_dict[self.angle][0]:
					self.count +=1
        
        # 打印出所有点
		for k,v in self.mark_dict.items():
			x_mark = round(math.cos(math.radians(k)),2) * v[0] * self.mark_scale
			y_mark = round(math.sin(math.radians(k)),2) * v[0] * self.mark_scale
			plt.plot(x_mark, y_mark, v[1], color=v[2])


		




		plt.axis('off')
		plt.xlim(-self.r_length, self.r_length)
		plt.ylim(0, 1000)






	def release():
    		plt.show()




  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值