ESP32로 라이다 분석용 코드를 포팅했습니다. 그리고 검증용으로 PC로 x,y 점들을 보내게 했더니 나오네요.

카카오를 안써서 이곳에 영상을 못올립니다. 

영상과 선 연결 정보등은 페북에서 :  www.facebook.com/groups/airoboticskr/posts/1146125082811698/

 

로그인 또는 가입하여 보기

Facebook에서 게시물, 사진 등을 확인하세요.

www.facebook.com

ESP32 쪽은 현재는 거의 초벌수준인 아주 엉성한 코드입니다.   PC쪽은 자신이 원하는 아무 프로그램으로 직접 만드셔야 합니다.

#define RXD2 16 // This line connects to TX of Lidar 
#define TXD2 17 // is not used

/*  On ESP32, there are D/A pin which emits voltage.
 *  You can set 5th pin of lidar to this D/A pin to change speed.
 *  0V = Maximum speed, 5V is Slowest or Stop.
 */

int machine_pack_type = 40; // only 1 machine out of 4 of mine is 60, rests are 40
const int BUFFER_SIZE = 200;
char buf[BUFFER_SIZE];
String s;
String rs;
int i, j, k, counter, rmax, pack_type, data_length, start_angle, stop_angle;
int diff, length3, dataOk = 0;
int distance, data0, data1, data2, angle ;
float steplength, angle_per_sample, distanceDivided, anglef, distanceInMeter;
bool LadarActive = true;
int FullCircleDataSize = 0;
int ThisRoundCount = 0, maxThisRound = 0, x, y;
float anglePlus;

enum States {
   START1 = 0,
   START2 = 1,
   HEADER = 2,
   DATA = 3
};

float angle_list[120];
float distance_list[120];
int   quality_list[120];

States state;

void serial2Flush(){
  while(Serial2.available() > 0) {
    char t = Serial2.read();
  }
}

void setup() {
   steplength = (PI*2);
   anglePlus  = PI/2;
   state = START1;
  
   Serial.begin(230400);  // To PC
   Serial2.begin(153600, SERIAL_8N1, RXD2, TXD2); // To Ridar
   s.reserve(200);    s = "";
   rs.reserve(260); rs = "";  // string to pass data
}

void loop() { 
   if (LadarActive) {
      if (Serial2.available() > 0) {  // Look for AA55
         if (state == START1) {
            dataOk = Serial2.readBytes(buf, 1);
            // Serial.println(dataOk); // 1 came out
            if (dataOk == 1) { 
               if (buf[0] == 0xAA) {
                  state = START2;
               } 
            }
         } else if (state == START2) {  // Confirm 55
            dataOk = Serial2.readBytes(buf, 1); 
            // Serial.println(dataOk); // 1 came out
            if (dataOk == 1) { 
               if (buf[0] == 0x55) {
                  state = HEADER;
               } else {
                  state = START1;
               }
            }
         } else if (state == HEADER) {   // Read main data
            dataOk = Serial2.readBytes(buf, 8);
            // Serial.println(dataOk);  // 8 came out
            if (dataOk == 8) { 
               pack_type = buf[0];
               data_length = int(buf[1]);
               start_angle = int(buf[3] << 8) + int(buf[2]);
               stop_angle  = int(buf[5] << 8) + int(buf[4]);
            
               diff = stop_angle - start_angle;
               if (stop_angle < start_angle) {
                  diff =  0xB400 - start_angle + stop_angle;
               }

               angle_per_sample = 0;
               if ((diff > 1) and ((data_length-1) > 0)) {
                  angle_per_sample = diff / (data_length-1);
               }

               // Debug 
               s = ("#") + String(counter)
                  + (" t:") + pack_type
                  + (" l:") + data_length 
                  + (" sa:")+ start_angle 
                  + (" ta:")+ stop_angle
                  + (" f:") + diff
                  + (" as:")+ round(angle_per_sample);
               //Serial.println(s);
               
               FullCircleDataSize += data_length;

               counter += 1;
               if (pack_type != machine_pack_type) {  // default = 40, for some device = 60
                  // about every 40 cycles, one full circle done.
                  s = ("Counter : ") + String(counter-1) 
                     + (" Cycle Size : ") + String(FullCircleDataSize*3);
                  //Serial.println(s);
                  //Serial.println("*"); // Send End of 1 Full Cycle
                  counter = 0;
                  FullCircleDataSize = 0;
               }
               state = DATA;  
               rs = ""; 
            }       
         } else if (state == DATA) {   // Read main data
            state = START1;
            length3 = data_length * 3;
            dataOk = Serial2.readBytes(buf, (length3));

            s = " Data_length : " + String(data_length) 
               + "  dataOk :" + String(dataOk);
            // Serial.println(s); // usually 40, 120 came out
            
            if (dataOk == length3) { 
               for (int i = 0; i < data_length; i++) {
                  data0 = int(buf[i*3 + 0]);
                  data1 = int(buf[i*3 + 1]);
                  data2 = int(buf[i*3 + 2]); 
                  distance = (data2 << 8) + data1;

                  angle = (start_angle + angle_per_sample * i);
                  // 0xB400 = 46080, steplength = 2*PI, angle sample 20006
                  anglef = (steplength * angle) / 0xB400; // steplength = 2*PI
                  distanceDivided = distance / 100;

                  if (distanceDivided < 60) {
                     distanceInMeter = (distance/5); // div to convert mm to meter
                     y = distanceDivided * cos(anglef);
                     x = distanceDivided * sin(anglef);
                     // 0:556.00-556~0  // 1739:324.00-324~0
                     //rs += String(anglef) +(":") + String(distanceInMeter) + ("-")
                     //   + String(x) + ("~") + String(y) +(", "); 
                     if ((x != 0) and (y != 0)) { 
                        rs += ("[") + String(x) + (":") + String(y) + ("]");  
                     }
                     if (rs.length() > 240) { 
                         Serial.println(rs);  
                         rs = "";
                     }
                     serial2Flush();
                  }
                    
               //   angle_list[i] = anglef;

               //   distance_list[i] = distance / 1000; // div to convert mm to meter
               //   quality_list[i] = data0;
               }
               Serial.println(rs); // send remaining
               if (pack_type != machine_pack_type) { // default = 40, for some device = 60
                  // Draw stuffs now if OLED is attached
                  Serial.println("*"); // Send End of 1 Full Cycle
               }
               /*if (data_length > 0) {  // Draw data or prepare data to send
                  // Debug 
                  s = " Data_length : " + data_length;
                  //Serial.println(s);
                  for (int i = 0; i < data_length; i++) {
                     s += String(angle_list[i]) + (", ");
                  }
                  //Serial.println(s);
               }*/
            }
            
         }
        
      } 
      
   }
}

 

 

