---
# System prepended metadata

title: Rpi與Arduino溝通(with ROS)
tags: [2023 軟體培訓]

---

# Rpi(或電腦)與Arduino溝通(with ROS)

## 1. Arduino ros的設置
首先，安裝Arduino IDE(https://www.arduino.cc/en/software)，作為燒入程式碼的工具。

接著，手動安裝函式庫(**Rosserial_Arduino_Library**):


###  Example arduino code:
```=arduino
#include <ros.h>
#include <std_msgs/Int64.h>
#include <Servo.h>
Servo servo;
ros::NodeHandle  nh;
void messageCb( const std_msgs::Int64& msg){
  servo.write(msg.data);//write the angle
}
ros::Subscriber<std_msgs::Int64> sub("Servo_topic", &messageCb );
void setup()
{ 
  Serial.begin(9600);
  pinMode(9, OUTPUT);
  servo.attach(9);
  servo.write(1);

  nh.initNode();
  nh.subscribe(sub);
  
  
}
void loop()
{  
  nh.spinOnce();
  delay(1);
}

```


## 2. Docker與ros設置


### (1) Wsl 連線 USB 裝置

首先，讓windows上的裝置(device)能分享到wsl上: 

```
# windows下 
$ winget install --interactive --exact dorssel.usbipd-win

# wsl linux下
#如果出現" WSL 'usbip' client not correctly installed. "，就再重裝一次
$ sudo hwclock --hctosys
$ sudo apt-get -o Acquire::Check-Valid-Until=false -o Acquire::Check-Date=false update
$ sudo apt install linux-tools-virtual hwdata
$ sudo update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20
```

記得重新開機!!

使用指令參考:

```
#檢查各個設備的使用狀態
$ usbipd wsl list

#分享ID為"1-3"的設備
$ usbipd wsl attach --busid 1-3

#停止分享ID為"1-3"的設備
$ usbipd wsl detach --busid 1-3
```

範例圖: 
![image](https://hackmd.io/_uploads/HkdhL2sVp.png)
如此可在wsl或ubuntu中使用(下圖為ubuntu環境下的示意):
![image](https://hackmd.io/_uploads/BJlSP3oNT.png)

---

### (2) 引入docker image(映像檔)、宣告container
[Docker] 建立群組
https://quietbo.com/2022/06/06/docker-建立群組-got-permission-denied-while-trying-to-connect-to-the-docker-daemon-socket-at-unix解決/

 
```=linux
# 列出images
$ docker images -a

# pull引入image
# docker pull {Docker hub user}/{image_name}:{tag}
$ docker pull dongdonghsu065/ros_test:latest
$ docker images -a

# 以此image來宣告container
$ docker run -itd --name {container name} --hostname {host name} --device=/dev/ttyACM0:/dev/ttyACM0 {image_name}:{tag}

# 列出containers
$ docker ps -a

#進入container 
$ docker exec -it {container_name} bash
```

Example talker code:
```=C++
#include "ros/ros.h"
#include "std_msgs/Int64.h"
#include <sstream>
/**
* This tutorial demonstrates simple sending of messages over the ROS system.
*/
int main(int argc, char **argv)
{
/**
* The ros::init() function needs to see argc and argv so that it can perform
* any ROS arguments and name remapping that were provided at the command line.
* For programmatic remappings you can use a different version of init() which takes
* remappings directly, but for most command-line programs, passing argc and argv is
* the easiest way to do it.  The third argument to init() is the name of the node.
*
* You must call one of the versions of ros::init() before using any other
* part of the ROS system.
*/
        ros::init(argc, argv, "talker");
/**
* NodeHandle is the main access point to communications with the ROS system.
* The first NodeHandle constructed will fully initialize this node, and the last
* NodeHandle destructed will close down the node.
*/
        ros::NodeHandle n;
/**
* The advertise() function is how you tell ROS that you want to
* publish on a given topic name. This invokes a call to the ROS
* master node, which keeps a registry of who is publishing and who
     * is subscribing. After this advertise() call is made, the master
     * node will notify anyone who is trying to subscribe to this topic name,
     * and they will in turn negotiate a peer-to-peer connection with this
     * node.  advertise() returns a Publisher object which allows you to
     * publish messages on that topic through a call to publish().  Once
     * all copies of the returned Publisher object are destroyed, the topic
     * will be automatically unadvertised.
     *
     * The second parameter to advertise() is the size of the message queue
     * used for publishing messages.  If messages are published more quickly
    * than we can send them, the number here specifies how many messages to
     * buffer up before throwing some away.
     */
        ros::Publisher chatter_pub = n.advertise<std_msgs::Int64>("Servo_topic", 1000);

    ros::Rate loop_rate(1); //1Hz

    /**
     * A count of how many messages we have sent. This is used to create
    * a unique string for each message.
     */
        int count = 1;
    while (ros::ok())
    {
      /**
       * This is a message object. You stuff it with data, and then publish it.
       */
                std_msgs::Int64 msg;
                msg.data = count;

                //ROS_INFO("%s", msg.data;

                /**
                * The publish() function is how you send messages. The parameter
                * is the message object. The type of this object must agree with the type
                * given as a template parameter to the advertise<>() call, as was done
                * in the constructor above.
                */
                chatter_pub.publish(msg);

                ros::spinOnce();
                loop_rate.sleep();

                if(count == 180)
                        count = 1;
                else if(count == 1){
                        count = 45;
                }
                else
                        count += 45;
        }


   return 0;
}
```

### (3) 完成arduino與電腦間的溝通(with ros)
首先，讓ros環境可以運行，使用指令(會用到三個視窗):
```
$ roscore
```

接著，開啟我們arduino裡的ros_node(這裡是subscriber): 
```
$ rosrun rosserial_python serial_node.py _port:=/dev/ttyACM0
```

最後，開啟我們電腦內的ros_node(這裡是publisher):
```
# 進入workspace、source資源
$ cd ~/catkin_ws 
$ source devel/setup.bash
# 編譯
$ catkin_make

#跑talker_node
$ rosrun servo_test talker

# 檢查topic是否存在 
$ rostopic list 
# 檢查特定topic的資料
$ rostopic echo {topic_name}
```
根據希望的角度變化，可以更改"~/catkin_ws/src/servo_test/src/servo_angle.cpp"的code。

---

教學錄影: https://www.youtube.com/watch?v=D6z961M7gVQ&ab_channel=DongdongHsu

其它參考網址:
1. 【WSL 2】配置连接 USB 设备并使用主机的 USB 摄像头
https://github.com/dorssel/usbipd-win/wiki/WSL-support
https://learn.microsoft.com/zh-tw/windows/wsl/connect-usb
2. 在樹梅派上跑ROS控制Arduino Servo
https://harry123180.medium.com/%E5%9C%A8%E6%A8%B9%E6%A2%85%E6%B4%BE%E4%B8%8A%E8%B7%91ros%E6%8E%A7%E5%88%B6arduino-servo-6823f69276f0
3. ROS Tutorials
http://wiki.ros.org/ROS/Tutorials?fbclid=IwAR0TnA-7-gvzoATBM8wF55PySEjDwu6ZqAzhgVC3bzbujXCY03VXN3ksRiE
4. 2022AUV軟體培訓-Servo馬達
https://hackmd.io/P950P583QpKtpE-pQGrSyg
5. 認識UART、I2C、SPI三介面特性
https://makerpro.cc/2016/07/learning-interfaces-about-uart-i2c-spi/
6. Docker Desktop Tutorial
https://hackmd.io/oeLOi6P-SjyV5HPMYqZdxw

---