2017年11月12日日曜日

ROSとPSoC5LPでUSBUART通信(ROS編)

今回はROS編です。はい。
とりあえず、環境のほうをざっくり書いときます。
環境
MacBook Air (11-inch, Mid 2011)
・プロセッサ  1.6 GHz Intel Core i5(多分3世代?)
・メモリ    4 GB 1333 MHz DDR3
・グラフィック Intel HD Graphics 3000 384 MB
・シリアル番号…っと危ない危ない(;´∀`)

macos Sierra 10.12.5(16F73)とUbuntu 16.04.2を
デュアルブートさせてます。

Ubuntu 16.04ということでROS界でのLTS版とされる
Kinetic KAMEを使用しています。

まずディレクトリ構造から
※いじる必要のないフォルダ、ファイルは非表示にしています。

├── catkin-ws
│   ├── build
│   ├── devel  
│   └── src
│       ├── CMakeLists.txt
│       ├── USBUART_comm
│       │   ├── CMakeLists.txt
│       │   ├── include
│       │   │   └── USBUART_comm
│       │   ├── package.xml
│       │   └── src
│       │       └── USBUART_comm.cpp
│       └── 
└──       

下はUSBUART_comm.cppのソースです。

#include <ros/ros.h>
#include <string>

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

int str_counter (char *str){
  int counter = 0;
  while(*str++){
    counter++;
  }

  return counter;
}

int main(int argc, char **argv){
  std::string dev = "/dev/ttyACM0",str_str;
  int baudrate = B9600;

  char str[64] = "Hello ROS & PSoC";

  ros::init(argc, argv, "UART_comm");

  ros::NodeHandle arg_nh("~");
  ros::NodeHandle nh;

  arg_nh.getParam("device", dev);
  arg_nh.getParam("baudrate", baudrate);
  arg_nh.getParam("message",str_str);

  strcpy(str,str_str.c_str());

//-------シリアルポート設定-------------------------
      int fd;                           /* ファイルディスクリプタ */
      struct termios oldtio, newtio;    /* シリアル通信設定 */
      int baudRate = B57600;
      fd = open(dev.c_str(), O_RDWR);   /* デバイスをオープンする */

      ioctl(fd, TCGETS, &oldtio);       /* 現在のシリアルポートの設定を待避させる */
      newtio = oldtio;                  /* ポートの設定をコピー */
      newtio.c_cflag = baudRate | CS8 | CREAD;
  	  newtio.c_iflag = IGNPAR | ICRNL;
  	  newtio.c_oflag = 0;
  	  newtio.c_lflag = 0;          /* ポートの設定をおこなう 詳細はtermios参照 */
      ioctl(fd, TCSETS, &newtio);       /* ポートの設定を有効にする */
//--------------------------------------------------------

  while(ros::ok()){

    printf("%s\n%d\n",str, str_counter(str));

    if(str_counter(str)>64){
      ROS_INFO("Warning!! \nThe amount of data that PSoC5 can receive is up to 64bytes.");
      //PSoC5のUSBUARTは一度に最大64バイトまでしか受け付けない。
    }

    if(fd<0){
      ROS_INFO("Error ! serialport open error!");
      return -1;
    }



    write(fd,str,sizeof(str)); //送信

    ros::spinOnce();

  }
  ioctl(fd, TCSETS, &oldtio);       /* ポートの設定を元に戻す */
  close(fd);                        /* デバイスのクローズ */

  return 0;
}
下はUSBUART_commフォルダー内のCMakeLists.txtです。
cmake_minimum_required(VERSION 2.8.3)
project(USBUART_comm)

add_compile_options(-std=c++11)


find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
)


catkin_package(
 INCLUDE_DIRS include
 LIBRARIES USBUART_comm
 CATKIN_DEPENDS roscpp std_msgs
 DEPENDS system_lib
)


include_directories(
include
  ${catkin_INCLUDE_DIRS}
)


add_executable(${PROJECT_NAME}_node src/USBUART_comm.cpp)


add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})


target_link_libraries(${PROJECT_NAME}_node
  ${catkin_LIBRARIES}
)
あとは記述する必要はなさそうですが、 一応USBUART_commフォルダー内のpackage.xmlも晒しときます。
<?xml version="1.0"?>
<package>
  <name>USBUART_comm</name>
  <version>0.0.0</version>
  <description>The USBUART_comm package</description>

  <maintainer email="yukimakura@todo.todo">yukimakura</maintainer>


  <license>TODO</license>


  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>std_msgs</build_depend>
  <run_depend>roscpp</run_depend>
  <run_depend>std_msgs</run_depend>


  <export>


  </export>
</package>

ソースコードを見たら一目瞭然ですが、 ROSのソースにそのままlinuxのシリアル通信のソース乗っけただけという簡単なものです。 ですが、応用すれば別ノードやサービスから購読したデータをPSoCや別のシリアル通信できる マイコンと通信することができます...
えぇ、そうですとも。



絶対同等以上のことできるパッケージってもう存在してますよね!?

というわけでもし誰かご存知でしたら
教えてくださるとすごくありがたいです...m(_ _)m
あと素人ながら書かせて頂いたのでぜひご指摘等ございましたらビシバシ叩いていただくと光栄です。
参考にさせていただいたサイト様
FAQ : シリアル通信をおこなうプログラムを作成するには?
https://armadillo.atmark-techno.com/faq/serial-programming


4 件のコメント:

  1. do you have de code for psoc? i need comunication ros and psoc for drive a stepper motor

    返信削除
    返信
    1. Thank you for your comment!!

      https://yukihurumakura.blogspot.com/2017/11/rospsoc5lpusbuartpsoc.html
      ↑This article is about PSoC.
      However, it is not recommended for reference.
      Because it ’s not very robust.

      translated by google translate

      削除
  2. 質問です。このnodeを実行すると0がずっと表示されるのですが、どのような挙動を見せれば正しく通信できているのでしょうか?
    環境としてはUbuntu18.04,ros melodicです。
    GR-PEACHとUSBUART通信をさせようとしています。

    /catkin_ws/src/hellow/src/hellow.cpp

    #include
    #include

    #include
    #include
    #include
    #include
    #include
    #include
    #include

    #define SERIAL_PORT "/dve/ttyACM0"

    int str_counter (char *str){
    int counter = 0;
    while(*str++){
    counter++;
    }
    return counter;
    }

    int main(int argc, char **argv){
    std::string dev = "/dev/ttyACM0",str_str;
    int baudrate = B9600;

    char str[64] = "Hello world";

    ros::init(argc,argv,"hellow");

    ros::NodeHandle arg_nh("~");
    ros::NodeHandle nh;

    arg_nh.getParam("device",dev);
    arg_nh.getParam("baudrate",baudrate);
    arg_nh.getParam("message",str_str);

    strcpy(str,str_str.c_str());

    //-------シリアルポート設定-------------------------
    char buf[255];
    int fd; /* ファイルディスクリプタ */
    struct termios oldtio, newtio; /* シリアル通信設定 */
    int baudRate = B57600;
    fd = open(dev.c_str(), O_RDWR); /* デバイスをオープンする */

    ioctl(fd, TCGETS, &oldtio); /* 現在のシリアルポートの設定を待避させる */
    newtio = oldtio; /* ポートの設定をコピー */
    newtio.c_cflag = baudRate | CS8 | CREAD;
    newtio.c_iflag = IGNPAR | ICRNL;
    newtio.c_oflag = 0;
    newtio.c_lflag = 0; /* ポートの設定をおこなう 詳細はtermios参照 */
    ioctl(fd, TCSETS, &newtio); /* ポートの設定を有効にする */
    //--------------------------------------------------------

    //ros::Rate rate(1);

    while(ros::ok()){
    printf("%c %d\n",str, str_counter(str));
    //SERIAL_PORT.printf("%s\n%d\n",str, str_counter(str));
    write(fd,buf,sizeof(buf));
    if(str_counter(str)>64){
    ROS_INFO("Warning!! \nThe amount of data that PSoC5 can receive is up to 64bytes.");
    //PSoC5のUSBUARTは一度に最大64バイトまでしか受け付けない。
    }

    if(fd<0){
    ROS_INFO("Error ! serialport open error!");
    return -1;
    }



    write(fd,str,sizeof(str)); //送信

    ros::spinOnce();
    }
    ioctl(fd, TCSETS, &oldtio); /* ポートの設定を元に戻す */
    close(fd); /* デバイスのクローズ */

    return 0;
    }

    GR-PEACH側にHello worldという文字列を送りたいです。

    返信削除
    返信
    1. お返事遅れてごめんなさいm(_ _)m
      (まじでブログの管理が雑)

      結論から申し上げますと、このコードはあまりおすすめしません。
      今の私ならBoostというC++ライブラリのASIO経由でシリアル通信とか、TCPIP通信をするでしょう。


      こちらのサイトをご参考ください。
      https://blog.myon.info/entry/2015/04/19/boost-asio-serial/

      削除