코딩처음입니다만
군집 로봇, 모션 플래닝, 자율주행에 관심있는 SW 개발자입니다 !
코딩처음입니다만★ (34)
[C++] 각도 제한 [ -pi ~ pi ]
728x90
반응형

Robotics 분야에서 각도 표현은 굉장히 중요하다 !!
로봇의 heading angle이 200도라도 표현하기 보단 -160도라고 표현하는 것이 일반적이다.

즉, -180 ~ 180도 사이에서 모든 각도를 표현할 수 있어야 한다. 따라서 그 사이값으로 각도를 제한해보자.

1. pi_to_pi 코드

double pi_to_pi(double angle)
{
  while(angle >= M_PI)
  {
    angle -= 2.*M_PI;

    while(angle < -M_PI)
    angle += 2.*M_PI;

    return angle;
  }
}

이렇게 하면 -180도 ~ 180도 사이로 각도가 들어온다.

반응형
  Comments,     Trackbacks
[C++] Quaternion to Euler 상호 변환
728x90
반응형

Robotics 분야에서 각도 표현에 자주 사용되는 것이 1) Quaternion과 2) Euler이다.

일반적으로 roll, pitch, yaw로 표현되는 Euler 각도에 다들 익숙할 것인데, 짐벌락이라는 한계때문에 각도는 Quaternion으로 계산하곤 한다. 거두절미하고 바로 코드를 보자

 

1. Quaternion to Euler 코드

#include <tf/tf.h>

tf::Quaternion q(
        msg->pose.pose.orientation.x,
        msg->pose.pose.orientation.y,
        msg->pose.pose.orientation.z,
        msg->pose.pose.orientation.w);
tf::Matrix3x3 m(q);
double roll, pitch, yaw;
m.getRPY(roll, pitch, yaw);

반대도 알아야겠죠~~

 

2. Euler to Quaternion 코드

#include <tf2/LinearMath/Quaternion.h>

// input : 오일러 각(roll, pitch, yaw)
tf2::Quaternion quat;
quat.setRPY(roll, pitch, yaw);
quat.normalize();
반응형
  Comments,     Trackbacks
[C++] 알고리즘 수행 시간 측정
728x90
반응형

1. 개요

알고리즘을 개발하다 보면 수행 시간이 얼마나 걸리느냐가 굉장히 중요한 요소 중 하나이다. 그렇다면 코드 단위에서 실행 시간을 어떻게 측정할까?

2. 간단한 예시

아주 간단하게는 <ctime>clock()을 사용하는 방법이 있다.

#include <ctime>

clock_t start, end;

start = clock();
// 이 공간에 측정하고자 하는 알고리즘을 넣는다.
end = clock();

std::cout << "실행시간: " << end - start  << " ms" << std::endl;

하지만 다음 설명할 방법이 내가 제일 좋아하는 방법이며, 헤더 파일로 하나 만들어두면 어느 프로그램을 개발할 때나 사용할 수 있다 !

3. 정확한 예시

클래스를 이용하여 아래와 같이 미리 선언해둔다.

class TicToc
{
  public:
    TicToc()
    {
        tic();
    }

    void tic()
    {
        start = std::chrono::system_clock::now();
    }

    double toc()
    {
        end = std::chrono::system_clock::now();
        std::chrono::duration<double> elapsed_seconds = end - start;
        return elapsed_seconds.count() * 1000;
    }

  private:
    std::chrono::time_point<std::chrono::system_clock> start, end;
};

이후 사용하는 곳에서는 아래와 같이 사용하면 끝 !!

TicToc t_algorithm;
// 측정하고자 하는 알고리즘
std::cout << "실행시간: " << t_algorithm.toc() << std::endl;

단위는 [ms]이다.

반응형
  Comments,     Trackbacks
[C++] 코딩테스트 때 자주 사용하는 STL 및 알고리즘 정리
728x90
반응형

1. 개요

코딩테스트 문제를 풀다보면 STL을 많이 사용하게 된다. 내가 자주 사용하는 것들을 까먹지 않게 좀 정리해본다.

원래 SW를 개발할 때는 namespace를 붙이지 않고 개발하는 게 좋지만, 코딩테스트의 편의성을 위해서 아래와 같이 선언해준다.

