# ROS-STM32 communication
[TOC]
## USB轉串口模塊
常見的有:CH340,CP2102
we use PL2303 USB to TTL(手邊剛好有)

linux:
一般情況不須另外安裝驅動程式,若需要請查看下面文章:
https://www.796t.com/content/1541534290.html
1. 利用下面指令確認是否已有驅動程式支援:
```
$ lsmod |grep pl2303
```

若有驅動程式,會得到類似的資訊。
2. 檢視系統資訊:
```
$ dmesg | tail -f
```

由上面結果可以看到裝置為ttyUSB0
3. 尋找serial port的資訊
```
udevadm info -a -n /dev/ttyUSB0
udevadm info -a -n /dev/ttyUSB1
udevadm info -a -n /dev/ttyUSB2
```


4. 利用上述資訊創建自定義的rules
rules名字自己取
```
$ sudo vim /etc/udev/rules.d/rplidar_imu_stm32_port.rules
```
In the file:
```
KERNEL=="ttyUSB*", ATTRS{devpath}=="3.3", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0777", SYMLINK+="front_left_laser"
KERNEL=="ttyUSB*", ATTRS{devpath}=="3.2", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0777", SYMLINK+="back_right_laser"
KERNEL=="ttyUSB*", ATTRS{devpath}=="3.1", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60",, MODE:="0777", SYMLINK+="imu"
~
~
```
# KERNEL=="ttyUSB*": 把所有的ttyUSB都叫出來修改,並符合後面條件的都叫出來修改。
# MODE:="0777": MODE代表賦予串口端口的權限,"0777"是具體的權限
# ATTRS{devpath}:用來使用在當廠商代碼跟商品代碼都一樣時,這個通常是電腦本身的port口的號碼,除此之外,如果像我們有另外接usb集線器就有可能會有"."。
# ATTRS{idVendor}:廠商代碼,有可能rpli imu這類的都會有一樣的名字。
# ATTRS{idProduct}: 商品代碼,有可能rpli imu這類的都會有一樣的名字,因為通訊的東西都一樣。
# SYMLINK+="stm32_port": 別名,"stm32_port" 是自己取的別名
:warning: 通常devpath都是選第一次出現的devpath因為在那裡才有標明確切在集線器的位置。
4. 重新加載udev規則
```
$ service udev reload
$ service udev restart
```
5. 拔插USB之後,查詢更改結果
```
ls -l /dev/ | grep ttyUSB
```

結果類似截圖,則表示更改完成!
https://leidawt.github.io/post/%E5%9C%A8stm32%E4%B8%8A%E8%BF%90%E8%A1%8Cros%E8%8A%82%E7%82%B9-rosserial-stm32%E5%BC%80%E5%8F%91%E5%8F%8A%E8%B0%83%E8%AF%95%E6%96%B9%E6%B3%95/
## rosserial (failed)
主要按照第二個連結影片步驟:
https://blog.csdn.net/leida_wt/article/details/109690562
https://www.bilibili.com/s/video/BV19B4y1M7f3
安裝rosserial_stm, 修改stm32cubeIDE程式碼, 執行
但最後rosrun時, reqiring topic失敗

## 07/28 問學長方法
1. 利用screen /dev/ttyUSB0 115200 (在terminal),先確認STM32是否有正確傳送訊息
2. 之後在ros寫node:建議用pyserial
https://pyserial.readthedocs.io/en/latest/shortintro.html
:::info
$ screen /dev/ttyUSB0 9600 (usb port and baud)
* Close screen:
ctrl+a -> K -> y
:::
目前問題:
* linux terminal screen ttyUSB0 沒有訊息
* 改成 screen ttyACM0 才出現訊息
* STM32 Debug Console 新增ttyACM0也可以查看
* ttyACM0 是 STM32 micro usb 傳輸線
* ttyUSB0 是 uart 傳輸線訊息
解決:
* 把 uart2 換成 uart3 pin 則可以成功傳送
## Linux terminal command <-> STM32
### STM32 Send Message
In STM32CubeIDE:
1. Connectivity: USART3
2. Mode: Asynchronous
3. Baud rate: 115200
4. Code in while loop:
```
HAL_UART_Transmit(&huart3, (uint8_t*)"Hello World!\n\r", sizeof("Hello World!\n\r")-1, 1000);
HAL_Delay(200);
```
5. Run
In Linux terminal:
1. find Uart port
```
$ ls -l /dev/ttyUSB*
```
2. screen the message STM32 sending
```
$ screen /dev/ttyUSB4 115200
```

3. close screen
ctrl+a -> K -> y
### STM32 Receive message
In STM32CubeIDE:
1. Connectivity: USART3
2. Mode: Asynchronous
3. Baud rate: 115200
4. Code in Private user code:
```
uint8_t Rx_data[10];
```
6. Code in while loop:
```
HAL_UART_Receive(&huart3, Rx_data, 10, 100);
```
5. Debug
6. Llive Expression
7. Add New Expression: Rx_data
8. Resume
In Linux terminal:
1. Set baud rate
```
$ stty -F /dev/ttyUSB0 115200
```
2. Write message to the uart
```
$ echo "Helloworld" > /dev/ttyUSB0
```

## Pyserial
### install
```
$ sudo apt-get install python3
$ sudo apt install python3-pip
$ sudo pip3 install pyserial
$ python3 -m pip show pyserial
```

```
$ mkdir pyserial_ws
$ cd pyserial_ws
$ touch receive.py
$ vim receive.py
```
In the file:
```
import serial
ser = serial.Serial()
ser.port = '/dev/ttyUSB0'
ser.baudrate = 115200
ser.open()
while(True):
line = ser.readline()
print(line)
```
```
$ python receive.py
```

## keyboard control stm32 motors
### Method 1:
teleop_twist_keyboard + base_controller
teleop_twist_keyboard:
https://github.com/ros-teleop/teleop_twist_keyboard
base_controller:
subscribe data type: geometry_msgs.msg / Twist

### Method 2: (目前執行方案)
import keyboard + keyboard_control
keyboard_control:
subscribe data type: std_msgs.msg / String

**Github file:**
Ros: https://github.com/PeiChi-Hu/unmanned_car_KeyboardUartToSTM32
keyboard_control pkg & base_controller pkg
STM32: https://github.com/PeiChi-Hu/unmanned_car_stm/tree/main/keyboard0805
terminal 1:
```
$ roscore
```
terminal 2:
```
$ source /opt/ros/noetic/setup.bash
$ source ~/stm32_ws/devel/setup.bash
$ rosrun base_controller keyboard_control.py
```
terminal 3:
```
$ sudo su (enter root)
$ source devel/setup.bash (in workspace directory)
$ rosrun keyboard_control keyboard_control.py
$ exit // exit root
```
Use command sudo su to enter root, because python keyboard import function requires root.
:small_red_triangle:try to find some other ways to avoid root reqiurement.
### Method 3:
import getkey + keyboard_control
getkey function:
:small_red_triangle: Issue: getkey(blocking=False) results in missed keyboard inputs
https://github.com/kcsaff/getkey/issues/17
getkey(blocking=True):
The keyboard status will remain until the next input.
-> need to modify the STM32 code.
:small_red_triangle:STM32 code: in the dc motor function, we put stop function at the end. However, the car didn't move.
### Method 4:
import pynput + keyboard_control
:small_red_triangle:Problem: pynput do not detect the keyboard inputs
### Method 5:
import tkinker + keyboard_control
tkinker: GUI module in python