Documentation/FlyCore i225U WikiEnglish · V1
Browse documentation
Beginner User Guide

FlyCore Recognition and Planning Computer Application Guide

Before you begin, confirm that the following conditions are met:

9 min read · English documentation

Preparations Before Use

Before you begin, confirm that the following conditions are met:

Hardware Preparation

  • One Windows computer

  • Ethernet cable

  • FlyCore system

Network and Account Information

The recognition and planning computer uses the following address and credentials:

Recognition and planning computer IP: 192.168.1.66

Username: amov

Password: amov

Hardware Information

External hardware interfaces of the recognition and planning computer

The recognition and planning computer has two external hardware interfaces.

Interface ①: Primarily the external serial port of the recognition and planning computer, used mainly for serial communication with the flight controller.

Interface ②: Primarily the MIPI camera interface and serial interfaces for the gimbal.

image.png

Logging In to the RK System

Connecting the Development Board

Use an Ethernet cable to connect the development board to your host computer.

Logging In via SSH

Run the following command in a terminal:

ssh amov@192.168.1.66

Enter the password when prompted:

amov

After a successful login, you will enter the terminal of the recognition and planning computer.

Checks When SSH Login Fails

Check the following first:

Whether the host and the recognition and planning computer are on the same subnet

Whether the Ethernet cable is connected properly

Whether the target IP is reachable

Whether the recognition and planning computer has started normally

Whether the username or password has been changed

You can first run the following command on the host:


ping 192.168.1.66

PTP Time Synchronization

Purpose

This step configures the recognition and planning computer as a slave to synchronize its time with the mapping and localization onboard computer.

Command

Run the following command in the terminal of the recognition and planning computer:


sudo ptpd2 -s -i eth0 -C

Determining Success

If the host IP appears in the output, the PTP configuration has usually succeeded and the recognition and planning computer has begun synchronizing its time with the host.

Troubleshooting Suggestions

If synchronization fails, focus on checking the following:

Whether eth0 is the network interface actually in use

Whether the host is providing a PTP master clock

Whether the network link is functioning normally

Whether the device's time synchronization service is occupied or disrupted by another program

Video Streaming, Stream Playback, and Image Capture

First, use the MIPI interface to connect to interface ② shown above.

Implementing Streaming

Logging In to the Recognition and Planning Computer

First, log in to the recognition and planning computer via SSH:

ssh amov@192.168.1.66

Starting mediamtx

Enter the tool directory and start it:


cd Push_flow_Tool
./mediamtx &

Viewing Camera Device Numbers

Run:


v4l2-ctl --list-devices

Note: The /dev/videoX number may differ among device batches, camera modules, or system versions. Use the actual query result as the device number in subsequent commands.

Infrared Camera Streaming Example


gst-launch-1.0 v4l2src device=/dev/video20 io-mode=4 ! video/x-raw,width=1280,height=512 ! mpph265enc ! rtspclientsink protocols=udp latency=0 location=rtsp://127.0.0.1:8554/1

Visible-Light Camera Streaming Example (IMX586)


gst-launch-1.0 v4l2src device=/dev/video11 io-mode=4 ! video/x-raw,width=1920,height=1080 ! mpph265enc ! rtspclientsink protocols=udp latency=0 location=rtsp://127.0.0.1:8554/1

Notes:

The device=/dev/videoX values used for the infrared and visible-light cameras are not necessarily fixed.

By default, the stream is sent to the local mediamtx instance at:


rtsp://127.0.0.1:8554/1

Playing the Stream on the Host Computer

Use VLC on the host computer to open the network stream:


rtsp://192.168.1.66:8554/1

Notes:

4000x3000 is an example resolution.

Replace the device number with the actual camera node.

Camera Sample Programs

The original document includes OpenCV-based camera examples for the color camera and infrared camera. These examples capture a single-frame image and save it as a JPG file.

For this user application guide, you only need to understand how to run the examples; there is no need to read the source code first.

Color Camera Example


cd rgb
mkdir build
cd build
cmake ..
make
./rgb_camera_demo

After the program runs successfully, the following file will be generated in the current directory:


rgb_capture.jpg

Infrared Camera Example


cd ti
mkdir build
cd build
cmake ..
make
./ti_camera_demo

After the program runs successfully, the following file will be generated in the current directory:


ti_capture.jpg

Usage Notes

By default, the program opens a /dev/videoX device internally.

If the default device number is incorrect, pass the actual device number as a command-line argument at runtime.

The color camera example supports changing the resolution; the example sets it to a maximum of 4000x3000.

Serial Port Description

When connected to interface ②, the recognition and planning computer controls the gimbal through the following serial ports:

ttyS7

ttyS8

Users can select a gimbal solution according to their requirements and define their own communication protocol to control the gimbal through the serial port.

Communicating with the Flight Control Computer (BSA-PX4)

Flight controller configuration: First configure the correct baud rate and serial port number on the flight controller. For example, when using DDS for communication through the TELEM2 interface, set SER_TEL2_BAUD to 921600 in the QGC parameters.

image.png

image.png

Recognition and planning computer configuration and verification: In the terminal of the recognition and planning computer, set the baud rate for the corresponding serial port (for example, ttyS6): sudo stty -F /dev/ttyS6 921600

Purpose

View the data received over the serial port in hexadecimal format to confirm whether the recognition and planning computer can continuously receive MAVLink data sent by the flight controller.

Command

sudo cat /dev/ttyS6 | xxd

Normal Output

The terminal should continuously output hexadecimal data. Continuous data indicates that the serial link is connected. If there is no output, check the serial port number, baud rate, wiring, and flight controller port configuration.

Subsequent Development

After the link has been verified, users can communicate with the flight controller and perform secondary development through this serial port (/dev/ttyS6), using the DDS or MAVLink protocol to transmit localization, planning, and control data.

image.png

Obtaining Mapping and Localization Information

The mapping and localization onboard computer continuously sends map and localization information to the recognition and planning computer. Through UDP broadcast, the recognition and planning computer can obtain map and localization data by listening on port 8888. This data is used for UAV navigation and planning.

The following is ROS 2 sample code. It assumes that the ROS 2 packages are installed on the recognition and planning computer. If the ROS 2 packages are not installed by default, it is recommended to use AI (Cursor or Codex) to take over this onboard computer by logging in through SSH with a non-interactive public key. After establishing passwordless SSH access, the AI can automatically detect the libraries that the system requires and install the corresponding ROS 2 packages, greatly improving development efficiency.

The following uses Cursor as an example to explain how to use AI to take over this onboard computer.

1: Log in to the recognition and planning computer from Cursor's terminal.

2: Copy the local public key to the recognition and planning computer. If the local machine has no key, generate one first. AI can guide both non-interactive key generation and copying the public key, so these procedures are not described here. Ultimately, you can use passwordless SSH in the AI dialog to log in to the recognition and planning computer, obtain the highest system privileges, and automatically write code. After the product is released, close these SSH ports to avoid security risks.

Sample code:

      
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cmath>

#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl_conversions/pcl_conversions.h>

// #include "bsaslam2/udp/crcLib.h"
// #include "bsaslam2/utils/tic_toc.h"

// ROS2 includes
#include <rclcpp/rclcpp.hpp>
#include <sensor_msgs/msg/point_cloud2.hpp>
#include <geometry_msgs/msg/pose_stamped.hpp>
#include <nav_msgs/msg/odometry.hpp>

// Eigen includes
#include <Eigen/Dense>
#include <Eigen/Geometry>

typedef pcl::PointXYZINormal PointType;
typedef pcl::PointCloud<PointType> PointCloudXYZI;

// ROS 2 node class
class UDPPointCloudReceiver : public rclcpp::Node
{
public:
    UDPPointCloudReceiver() : Node("udp_pointcloud_receiver"),uav_id_(1)
    {
        // Create the point cloud topic publisher
        pointcloud_pub_ = this->create_publisher<sensor_msgs::msg::PointCloud2>(
            "/uav" + std::to_string(uav_id_) + "/prometheus/local_points", 10);
        
        // Create the pose topic publisher
        pose_pub_ = this->create_publisher<geometry_msgs::msg::PoseStamped>(
            "/uav" + std::to_string(uav_id_) + "/prometheus/pose_slam", 10);
        
        // Create the odometry topic publisher
        odom_pub_ = this->create_publisher<nav_msgs::msg::Odometry>(
            "/uav" + std::to_string(uav_id_) + "/prometheus/odom_slam", 10);
        
        RCLCPP_INFO(this->get_logger(), "UDP PointCloud Receiver started");
    }
    