using namespace std;

대부분의 자료 구조는 4가지의 기본 연산을 갖고 있다. 따라서 지금부터 나열할 STL은 아래의 기준으로 나열한다.

  1. 읽기 : Read
  2. 탐색 : Search
  3. 삽입 : Insert
  4. 삭제 : Delete

여기서 어느 정도 눈치챈 사람들이 있겠지만, 앞으로 나올 STL은 위의 4가지 연산마다 저마다의 장점을 갖고 있다.

 

2. Vector

배열 관련하여 사용할 때는 vector를 줄구장창 사용할 것이다. 아래와 같이 코드가 선언되어 있다고 가정하자.

#include <vector>

using namespace std;

int main()
{
  vector<int> v;

  return 0;
}

2-A. 읽기

읽기는 대괄호를 이용해서 해당 값을 읽으면 된다.

cout << v[0] << endl;

2-B. 탐색

탐색을 위해서는 std::find를 이용하여 2가지 방법이 있다.

// 1. 반복자(iterator) 찾기
auto iter = std::find(v.begin(), v.end(), 178);

// 2. 인덱스(index) 찾기
auto idx = std::find(v.begin(), v.end(), 178) - v.begin();

// 만약에 없으면?
if ( std::find(v.begin(), v.end, 178()) == v.end() );

std::find() 함수를 이용하며, 해당 요소가 vector에 존재하지 않으면 v.end()를 반환한다. 이 함수의 반환값은 반복자이며, 해당 반복자에 해당하는 인덱스를 얻고 싶다면 첫번째 반복자 v.begin()을 빼주면 된다.

Iterator를 이용하여 인덱스를 얻는 방법이 하나 더 있다. 바로 distance() 함수를 이용하여 아래와 같이 사용가능하다.

#include <algorithm>

auto index = std::distance(v.begin(), iter);

2-C. 삽입

삽입은 insert()를 이용하며 아래와 같이 사용한다.

v.insert( v.begin(), 100 ); // 100을 제일 처음에 추가
v.insert( v.begin()+5, 5 ); // 5를 (처음+5)에 추가
v.insert( v.end(), 9 ); // 9를 제일 마지막에 추가

2-D. 삭제

삭제는 erase()를 이용하며 아래와 같이 사용한다.

v.erase( v.begin() ); // 제일 첫 번째 원소 제거
v.erase( v.end()-1 ); // 마지막에서 한 칸 앞에 원소 제거

3. Map

<map> 정말 많이 사용한다. 전화번호부, 메뉴판과 같이 이름-전화번호 혹은 메뉴-가격 이렇게 key-value의 쌍으로 표현할 수 있을 때라던지, 투표소에서 누가 투표를 안 했는가?에 대한 문제도 손쉽게 해결 가능 하다. 기본 자료 구조는 해시 테이블(hash table) 또는 트리(tree)이다. 기본 선언은 아래와 같다.

#include <map>

// 또는

#include <unordered_map> // 필자는 이걸 더 선호한다.

/*
  사용하는 곳 안에서 (대게 main문)
  key-value의 쌍(pair)로 선언해야 하므로 2가지를 <> 안에 넣어줘야 한다.
*/
unordered_map<string, int> um;
um["bigbigpark"] = 1234;   // 문자열 bigbigpark이라는 key에 저장된 value는 정수형 1234이다.

3-A. 탐색

탐색은 find 메소드를 이용해준다. 위에 vectorstd::find를 이용해주었다. 차이점을 주의하자.

if ( um.find("bigbigpark") != um.end() ) // 찾지 못한다면 end()를 반환

// 만약 찾았으면?
/*
  앞서 말했다시피 map 자료구조는 key-value 두 가지로 구성되어 있다.
  따라서 찾았을 때 두 가지 모두 접근이 가능하다.
*/
auto iter = um.find("bigbigpark");

auto key   = iter->first;  // key에 접근한다. -> 문자열 bigbigpark 반환.
auto value = iter->second; // value에 접근한다. -> 정수형 1234 반환.

3-B. 삽입

여러 방법이 있지만 나는 아래와 같이 사용한다.

um["Eric"] = 9999;

3-C. 삭제

