본문 바로가기
기계공학부 시절의 기록/ROS일기

open_manipulator_teleop.cpp 코드수정을 위한 코드공부(ros::spin, 클래스 접근지정, vector, 포인터)

by juhyeonglee 2021. 10. 27.
728x90
반응형

어제 myo센서에서 생성되는 토픽을 오픈매니퓰레이터의 teleop노드에서 subscribe하도록 코드를 만들었다. teleop노드가 헤더파일과 cpp파일로 나뉘어있고 나는 c++언어를 잘 모르기에 어려움이 있었다. 다하고보니 별거 없었다.

myo데이터 수신하는 subscriber open_manipulator_teleop.cpp에 만들기

https://needs-searcher.tistory.com/192?category=885778 

 

myo로 publish, teleop로 subscribe 확인

도움이 된 글 https://cafe.naver.com/openrt/18408 ros에서 pub되는 msg가 배열인데 이거 통째로 어떻게 sub받나요??? 질문양식[개발환경] (옵션)1) 운영체제 :우분투 16, 로스 키네틱2) 보드이름 : 3) 컴파일러..

needs-searcher.tistory.com

 


open_manipulator_teleop.cpp 코드수정을 위한 코드공부

(ros::spin, 클래스 접근지정, vector, 포인터)

 

어제는 teleop노드에서 subscriber만 만들어 연결시킨 것이었고 이제는 myo에서 생성되는 orientation 데이터를 받아와 변화각을 계산하여 이를 통해 모터각을 움직이도록 코드를 만들어야 한다.

Callback function과 다른 필요한 함수들을 만들어야 한다. 이를 수행하며 필요했던 공부들을 적어보았다.

 

1. ros::spinOnce()의 역할

먼저, teleop cpp코드의 main함수안에서 ros::spinOnce()가 있는데 이 것이 무엇인지부터 알아보았다. 만들어진 subscriber로 받아온 데이터를 callback function에 넘겨주는 역할을 한다고 이해하였다. subscriber뿐만 아니라 ROS통신의 모든 callback function에 해당되는 이야기인 것 같다.

Significance of ros::spinOnce() : https://answers.ros.org/question/11887/significance-of-rosspinonce/

 

2. 멤버변수는 main함수에서 메소드에 의해 값이 변경되면 이 후 다시 호출했을 때 변경된 값을 주는가?

myo센서로부터 받아온 데이터를 여러 변수들에 담아 저장하고 다뤄야 했다. 간단한 코드와 달리 본 코드는 main안에서  Class로 메소드, 멤버변수들을 다루다보니 변수관리에서도 어려움이 있었다. 함수안에서 선언된 변수는 함수바깥에서 소멸되는데 이와 클래스의 멤버변수가 헷갈렸다. 클래스의 private변수는 멤버함수에서 불러 값을 변경하면 이 값이 유지되는지 확인해보았다. 그 결과 유지됨을 확인하였다. 마치 함수바깥 전역변수와 같는 느낌이 들었다. 조금 더 생각해보면 객체를 선언하고 그 안에 멤버변수가 메모리에 저장되므로 메소드로 그 멤버변수를 수정하면 당연히 수정된 대로 유지되는 것이 당연하다.

 

또, 새롭게 필요한 멤버변수와 메소드들을 먼저 헤더파일에서 선언해주어야 했다.

그리고 책에서 객체는 마치 캡슐과 같아서 멤버변수들은 클래스 안에서만 접근가능하도록 하여 클래스에서만 다루고 그 결과를 캡슐바깥으로 전달할 방법으로 public을 활용하라고 하였다. 코드를 작성하며 어떤 느낌인지 알 수 있었다.

아래의 코드에서 int a가 바로 캡슐안에서만 다뤄지는 멤버변수이고 이는 메소드들에 의해서만 접근이 가능하다. 이 a값을 바깥으로 전달하기 위해서 public안의 print, change 메소드를 활용하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# include <iostream>
 
class Opt
{
public:
    void print();
    int change(int num);
private:
    int a = 0;
    
};
 
void Opt::print()
{
    std::cout << a << std::endl;
}
 
 
int Opt::change(int num)
{
    a = num;
    return a; 
}
 
int main() 
{
    Opt ka;
    ka.print(); // 0
    ka.change(10); 
    ka.print(); // 10
 
    return 0;
// private에는 멤버함수에서만 사용가능한 변수를 두고
// main에서 사용할 함수는 public에서 만든다. 
// 즉, 멤버변수를 클래스 함수에서만 처리하고 외부에서 접근 가능한 리턴함수를 만들어두고 main에서 접근한다.
cs
 

3. 크기지정이 필요없는 배열 : vector

# include <vector>를 선언한 후

std::vector<double> v1; // double type의 vector선언

v1.push_back(1); // 끝부분에 1 추가

 

센서에서 값을 받아오고 시간 순으로 이를 배열에 저장해야하는데 기존의 배열은 선언과 동시에 크기를 선언해야 했는데 vector를 사용하면 받아오는 데이터를 계속해서 배열에 추가시킬 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# include <iostream>
# include <vector>
 
int main()
{
    std::vector<int> v1(5,0);
 
 
    for (int i = 0; i < 1000++i)
    {
        v1.push_back(i);
        std::cout << v1[i] << std::endl;
    }
    return 0;
cs

 

4. 절댓값 in cpp

1
2
3
4
5
6
7
8
9
# include <iostream>
#include <cmath>
 
void main()
{
    double a = 1.05;
    std::cout << a / abs(a) << std::endl;
 
}
cs

 

 

5. 포인터 이해

class 안의 멤버에 접근할 때, 두가지 방법이 있다. 점연산자(.)와 포인터(->)이다.

Circle이라는 class에 getArea()멤버가 있다고 할 때,

 

1) 점연산자

Circle donut;

d = donut.getArea();

 

2) 포인터

Circle donut;

Circle *p; //포인터 선언

p = &donut;

d = p->getArea();

 

다음 글에서 이를 바탕으로 수정한 코드들을 포스팅하고 실행해볼 것이다.

728x90
반응형

댓글