2021년 월초에 했었던 프로젝트를 정리하면서, 과정들을 다시 업로드 시작.
2차원 360도의 거리정보를 측정하는 센서
Uart통신을 사용해서 MCU와 동작함
연결 후, 자동으로 데이터를 보내주지 않기 때문에 통신을 해야함.
요청 / 응답 모드
스캔을 시작하기 전 or Lidar가 스캔 중 다른 일을 하고 있을 때
요청 / 다수 응답 모드
스캔을 시작하고, 데이터를 받을 때
요청 / 응답 없음 모드
Stop or Reset을 할 때
Star Flag는 0xA5로 고정. Command로만 scan, stop, reset 결정.
System Power Up : 전원이 들어온 후, Idle(대기 상태)
Request Processing : 데이터 요청 패킷을 받은 후, 처리하는 과정. 이 과정동안 스캔 작업, 데이터 송신을 하지않음.
Scannig : 측정 시작. 거리를 측정하고, 결과값을 계속해서 전송. 모터의 회전 속도가 안정할 때에만 거리를 측정함.
STOP
측정 시스템을 종료하고, Idle 상태로 들어감. 다른 요청을 위해서는 최소 1ms 대기.
Reset
Lidar 전원을 리셋. 다른 요청을 위해서는 최소 2ms 대기.
Scan
전송되는 데이터 패킷.
(패킷이 의미하는 값)
위의 설명을 토대로 XMC4500환경에서 펌웨어 개발.
: 스케쥴러 함수에서 1ms마다 동작 시켰음.
(센서는 0.5ms마다 측정가능하지만, 스케쥴러의 타이머가 1ms마다 동작하게 했기 때문에)
void TaskIdle(){
switch(test_cmd)
{
case 1:
RPLidar_Scan();
test_cmd = 0;
break;
case 2:
RPLidar_Stop();
test_cmd = 0;
break;
case 3:
RPLidar_Reset();
test_cmd = 0;
break;
default:
break;
}
RPLidar_Process();
}
Scan에서 송신하는 Tx_Data의 바이트들은 0xA5, 0x20이다.
void RPLidar_Scan()
{
while(UART_IsTxBusy(RPLidar.handle) == true) {};
uint8_t _Tx_Data[] = {RPLIDAR_CMD_SYNC_BYTE, RPLIDAR_CMD_SCAN};
UART_Transmit(RPLidar.handle, _Tx_Data, 2);
RPLidar.Rx_Size = 5;
RPLidar.Mode = scan;
}
void RPLidar_Stop()
{
while(UART_IsTxBusy(RPLidar.handle) == true) {};
uint8_t _Tx_Data[] = {RPLIDAR_CMD_SYNC_BYTE, RPLIDAR_CMD_STOP};
UART_Transmit(RPLidar.handle, _Tx_Data, 2);
RPLidar.Mode = stop;
}
void RPLidar_Reset()
{
while(UART_IsTxBusy(RPLidar.handle) == true) {};
UART_ClearRXFIFOStatus(RPLidar.handle, XMC_USIC_CH_RXFIFO_EVENT_STANDARD);
uint8_t _Tx_Data[] = {RPLIDAR_CMD_SYNC_BYTE, RPLIDAR_CMD_RESET};
UART_Transmit(RPLidar.handle, _Tx_Data, 2);
RPLidar.Mode = reset;
}
void RPLidar_Process()
{
if(RPLidar.Mode != scan){
test_cmd = 1;
}
if(RPLidar.Trans_hex2dec_flag)
{
uint16_t temp_angle = (((uint16_t)Rx_data[2]<<7)|((Rx_data[1]>>1)&0x7F));
temp_angle = (float)temp_angle/64.0;
if(temp_angle < 360) // 360' 이상의 각도는 에러라고 판단
{
RPLidar.angle = temp_angle;
}
float temp_distance = ((uint16_t)Rx_data[4]<<8|Rx_data[3]);
temp_distance = temp_distance/4/10; // 단위 : cm
if((temp_distance < MAX_DISTANCE) && (temp_distance > MIN_DISTANCE))
{
RPLidar.distance[RPLidar.angle] = temp_distance;
}
else
{
RPLidar.distance[RPLidar.angle] = MAX_DISTANCE;
}
RPLidar.Trans_hex2dec_flag = false;
}
}
void CB_Transmit_End()
{
if(RPLidar.Mode == scan)
{
UART_Receive(RPLidar.handle, Rx_response_descript, 7);
}
}
데이터를 송신한 후, 응답 패킷을 받아야 함.
응답 패킷을 받은 이후, 데이터 패킷을 받음.
(스캔모드에서만 하는 이유는, 다른모드에서는 응답 패킷을 송신하지 않기 때문에)
void CB_Receive_End()
{
switch(RPLidar.Mode)
{
case scan:
RPLidar.Trans_hex2dec_flag = true;
UART_Receive(RPLidar.handle, Rx_data, RPLidar.Rx_Size);
break;
case stop:
Set_UART_RXFIFOEmpty();
RPLidar.Mode = idle;
break;
case reset:
Set_UART_RXFIFOEmpty();
RPLidar.Mode = idle;
break;
default:
break;
}
}
(포스트의 사진은 RP Lidar A1의 Protocol Datasheet에서 캡쳐함)