Simple pass-thru : (my local folder :  /SHARE/TTGO_Liligo/rider01_path_thru_esp32)

#define RXD2 16  
#define TXD2 17 // is not used

const int BUFFER_SIZE = 500;
char buf[BUFFER_SIZE];

void setup() {
//  Serial.begin(230400);  // To Lazarus App
  Serial.begin(250000);  // To PC
  Serial2.begin(153600, SERIAL_8N1, RXD2, TXD2); // To Ridar
}

void loop() { 
  while (Serial2.available()){
    Serial.print(char(Serial2.read())); 
  }
}

 

'폐품 Lidar 살리기' 카테고리의 다른 글

헐값 폐품 Lidar 살리기. ($13 + 배송)  (0) 2021.07.18

제 구매처 : https://www.aliexpress.com/item/4001253880158.html?spm=a2g0s.9042311.0.0.51cd4c4dFsfQSj&fbclid=IwAR1rvYLt_6CMDVgvjOSD-1njVUQhOB2RBI6-sXNhqkfqUt-XzrxOjSF72IM 

 

13.55US $ |laser radar 360 degree laser radar scanning distance measuring sensor diy wireless transmission infrared data transmi

Smarter Shopping, Better Living! Aliexpress.com

www.aliexpress.com

윗 제품을 한 번 사서 살려봤는데, 제 능력보다는 어떤 이가 어제 딱 성공을 해서 웹에 올려놓은 덕에 저도 따라서 베껴서 성공했습니다.

 

동영상 페북 링크 : https://www.facebook.com/permalink.php?story_fbid=4071094949677690&id=100003316754962&notif_id=1626497694343936&notif_t=feedback_reaction_generic&ref=notif 

 

로그인 또는 가입하여 보기

Facebook에서 게시물, 사진 등을 확인하세요.

www.facebook.com

 

 

 

중요한 내용 : 

     제품 마크 : Radar_MB_1R2T_V1.5.8  or V.1.5.9 <==  제품 밑에 반드시 이 마크가 있는 제품에 국한된 내용입니다.

     헤더 : AA 55 28 28

     시리얼 속도 : 153600

     처음 테스트용 라이다와 PC의 연결은 흔한 $2짜리 USB<=>UART 모듈을 사용하시면 됩니다.

     핀 연결 : 저기 속도 조정 핀은 연결 안해도 됩니다.   

     Serial은 3.3V

     전원은 5V

중요한 화일들 :  화일 이름은 편하게 각자 정하면 됩니다.  저는 my_lidar.py라고 부릅니다.

   이게 메인 Working Code입니다. 

 

   Credit : Vidicon from Discord, Subject : zRGJcqa, #radar_mb_1r2t

 

아래 코드는 matplotlib를 사용해서 너무 느려서, 아래 코드를 사용하지 말고  PyQtGraph 라이브러리를 사용해서 완전히 다시 만든 코드를 사용하십시요.   속도가 100배는 차이가 나는 것 같습니다. 제가 직접 PyQtGraph를 배워가며 만들었습니다.

엄청 빠른 새 코드는 다음 링크에 있습니다. https://wise-self.tistory.com/78?category=1044077

 

아래 코드는 그냥 구조를 보기 좋으니 데이타 구조가 어떤가를 보기용으로만 쓸만합니다.