key를 기준으로 삭제한다.

um.erase["Amanda"]; // 없으면 um.end()를 반환한다.

3-D. 반복문 순회

// vector의 경우 아래와 같이 반복문을 순회하며 값에 접근이 가능하다.
vector<int> v = {1, 2, 3, 4, 5};
for(auto n: v)
{
  std::cout << n << std::endl;
}

// map의 경우 어떨까?
unordered_map<string, int> um;
um["A"] = 1111;
um["B"] = 2222;

for(auto it: um)
{
  // key-value의 특성에 따라 접근하면 된다.
  std::cout << "key  : " << it->first << std::endl; // 문자열 A, B 출력
  std::cout << "value: " << it->second << std::endl; // 정수형 1111, 2222 출력
}

4. 문자열(String)

애증의 녀석. C++ 코테에 문자열은 빠지면 정말 섭섭하다. 큰 수 입력받을 때 9999999999999999도 string으로 받으면 된다. 아래와 같이 선언한다.

#include <string>

string s = "bigbigpark";

4-A. 찾기

find() 메소드를 사용하긴 하지만, 찾지 못하였을 때 반환값이 다름에 주의하자.

if ( s.find("big") != std::string::npos )

find() 메소드에는 다음과 같은 특성들이 있다.

  1. 못 찾았을 시 반환값은 std::string::npos이다.
  2. 찾았을 때 반환값은 해당 인덱스이다.
  3. 중복되는 문자의 경우 제일 먼저 등장한 인덱스를 반환해준다.

4-B. 교체

replace() 메소드를 사용한다.

int pos = 3;
int length = 5;
string 문자열 = "name";

/*
  pos위치에서 length길이만큼 문자열로 채우게 된다.
  pos위치와 length와 문자열 길이의 차이로 인한 에러는.. 각자 센스로 해결하자.
*/
s.replace(pos, length, 문자열);

4-C. 삭제

// 1.
s.erase(pos, len); // pos위치에서 len길이만큼 삭제한다.

// 2.
s.erase(s.begin()+2); // 처음 위치+2 에 있는 녀석을 삭제한다.

// 3.
s.erase(s.begin()+1, s.end()-3) // 첫 번째 위치 ~ 두 번째 위치까지의 요소들을 삭제한다.

자 ! 여기서 특정 문자만 제거하기를 해보자

/*
  A는 문자열이 아닌 char 형으로 들어감에 주의하자.
  문자열 s에서 'A'가 들어간 부분을 모조리 지워준다.
*/
s.erase( std::remove(s.begin(), s.end(), 'A'), s.end() )

4-D. 문자열 부분 추출

삽입, 삭제 말고 이미 존재하는 문자열에서 조금만 떼올 순 없나?
있다.

// 1. 전체 가져오기
string new_string = s.substr();

// 2. 5번 인덱스부터 끝까지 가져오기
string new_string = s.substr(5);

// 3. 5번 인덱스부터 1길이만큼 가져오기
string new_string = s.substr(5, 1);

4-E. 문자열 형변환

정말정말 많이 나온다. 자주 사용하면 거의 외울 수 있을 듯 ?

// char -> string, 문자열 객체 선언후 그냥 더하기.
char ch = 'A';
string temp = "";
temp += ch;

// string -> char, 그냥 인덱싱 하자.
string str = "bigbigpark";
char c = str[0];

// int -> string
int num = 5;
string str = to_string(num);

// string -> int 또는 double
string n_str = "1122";
int n1 = stoi(n_str);
double n2 = stod(n_str);

// char -> int
// 자릿수 연산에 많이 등장한다.
char ch = '9';
int n = ch - '0'; // '0'를 빼게 되면 보이는 그대로 숫자가 저장되게 된다.

추가적으로 ASCII 숫자 맵핑 관계를 알아보자

  1. AZ: 6590
  2. az: 97122

4-F. 문자열 공백으로 분리

공백 말고 다른 구분자(delimeter)으로도 분리 가능!

#include <sstream>
#include <string>

// 공백이 포함된 문자열이 있다고 가정하자.
string str = "hello world this is park";
istringstream ss(str);

string word;