    // Publish point cloud data
    void publishPointCloud(const PointCloudXYZI::Ptr& cloud, double timestamp)
    {
        if (cloud->empty()) return;
        
        sensor_msgs::msg::PointCloud2 cloud_msg;
        pcl::toROSMsg(*cloud, cloud_msg);
        
        // Set the message header
        cloud_msg.header.stamp = this->now();
        //cloud_msg.header.frame_id = "/world";
        cloud_msg.header.frame_id = "/uav" + std::to_string(uav_id_) + "/lidar_link";
        
        // Log the number of points in the point cloud
        RCLCPP_INFO(this->get_logger(), "Publishing pointcloud with %zu points", cloud->size());
        
        // Publish the point cloud
        pointcloud_pub_->publish(cloud_msg);
    }
    
    // Publish pose data
    void publishPose(const Eigen::Vector3d& pos, const Eigen::Quaterniond& quat, double timestamp)
    {
        geometry_msgs::msg::PoseStamped pose_msg;
        pose_msg.header.stamp = this->now();
        pose_msg.header.frame_id = "/uav" + std::to_string(uav_id_) + "/base_link";
        
        pose_msg.pose.position.x = pos.x();
        pose_msg.pose.position.y = pos.y();
        pose_msg.pose.position.z = pos.z();
        
        pose_msg.pose.orientation.x = quat.x();
        pose_msg.pose.orientation.y = quat.y();
        pose_msg.pose.orientation.z = quat.z();
        pose_msg.pose.orientation.w = quat.w();
        
        pose_pub_->publish(pose_msg);
    }
    
    // Publish odometry data
    void publishOdometry(const Eigen::Vector3d& pos, const Eigen::Quaterniond& quat, 
                        const Eigen::Vector3d& vel, double timestamp)
    {
        nav_msgs::msg::Odometry odom_msg;
        odom_msg.header.stamp = this->now();
        odom_msg.header.frame_id = "/world";
        
        // Position
        odom_msg.pose.pose.position.x = pos.x();
        odom_msg.pose.pose.position.y = pos.y();
        odom_msg.pose.pose.position.z = pos.z();
        
        // Orientation
        odom_msg.pose.pose.orientation.x = quat.x();
        odom_msg.pose.pose.orientation.y = quat.y();
        odom_msg.pose.pose.orientation.z = quat.z();
        odom_msg.pose.pose.orientation.w = quat.w();
        
        // Velocity
        odom_msg.twist.twist.linear.x = vel.x();
        odom_msg.twist.twist.linear.y = vel.y();
        odom_msg.twist.twist.linear.z = vel.z();
        
        odom_pub_->publish(odom_msg);
    }

private:
    rclcpp::Publisher<sensor_msgs::msg::PointCloud2>::SharedPtr pointcloud_pub_;
    rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr pose_pub_;
    rclcpp::Publisher<nav_msgs::msg::Odometry>::SharedPtr odom_pub_;
    int uav_id_;
};

const uint32_t tmp_Crc32Table[256] = {
    0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
    0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
    0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7,
    0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
    0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3,
    0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
    0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF,
    0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
    0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB,
    0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
    0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
    0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
    0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4,
    0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
    0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08,
    0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
    0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC,
    0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
    0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 0xE0B41DE7, 0xE4750050,
    0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
    0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
    0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
    0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1,
    0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
    0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5,
    0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
    0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E, 0xF5EE4BB9,
    0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
    0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD,
    0xCDA1F604, 0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
    0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
    0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
    0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2,
    0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
    0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E,
    0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
    0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A,
    0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
    0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676,
    0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
    0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
    0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
    0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4};

uint32_t tmp_checkCRC32(uint8_t *pData, uint32_t Length)
{
    uint32_t nReg;
    uint32_t nTemp = 0;
    uint16_t i, n;

    nReg = 0xFFFFFFFF;
    for (n = 0; n < Length; n++)
    {
        nReg ^= (uint32_t)pData[n];

        for (i = 0; i < 4; i++)
        {
            nTemp = tmp_Crc32Table[(uint8_t)((nReg >> 24) & 0xff)];
            nReg <<= 8;
            nReg ^= nTemp;
        }
    }
    return nReg;
}

