# 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 ---