---
# System prepended metadata

title: CV2X Lab 2
tags: [NYCU, CV2X]

---

# CV2X Lab 2
## C-V2X之MEC定位應用實作：利用軌跡進行室內定位（收集資料）
![系統架構](https://hackmd.io/_uploads/BJtkpd4Uxl.jpg)

## TurtleBot
### 介紹
https://emanual.robotis.com/docs/en/platform/turtlebot3/features/

## ESP32-S3
### 介紹
ESP32-S3 是樂鑫科技（Espressif Systems）推出的一款高性能、低功耗的 MCU（微控制器單晶片），專為 AIoT（人工智慧物聯網）應用設計。

**主要特點：**

- **強大的處理能力**：搭載 Xtensa® 32 位元 LX7 雙核心處理器，主頻高達 240 MHz，內建 512 KB SRAM（TCM）。

- **無線連接**：支援 2.4 GHz Wi-Fi（802.11 b/g/n）和 Bluetooth 5（LE），並支援 Bluetooth Mesh，可透過 Coded PHY 與廣播擴展實現遠距離通信。

- **AI 加速**：新增向量指令集，可加速神經網路計算和訊號處理，透過 ESP-DSP 和 ESP-NN 庫，實現高效能的圖像識別、語音喚醒和識別等應用。

- **豐富的外設接口**：提供 45 個可編程 GPIO，支援 SPI、I2S、I2C、PWM、UART、SD/MMC 主機控制器和 TWAI™ 控制器等常用外設接口。

- **安全機制**：支援基於 AES-XTS 演算法的 Flash 加密、基於 RSA 演算法的安全啟動、數位簽章和 HMAC，提供完善的安全保護措施。

**應用場景：**

憑藉強大的處理能力和豐富的外設接口，ESP32-S3 適用於多種 AIoT 應用場景，如：

- 智慧家居設備
- 可穿戴設備
- 工業自動化
- 健康監測
- 語音識別和圖像處理應用

開發者可以使用樂鑫提供的 ESP-IDF（Espressif IoT Development Framework）開發框架，快速上手 ESP32-S3 的開發。

### Implement Wi-Fi scan
1. Download Arduino IDE
https://www.arduino.cc/en/software
2. Download ESP32 library
- 舊版Arduino, 參考 https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html
- linux, 參考 https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html#linux
- **esp32** by Espressif Systems
![image](https://hackmd.io/_uploads/B1HM1-HRkx.png)
3. ESP32-S3 connect to PC
4. Board: choose "ESP32S3 Dev Module"
5. Port: choose "COM3" or depend on your system
![image](https://hackmd.io/_uploads/HJsqJWS01e.png)
6. Write the **Wi-Fi scan** code
```ino=
/*
    This sketch demonstrates how to scan WiFi networks in Async Mode.
    The API is based on the Arduino WiFi Shield library, but has significant changes as newer WiFi functions are supported.
    E.g. the return value of `encryptionType()` different because more modern encryption is supported.
*/
#include "WiFi.h"

void startWiFiScan() {
  Serial.println("Scan start");
  // WiFi.scanNetworks will return immediately in Async Mode.
  WiFi.scanNetworks(true);  // 'true' turns Async Mode ON
}

void printScannedNetworks(uint16_t networksFound) {
  if (networksFound == 0) {
    Serial.println("no networks found");
  } else {
    Serial.println("\nScan done");
    Serial.print(networksFound);
    Serial.println(" networks found");
    Serial.println("Nr | SSID                             | RSSI | CH | Encryption | BSSID");
    for (int i = 0; i < networksFound; ++i) {
      Serial.printf("%2d", i + 1);
      Serial.print(" | ");
      Serial.printf("%-32.32s", WiFi.SSID(i).c_str());
      Serial.print(" | ");
      Serial.printf("%4ld", WiFi.RSSI(i));
      Serial.print(" | ");
      Serial.printf("%2ld", WiFi.channel(i));
      Serial.print(" | ");
      switch (WiFi.encryptionType(i)) {
        case WIFI_AUTH_OPEN:            Serial.print("open"); break;
        case WIFI_AUTH_WEP:             Serial.print("WEP"); break;
        case WIFI_AUTH_WPA_PSK:         Serial.print("WPA"); break;
        case WIFI_AUTH_WPA2_PSK:        Serial.print("WPA2"); break;
        case WIFI_AUTH_WPA_WPA2_PSK:    Serial.print("WPA+WPA2"); break;
        case WIFI_AUTH_WPA2_ENTERPRISE: Serial.print("WPA2-EAP"); break;
        case WIFI_AUTH_WPA3_PSK:        Serial.print("WPA3"); break;
        case WIFI_AUTH_WPA2_WPA3_PSK:   Serial.print("WPA2+WPA3"); break;
        case WIFI_AUTH_WAPI_PSK:        Serial.print("WAPI"); break;
        default:                        Serial.print("unknown");
      }
      Serial.print(" | ");
      Serial.print(WiFi.BSSIDstr(i));  // 顯示 MAC address
      Serial.println();
      delay(10);
    }

    Serial.println("");
    // Delete the scan result to free memory for code below.
    WiFi.scanDelete();
  }
}

void setup() {
  Serial.begin(115200);

  // Set WiFi to station mode and disconnect from an AP if it was previously connected.
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);

  Serial.println("Setup done");
  startWiFiScan();
}

void loop() {
  // check WiFi Scan Async process
  int16_t WiFiScanStatus = WiFi.scanComplete();
  if (WiFiScanStatus < 0) {  // it is busy scanning or got an error
    if (WiFiScanStatus == WIFI_SCAN_FAILED) {
      Serial.println("WiFi Scan has failed. Starting again.");
      startWiFiScan();
    }
    // other option is status WIFI_SCAN_RUNNING - just wait.
  } else {  // Found Zero or more Wireless Networks
    printScannedNetworks(WiFiScanStatus);
    startWiFiScan();  // start over...
  }

  // Loop can do something else...
  delay(250);
  Serial.println("Loop running...");
}
```
7. Verify
8. Upload
9. Check on **Serial Monitor**
    - baud rate set to **115200**

#### Install raspberry pi on turtle bot
1. Raspi imager
    - https://www.raspberrypi.com/software/
2. Flash ubuntu to SD card
    - Raspberry Pi Device: **Raspberry Pi 4**
    - System: **Ubuntu Server 22.04.5 LTS (64-bit)**
    > Remember to set the WiFi (國碼: US)
3. Setup source
    - add the ROS 2 GPG key with apt.
    ```shell=
    $ sudo apt update && sudo apt install curl -y
    $ sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
    ```
    - Then add the repository to your sources list.
    ```shell=
    $ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
    ```

4. Install ros2 package
```shell=
$ sudo apt update
$ sudo apt upgrade
$ sudo apt install ros-humble-desktop
```

5. Check ros2 was installed (optional)
```shell=
# Terminal 1
$ source /opt/ros/humble/setup.bash
$ ros2 run demo_nodes_cpp talker
```
```shell=
# Terminal 2
$ source /opt/ros/humble/setup.bash
$ ros2 run demo_nodes_py listener
```

6. Install Turtlebot3 package
```shell=
$ sudo apt install python3-argcomplete python3-colcon-common-extensions libboost-system-dev build-essential
$ sudo apt install ros-humble-hls-lfcd-lds-driver
$ sudo apt install ros-humble-turtlebot3-msgs
$ sudo apt install ros-humble-dynamixel-sdk
$ sudo apt install libudev-dev
$ mkdir -p ~/turtlebot3_ws/src && cd ~/turtlebot3_ws/src
$ git clone -b humble https://github.com/ROBOTIS-GIT/turtlebot3.git
$ git clone -b humble https://github.com/ROBOTIS-GIT/ld08_driver.git
$ cd ~/turtlebot3_ws/src/turtlebot3
$ rm -r turtlebot3_cartographer turtlebot3_navigation2
$ cd ~/turtlebot3_ws/
$ echo 'source /opt/ros/humble/setup.bash' >> ~/.bashrc
$ source ~/.bashrc
$ colcon build --symlink-install --parallel-workers 1
$ echo 'source ~/turtlebot3_ws/install/setup.bash' >> ~/.bashrc
$ source ~/.bashrc
```

7. USB Port Settings for OpenCR
```shell=
$ sudo cp `ros2 pkg prefix turtlebot3_bringup`/share/turtlebot3_bringup/script/99-turtlebot3-cdc.rules /etc/udev/rules.d/
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger
```

8. Setting TurtleBot3 ID
```shell=
$ echo 'export ROS_DOMAIN_ID=1 #TURTLEBOT3' >> ~/.bashrc
$ echo 'export TURTLEBOT3_MODEL=burger'>> ~/.bashrc
$ source ~/.bashrc
```

9. Setting OpenCR
```shell=
$ sudo dpkg --add-architecture armhf  
$ sudo apt-get update  
$ sudo apt-get install libc6:armhf  
$ export OPENCR_PORT=/dev/ttyACM0  
$ export OPENCR_MODEL=burger
$ rm -rf ./opencr_update.tar.bz2  
$ wget https://github.com/ROBOTIS-GIT/OpenCR-Binaries/raw/master/turtlebot3/ROS2/latest/opencr_update.tar.bz2   
$ tar -xvf opencr_update.tar.bz2 
$ sudo reboot now
$ export OPENCR_PORT=/dev/ttyACM0  
$ export OPENCR_MODEL=burger
$ cd ~/turtlebot3_ws/opencr_update  
$ ./update.sh $OPENCR_PORT $OPENCR_MODEL.opencr 
```

10. Setting Lidar
```shell=
$ echo 'export LDS_MODEL=LDS-01' >> ~/.bashrc
$ source ~/.bashrc
```

11. Make sure you can use keyboard to control the TurtleBot
```shell=
# Terminal 1
$ ros2 launch turtlebot3_bringup robot.launch.py
```
```shell=
# Terminal 2
$ ros2 run turtlebot3_teleop teleop_keyboard
```

#### ROS2 on virtualbox
virtualbox: http://gofile.me/6Ukc0/Z4kJamAOB

#### SLAM
- Pi
```shell=
$ ros2 launch turtlebot3_bringup robot.launch.py
```
- PC
```shell=
# Terminal 1: launch slam node
$ ros2 launch turtlebot3_cartographer cartographer.launch.py
```
```shell=
# Terminal 2: launch teleoperation node
$ ros2 run turtlebot3_teleop teleop_keyboard
```

- save map
```shell=
# Terminal 3: save the map
$ ros2 run nav2_map_server map_saver_cli -f ~/map
```

#### Homework
1. Use TurtleBot SLAM to scan the space map.
2. Combined ESP32 and TurtleBot. Make TurtleBot drive a trajectory and collect WiFi information (RSSI) in the space along the way. The information must have a trajectory and its corresponding RSSI.

#### Scoring Criteria

1. Presentation: 
    - 地圖完整度
    - 如何記錄WiFi訊號
        - 須紀錄當下所有的WiFi
    - 如何記錄trajectory

2. 收資料:
    - trajectory多樣性
    - trajectory覆蓋地圖程度

3. 可設定以下參數
    - 軌跡為 T 秒 (ex. 30秒)
    - 間隔 trace_t 秒記錄一次座標 (ex. 1秒)
    - 間隔 rssi_t 秒記錄一次 RSSI (ex. 0.5秒)

#### Note
1. 不建議設定秒數來對齊 WiFi 和 trajectory，因為 WiFi scan 大概要3.多秒才完成一次掃描。如果3秒紀錄一次資料，則有可能出現不同座標上有相同 WiFi 結果，甚至是3秒前的結果。
2. 建議根據 WiFi scan 頻率來紀錄資料，即為有新的 WiFi 結果就紀錄座標與 WiFi。
3. 都使用 keyboard 控制 turtlebot
4. 資料格式: 
    [時間] [絕對座標] [WiFi資料]
    [時間] [絕對座標] [WiFi資料]
    [時間] [絕對座標] [WiFi資料]
5. WiFi資料須包含 1. SSID, 2. MAC address, 3. RSSI
    

![結果](https://hackmd.io/_uploads/rJjZeKE8ll.jpg)
![畫圖](https://hackmd.io/_uploads/Hy5LlFVUgx.jpg)


#### Trouble shoot
##### raspberry can't neworking
```shell=
$ sudo vim.tiny /etc/netplan/50-cloud-init.yaml # 確認設定是否正確
```