int main(int argc, char** argv)
{
    // Initialize ROS 2
    rclcpp::init(argc, argv);
    
    // Create the ROS 2 node
    auto node = std::make_shared<UDPPointCloudReceiver>();
    
    // Create the UDP socket
    int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (server_socket == -1) {
        RCLCPP_ERROR(node->get_logger(), "Failed to create socket.");
        return -1;
    }

    // Bind the address and port
    sockaddr_in server_address{};
    server_address.sin_family = AF_INET;// IPv4 protocol
    server_address.sin_port = htons(8888);// Port 8888
    server_address.sin_addr.s_addr = INADDR_ANY;// Listen on all network interfaces
 
    if (bind(server_socket, (struct sockaddr*)&server_address, sizeof(server_address)) == -1) {
        RCLCPP_ERROR(node->get_logger(), "Failed to bind socket.");
        close(server_socket);
        return -1;
    }

    RCLCPP_INFO(node->get_logger(), "UDP server started on port 8888");
    // TicToc t_pose, t_cloud;

    try {
        while (rclcpp::ok()) {
            // Process ROS 2 callbacks
            rclcpp::spin_some(node);
            
            // Receive data
            sockaddr_in client_address{};
            socklen_t client_address_size = sizeof(client_address);

            PointCloudXYZI::Ptr save_cloud(new PointCloudXYZI());
            double timestamp = -1.0;// Timestamp; -1 indicates that it is uninitialized
            bool last_bag = false; // Whether the final packet has been received

            while(!last_bag)
            {
                uint8_t buffer[1223] = {0};// Data buffer
                int points_received = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_address, &client_address_size);
                if(points_received > 0)
                {   
                    // Check the frame header
                    bool bCorrupted = false;
                    if(*buffer != 0xEB || *(buffer+1) != 0x90)
                    {
                        bCorrupted  = true;
                        char *response = "The bag is corrupted";
                        sendto(server_socket, response, strlen(response), 0, (struct sockaddr*)&client_address, client_address_size);
                        continue;
                    }

                    if(*(buffer+2) == 0xFF && *(buffer+3) == 0xFF)
                    {
                        uint64_t timestamp;
                        {
                            uint64_t *ptr = (uint64_t *)(buffer+4);// Timestamp
                            timestamp = *ptr;
                        }
                        double time_stamp = timestamp * 1e-9; // Convert to seconds

                        Eigen::Vector3d pos;// Position data
                        {
                            int32_t *ptr = (int32_t *)(buffer+12);
                            pos(0) = *ptr * 1e-6;
                            ptr = (int32_t *)(buffer+16);
                            pos(1) = *ptr * 1e-6;
                            ptr = (int32_t *)(buffer+20);
                            pos(2) = *ptr * 1e-6;
                        }

                        Eigen::Quaterniond quat; // Quaternion orientation
                        {
                            int32_t *ptr = (int32_t *)(buffer+24);
                            quat.x() = *ptr * 1e-6;
                            ptr = (int32_t *)(buffer+28);
                            quat.y() = *ptr * 1e-6;
                            ptr = (int32_t *)(buffer+32);
                            quat.z() = *ptr * 1e-6;
                            ptr = (int32_t *)(buffer+36);
                            quat.w() = *ptr * 1e-6;
                        }

                        Eigen::Vector3d velocity_linear;
                        {
                            int32_t *ptr = (int32_t *)(buffer+40);
                            velocity_linear(0) = *ptr * 1e-6;
                            ptr = (int32_t *)(buffer+44);
                            velocity_linear(1) = *ptr * 1e-6;
                            ptr = (int32_t *)(buffer+48);
                            velocity_linear(2) = *ptr * 1e-6;
                        }

                        unsigned int num_front, num_back;// Point count statistics
                        {
                            uint16_t *ptr = (uint16_t *)(buffer+52);
                            num_front = *ptr;
                            ptr = (uint16_t *)(buffer+54);
                            num_back = *ptr;
                        }

                        float re_project;// Reprojection error
                        {
                            uint32_t *ptr = (uint32_t *)(buffer+56);
                            re_project = (float)(*ptr)/1e6;
                        }
                        // Sensor status
                        uint8_t lidar_state = *(buffer+60);
                        uint8_t imu_state = *(buffer+61);
                        uint8_t cam_state = *(buffer+62);
                        // CRC check 
                        uint32_t *crc = (uint32_t *)(buffer+63);// CRC checksum        
                        uint32_t crc_compute = tmp_checkCRC32(buffer, 63);
                        if(*crc == crc_compute)
                        {
                            printf("timestamp: %.6f, front_num: %u, back_num: %u, reprojection: %.6f, lidar: %x, imu: %x, cam: %x\n",
                                    time_stamp, num_front, num_back, re_project, lidar_state, imu_state, cam_state);
                            
                            // Publish pose and odometry data to ROS 2 topics
                            node->publishPose(pos, quat, time_stamp);
                            node->publishOdometry(pos, quat, velocity_linear, time_stamp);
                        }
                    }
                    else
                    {
                        if(*(buffer+2) == 0x0B)
                            last_bag = true; // Mark this as the final packet

                        // Read the current packet length
                        uint16_t *bag_size = (uint16_t *)(buffer+4);

                        // If the point cloud size is not initialized, read the number of points in this frame
                        if(save_cloud->empty())
                        {
                            uint16_t *ptr = (uint16_t *)(buffer+6);
                            unsigned int point_num = (unsigned int)*ptr;
                            save_cloud->reserve(point_num);
                        }

                        // If the point cloud timestamp is not initialized, read the timestamp
                        if(timestamp == -1.0)
                        {
                            uint64_t *ptr = (uint64_t *)(buffer+8);
                            timestamp = *ptr * 1e-9;
                        }

                        // Read the number of points in the current packet
                        unsigned int bag_point_size;
                        {
                            uint16_t *ptr = (uint16_t *)(buffer+17);
                            bag_point_size = (unsigned int)*ptr;
                        }
                        // Parse the coordinates of each point
                        for(unsigned int i = 0; i < bag_point_size; i++)
                        {
                            int8_t *ptr = (int8_t *)(buffer+19+3*i);
                            int x = (int)*ptr;

                            ptr = (int8_t *)(buffer+19+3*i+1);
                            int y = (int)*ptr;

                            ptr = (int8_t *)(buffer+19+3*i+2);
                            int z = (int)*ptr;

                            PointType pt;
                            pt.x = (float)x * 5.0f * 1e-2; 
                            pt.y = (float)y * 5.0f * 1e-2; 
                            pt.z = (float)z * 5.0f * 1e-2; // Coordinate conversion: multiply by 5.0f * 1e-2 = 0.05 to convert integer coordinates to meters
                            pt.normal_x = 0.0f;// Initialize the normal vector
                            pt.normal_y = 0.0f;
                            pt.normal_z = 0.0f;
                            pt.intensity = 0.0f;// Initialize the intensity
                            save_cloud->points.push_back(pt);
                        }

                        // Read the CRC checksum
                        uint32_t *crc = (uint32_t *)(buffer+(*bag_size));
                        uint32_t crc_compute = tmp_checkCRC32(buffer, *bag_size);
                    }
                }
                else
                {
                    char *response = "The bag is corrupted";
                    sendto(server_socket, response, strlen(response), 0, (struct sockaddr*)&client_address, client_address_size);
                }

                if(last_bag)
                {
                    printf("\ncloud size: %ld\n===========\n", save_cloud->size());
                    
                    // Publish point cloud data to the ROS 2 topic
                    if (!save_cloud->empty()) {
                        printf("Publishing pointcloud with %ld points\n", save_cloud->size());
                        node->publishPointCloud(save_cloud, timestamp);
                    } else {
                        printf("Warning: Point cloud is empty, not publishing\n");
                    }
                }
            }
        }
    }
    catch (...) {
        std::cerr << "An error occurred in the server loop." << std::endl;
    }
    
    // Clean up resources
    close(server_socket);
    rclcpp::shutdown();
    return 0;
}

    