// getline() 3번째 인자에 구분자를 설정해주자. 아래 예시는 공백.
while ( getline(ss, word, ' ') )
{
  std::cout << word << std::endl;
}

여기까지 내가 코테를 봐 오면서 시험 쳐온 현황이다. 다음은 함수를 몇 가지 알아보자.

5. 정렬

숫자를 오름차순/내림차순으로 정렬해보자.

#include <algorithm>
#include <vector>

using namespace std;

vector<int> v = {4, 2, 3, 5, 1};

// 오름차순
sort( v.begin(), v.end() );

// 내림차순
sort( v.begin(), v.end(), greater<>() );

6. 합

vector 요소의 합을 구해보자. 물론 반복문 선언해서 하나하나 다 더해도 됨.

#include <numeric>

// 합
auto sum = accumulate( v.begin(), v.end(), 0);

// 평균
auto avg = sum / n.size();

7. 이진수 연산

이진수를 위한 라이브러리가 있는지 최근에 알았다. 정말 편리하구나 ㅜㅜ

7-A. 선언 및 사용

#include <bitset>
/*
  1) 이진수 형태의 문자열을 바로 사용 가능.
  2) 십진수를 이진수로 바로 사용 가능.

  이진수 형태의 덧셈 뺄셈 가능
*/
int n1 = 544132;
string n2 = "01110111011";

bitset<16> bit; // 모든 16자리 비트가 0으로 초기화됨.
bitset<16> bit (n1); // 정수형을 바로 비트연산 가능
bitset<16> bit (n2); // 문자열을 바로 비트연산 가능

7-B. 이진수를 다시 문자열/정수형으로 변환

auto i_num = bit.u_long();    // 이진수를 정수형으로 변환
auto s_num = bit.to_string(); // 이진수를 문자열로 변환

7-C. 메소드들

  1. flip(n) : n번째 비트 반전 시키기
  2. test(n) : n번째 비트가 1인지 검사 (맞으면 true, 다르면 false) 반환
반응형
  Comments,     Trackbacks
[Ubuntu/리눅스] 우분투에 팀뷰어 설치하기(Install teamviewer on Ubuntu 18.04)
728x90
반응형

Install teamviewer on Ubuntu 18.04[리눅스/우분투에서 팀뷰어 설치하기]

안녕하세요~ 오늘은 팀뷰어를 설치하는 방법에 대해서 알아보겠습니다!

코로나19로 인해서 재택근무가 많아지실 시기가 왔네요 ㅎㅎ

동시에 직장 혹은 학교 컴퓨터에 원격으로 접속해야할 일이 많을텐데요?

많이들 사용하시는 팀뷰어 설치 방법에 대해 알아보겠습니다!

 

팀뷰어 설치하기(리눅스)

1) 팀뷰어 홈페이지 접속

아래 URL을 클릭하시면 홈페이지로 이동합니다

https://www.teamviewer.com/ko/download/linux/

저는 데비안 형식으로 설치할 예정이라 *.deb 파일을 다운로드합니다[빨간색 동그라미]

본인 컴퓨터 비트 수에 맞게[64bit / 32bit]를 다운로드 할게요!

저는 x86_64bit를 받겠습니다

 

2) 설치하기(deb파일)

설치는 아래 명령어로 설치 가능합니다!

각자 다운로드한 경로에 가서 명령어를 입력해줍니다.

보통 파일을 다운로드하면 ~/Downloads 에 설치될 겁니다 ㅎㅎ

$ sudo dpkg -i {다운로드 한 팀뷰어 파일 이름}.deb

위의 명렁어는 dpkg(데비안 패키지라는 뜻)을 -i (install)하겠다는 의미입니다

 

다들 이렇게 뜨셨나요? 축하합니다 ㅎㅎ 이제 설치가 완료되었습니다!

 

3) 팀뷰어 실행하기

아무 경로에서 teamviewer라고 입력하시면 이제 실행이 될 겁니다

$ teamviewer

 

EULA와 DPA에 동의하라는 메세지가 나오는데, 체크하고 Continue를 눌러줍니다

 

자 이제 다들 익숙한 화면이시죠? ㅎㅎ

이제부터 원격으로 리눅스를 사용할 수 있습니다!

반응형
  Comments,     Trackbacks