주의사항은 serial 라이브러리 설치시 pip3 install pyserial 을 해야지, pip3 install serial을 하시면 안됩니다.  (중요)

#!/usr/bin/env python3
import matplotlib.pyplot as plt
import sys
import serial
import time
from enum import Enum
import math

SERIAL_PORT = "/dev/ttyUSB0"

class State(Enum):
	START1 = 0
	START2 = 1
	HEADER = 2
	DATA = 3


def readbytes(file, count):
	data = ser.read(count)
	if len(data) != count:
		print("End of file")
		return False
	return data


if __name__ == "__main__":
		
	try:
		ser = serial.Serial(SERIAL_PORT, 153600, timeout=0.1) 
	except:
		print("could not connect to device")
		exit()
	counter = 0
	rmax = 10.0
	
	dist = plt.subplot(111, polar = True)
	
	data_lenght = 0
	start_angle = 0
	stop_angle = 0


	run = True
	step = (-math.pi*2) 
	try:
		state = State.START1
		while run:

			if state == State.START1:
				data = ser.read(1)
				#if data == False:
				#	break
				if data[0] == 0xAA:
					state = State.START2
				# else:
					# print("sync")
				continue
			elif state == State.START2:
				data = ser.read(1)
				#if data == False:
				#	break
				if data[0] == 0x55:
					state = State.HEADER
				else:
					state = State.START1
					# print("sync2")
				continue
			elif state == State.HEADER:
				data = ser.read(8)
				pack_type = data[0]
				data_lenght = int(data[1])
				start_angle = int(data[3] << 8) + int(data[2])
				stop_angle = int(data[5] << 8) + int(data[4])
				#unknown = int(data[7] << 8) + int(data[6])

				diff = stop_angle - start_angle
				if stop_angle < start_angle:
					diff =  0xB400 - start_angle + stop_angle

				angle_per_sample = 0
				if diff > 1 and (data_lenght-1) > 0:
					angle_per_sample = diff / (data_lenght-1)
				
				# print("[{}]\ttype:{},\tlenght {},\tstart: {},\tstop: {}, \tdiff: {} \tdiff: {}".format(counter, pack_type, data_lenght, start_angle, stop_angle, diff, angle_per_sample), end="\n")
				
				counter += 1
				if pack_type != 40:
					counter = 0

				state = State.DATA
				continue
				
			elif state == State.DATA:
				state = State.START1
				#read data
				data = ser.read(data_lenght * 3)
				#data = readbytes(f, data_lenght * 3) 
				if data == False:
					break
		
				angle_list = []
				distance_list = []
				quality_list = []
		
				for i in range(0, data_lenght):
					
					data0 = int(data[i*3 + 0])
					data1 = int(data[i*3 + 1])
					data2 = int(data[i*3 + 2]) 
					distance = (data2  << 8) + data1

					angle = (start_angle + angle_per_sample * i)
					anglef = step * (angle / 0xB400) 
					angle_list.append(anglef)

					distance_list.append(distance / 1000) # div to convert mm to meter
					quality_list.append(data0) 

				
				if pack_type != 40:
					plt.cla()
					continue # package contance no data skip plot

				dist.scatter(angle_list, distance_list, c = "purple", s = 3) # dot
				# dist.plot(angle_list, distance_list, c = "purple") # line 
				dist.scatter(angle_list, quality_list, c = "red", s = 1)

				dist.set_theta_offset(math.pi / 2)
				dist.set_rmax(rmax)
				dist.set_rmin(0.0)
				plt.pause(0.01)
				rmax = dist.get_rmax()
				
			else:
				print("error")
	

	except KeyboardInterrupt:
		run = False
		exit()

최근에 물건을 3개를 더 받았는데 그 중 2개가 Radar_MB_1R2T_V1.5.8  이 아니고 Radar_MB_1R2T_V1.5.9 이었습니다.

그리고 그 중 1개는 윗 코드로는 작동을 안해서 원인을 찾아보니, 오는 신호에서 type 이 다른 제품들은 40이었는데 이 한개만 60번으로 나오더군요.   찾아낸 방법은 코드의 라인 84번의 #를 풀면 라이다에서 나오는 신호를 분석해서 스크린에 뿌려줍니다.

그래서 그 제품 하나는 따로 코드를 만들었습니다.  라인 87과 120에 type의 값을 40에서 60으로 바꿨더니 작동하더군요.

======================================================================

저번에 이 라이다의 문제를 해결한 이가 이 라이다의 ROS v.1용 드라이버도 완성했습니다. 현재는 초벌입니다.

 https://github.com/Vidicon/mb_1r2t_ros

 

GitHub - Vidicon/mb_1r2t_ros: ROS1 driver for the mb_1r2t lidar

ROS1 driver for the mb_1r2t lidar. Contribute to Vidicon/mb_1r2t_ros development by creating an account on GitHub.

github.com

 

'폐품 Lidar 살리기' 카테고리의 다른 글

ESP32로 곧바로 라이다에 연결하기.  (0) 2022.02.24

+ Recent posts