The code above receives point-cloud and position data. After it runs successfully, enter the ROS message list command in the terminal of the recognition and planning computer. The following topics will be displayed:


$ ros2 topic list

    /parameter_events

    /rosout

    /uav1/prometheus/local_points

    /uav1/prometheus/odom_slam

    /uav1/prometheus/pose_slam

The system can display the point-cloud and position topics in real time. Printing the position information confirms that this data is exactly the same as the position information sent to the flight control computer. This position information fuses multisource sensor data from vision, LiDAR, IMU, RTK, and other sources. It serves as input for UAV planning and control and, together with the flight-controller communication interface, forms a complete foundation for control.

Updating the Recognition and Planning Computer System

This section describes how to update the recognition and planning computer and restore it to factory settings. It provides customers with an update method and allows them to reflash and restore the system for continued development after a system failure.

Installing the RK Driver

On the included USB flash drive, open the FlyCore planning computer development materials, select "Android and Linux Image Flashing Tools - RKDevTool and Drivers," and then open the folder shown below.

image.png

Use an extraction tool to extract DriverAssitant_v5.12.zip. In the extracted folder, locate and open the DriverInstall.exe executable.

image.png

After opening DriverInstall.exe, install the Rockchip driver as follows:

Click the "Install Driver" button.

image.png

After a short wait, a window will indicate that the driver was installed successfully. Click the "OK" button.

image.png

Installing the RK Download App

Next, extract RKDevTool_Release_v3.15.zip. This software does not require installation. Locate RKDevTool in the extracted folder and open it.

image.png

Downloading Firmware

After opening the RKDevTool flashing tool, the lower-left corner will display "No Devices Found" because the computer is not yet connected to the development board with a Micro_USB-Type_A cable.

image.png

Next, begin flashing the AMOV image to the recognition and planning computer.

(1) First, connect the development board to the Windows computer through Micro_USB-Type_A. The location of the development board's USB flashing port is shown below:

image.png

(2) Ensure that no other power source is connected to the development board.

(3) Press and hold the MaskROM button on the development board. Its location on the board is shown below:

image.png

(4) Connect power to the development board and power it on. You can then release the MaskROM button.

(5) If the preceding steps were successful, the development board will enter MASKROM mode and the flashing tool interface will display "Found One MASKROM Device."

image.png

(6) Select firmware upgrade.

image.png

(7) Click Firmware and select the firmware.

image.png

(8) Select the firmware.

image.png

(9) Click Upgrade and wait for the upgrade to complete.

Troubleshooting Common Issues

Unable to Connect via SSH

Possible causes:

Incorrect IP address

Abnormal Ethernet cable connection

The recognition and planning computer has not finished starting

The username or password has been changed

Run the following command first:


ping 192.168.1.66

Camera Device Is Not Visible

First run:


v4l2-ctl --list-devices

If the expected /dev/videoX device is not listed, check the following:

Whether the camera is connected properly

Whether the driver loaded normally

Whether the current image includes support for the corresponding camera

Stream Playback Fails

Check the following:

Whether mediamtx is running

Whether the streaming command is running

Whether the RTSP address is correct

Whether the host computer and the recognition and planning computer can communicate over the network

Whether device=/dev/videoX is correct

PTP Synchronization Fails

Check the following:

Whether the PTP master clock is enabled on the host

Whether the network interface on the RK side is eth0

Whether the network is directly connected or configured correctly

Whether another time synchronization service is causing a conflict

Recommended Sequence of Operations

For first-time use, follow this recommended sequence:

Prepare the tools, drivers, and firmware

Flash the firmware in Windows

Connect the recognition and planning computer to the host with an Ethernet cable

Log in to the system via SSH

Enable PTP time synchronization as needed

Start mediamtx

Query the camera device number

Stream video, play the stream, or capture images

Quick Reference for Key Commands

SSH Login


ssh amov@192.168.1.66

PTP Synchronization


sudo ptpd2 -s -i eth0 -C

View Camera Nodes


v4l2-ctl --list-devices

Start mediamtx


cd Push_flow_Tool
./mediamtx &

Infrared Streaming


gst-launch-1.0 v4l2src device=/dev/video20 io-mode=4 ! video/x-raw,width=1280,height=512 ! mpph265enc ! rtspclientsink protocols=udp latency=0 location=rtsp://127.0.0.1:8554/1

Visible-Light Streaming


gst-launch-1.0 v4l2src device=/dev/video11 io-mode=4 ! video/x-raw,width=1920,height=1080 ! mpph265enc ! rtspclientsink protocols=udp latency=0 location=rtsp://127.0.0.1:8554/1