Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Simulating a joystick
Forum Updated to NodeBB v4.3 + New Features

Simulating a joystick

Scheduled Pinned Locked Moved Solved General and Desktop
2 Posts 1 Posters 166 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • serkan_trS Offline
    serkan_trS Offline
    serkan_tr
    wrote on last edited by serkan_tr
    #1

    hello, i am working on a project, my aim is as follows, i get 2 joyistick data via "uart". I process and filter this data and I have 0 - 150 data (for x and y). I'm doing this job on the C++ side. I am accessing this data from my QML file as I generate the x and y values. Now there is x and y data on the QML side. I made two nested rectangles of this data. I made the rectangles I created take the shape of a circle by giving them a radius. I'm putting these circles together, the big circle is h:150 w:150 the smaller one is h:20 w:20. My aim is to move the circle in the interior according to the incoming x and y states. it works up to this point. but the data coming from the joystick (0,0), (0,150), (150, 0) (150, 150) ... the circle in the inner part passes the outer circle. To avoid this situation, I first subtract the x and y values ​​from the radius and add their squares, and if they are not greater than the square of the radius, I get the same, but if it is, what should I do? I use the "atan2" function to get the x and y data and get a radian, put it in the sin and cos data of this radian and multiply with the radius, but still got the wrong result. The reason for getting wrong results is because the center of the circle is in the upper left corner. What algorithm should I write?
    code:

    #include "SerialComm.hpp"
    #include <QSerialPortInfo>
    #define VOLTAGE_DEBUG
    // #define DEBUG
    
    Serial::Serial(): state(0), count(0), voltage(0), cam_value(0){
        port_ = new QSerialPort;
    
        connectionTimer = new QTimer(this);
        connectionTimer->setInterval(100);
        connectionTimer->start();
    
        raw_data.resize(V_SIZE);
        stable_data.resize(V_SIZE);
        joy_offset.resize(JOY_ALL);
        initializationData(RESET_ALL);
    
        checkDeviceConnection();
    
        connect(port_, &QSerialPort::readyRead, this, &Serial::readBytes);
        connect(port_, &QSerialPort::errorOccurred, this, [this]() { connectionTimer->start(); });
        connect(connectionTimer, &QTimer::timeout, this, &Serial::checkDeviceConnection);
    }
    
    Serial::~Serial(){
        port_->close();
        connectionTimer->stop();
        delete connectionTimer;
        delete port_;
    }
    
    void Serial::checkDeviceConnection(){
        if(port_->isOpen()) {  port_->close();  }
    
        for(const QSerialPortInfo port_list : QSerialPortInfo::availablePorts()){
            if((port_list.manufacturer() == "FTDI") || (port_list.description() == "Arduino Mega 2560") ){
                port_->setPortName(port_list.portName());
                port_->setBaudRate(BAUDRATE);
                port_->setDataBits(QSerialPort::Data8);
                start_com = true;
                while(port_->open(QIODevice::ReadOnly)){  qDebug() << "ReadOnly";   }
                connectionTimer->stop();
            }
    #ifdef DEBUG
            qDebug() << "-----------------------------------------------------";
            qDebug() << "portName:          " << port_list.portName();
            qDebug() << "systemLocation:    " << port_list.systemLocation();
            qDebug() << "description:       " << port_list.description();
            qDebug() << "manufacturer:      " << port_list.manufacturer();
            qDebug() << "serialNumber:      " << port_list.serialNumber();
            qDebug() << "vendorIdentifier:  " << port_list.vendorIdentifier();
            qDebug() << "productIdentifier: " << port_list.productIdentifier();
    #endif
        }
    }
    
    void Serial::readBytes(){
        while(port_->bytesAvailable()){
            uint8_t cur_byte;
            port_->read((char*)&cur_byte, 1);
            if(state == 0){
                if((cur_byte == HEADER) && (prev_byte == FOOTHER)){ rx_buffer[state++] = cur_byte; }
                else { state = 0; }
            }else if( state < HEADER_LEN + PAYLOAD_LEN){
                rx_buffer[state++] = cur_byte;
            }else if(state < HEADER_LEN + FOOTHER_LEN + PAYLOAD_LEN){
                state = 0;
                prev_byte = cur_byte;
                if(cur_byte == FOOTHER){
                    raw_data[0] = (static_cast<int16_t>(rx_buffer[1] & 0x01));
                    raw_data[1] = (static_cast<int16_t>((rx_buffer[1]>>1) & 0x01));
                    raw_data[2] = (static_cast<int16_t>((rx_buffer[1]>>2) & 0x01));
                    raw_data[3] = (static_cast<int16_t>((rx_buffer[1]>>3) & 0x01));
                    raw_data[4] = (static_cast<int16_t>((rx_buffer[1] >> 4) | ((rx_buffer[2] << 4) & 0x03FF)));
                    raw_data[5] = (static_cast<int16_t>((rx_buffer[2] >> 6) | ((rx_buffer[3] << 2) & 0x03FF)));
                    raw_data[6] = (static_cast<int16_t>((rx_buffer[4])      | ((rx_buffer[5] << 8) & 0x03FF)));
                    raw_data[7] = (static_cast<int16_t>((rx_buffer[5] >> 2) | ((rx_buffer[6] << 6) & 0x03FF)));
                    raw_data[8] = (static_cast<int16_t>((rx_buffer[6] >> 4) | ((rx_buffer[7] << 4) & 0x03FF)));
                    raw_data[9] = (static_cast<int16_t>((rx_buffer[7] >> 6) | ((rx_buffer[8] << 2) & 0x03FF)));
                }else{ state = 0;  }
            }else    { state = 0;  }
            prev_byte = cur_byte;
        }
    }
    
    void Serial::bufferCopy(QVector<int>& data){
        std::copy(raw_data.begin(), raw_data.end(), stable_data.begin());
    
        stable_data[QGC_VOL] = voltageFilter((float)raw_data[QGC_VOL]);
        stable_data[QGC_CAM] = camSliderFilter(raw_data[QGC_CAM]);
        stable_data[QGC_RX] = joyDataFilter(raw_data[4], JOY_RX);
        stable_data[QGC_RY] = joyDataFilter(raw_data[5], JOY_RY);
        stable_data[QGC_LX] = joyDataFilter(raw_data[8], JOY_LX);
        stable_data[QGC_LY] = joyDataFilter(raw_data[6], JOY_LY);
        std::copy(stable_data.begin(), stable_data.end(), data.begin());
    
    #ifdef DEBUG
        qDebug() << "Genel:" <<  raw_data[4] << raw_data[5] << raw_data[6] << raw_data[8];
        qDebug() << "Data: " << stable_data[QGC_RX] << stable_data[QGC_RY] << stable_data[QGC_LX] << stable_data[QGC_LY];
    #endif
    }
    
    int Serial::voltageFilter(float new_data){
    #ifdef VOLTAGE_DEBUG
        qDebug() << "voltage raw_data: " << new_data;
    #endif 
        new_data = filter[5].kalman(new_data);
        if(new_data < 610.0 || new_data > 860.0) { return -1; }
        new_data = map(new_data, 610.0, 860.0, 0.0, 100.0);
        if(filter[6].getKalmanDataOld() == 0){ filter[6].setKalmanDataOld(new_data);  }
        filter[6].setQR(0.005, 0.995);
        return (int)filter[6].kalman(new_data);  
    }
    
    int Serial::camSliderFilter(float new_data){
    #ifdef CAM_SLIDER_DEBUG
        qDebug() << "Cam slider raw_data: " << new_data;
    #endif 
        new_data = filter[4].kalman(new_data);
        if(new_data > (512 + OFFSET_CAM) ) { return cam_value += 5; }
        else if(new_data < (512 - OFFSET_CAM)) { return cam_value -= 5; }
        new_data  = constrain(new_data, 0.0, 1023.0);
        return (int)cam_value;
    }
    
    void Serial::calibrateJoy(){
        if(count == CALIBRATE_COUNT){
            joy_offset[JOY_RX] /= CALIBRATE_COUNT;  
            joy_offset[JOY_RY] /= CALIBRATE_COUNT;  
            joy_offset[JOY_LX] /= CALIBRATE_COUNT;  
            joy_offset[JOY_LY] /= CALIBRATE_COUNT;  
            calibrated = false;
        }else if(calibrated){
            joy_offset[JOY_RX] +=  filter[JOY_RX].kalman(constrain(raw_data[4], 0.0, 1023.0));
            joy_offset[JOY_RY] +=  filter[JOY_RY].kalman(constrain(raw_data[5], 0.0, 1023.0));
            joy_offset[JOY_LX] +=  filter[JOY_LX].kalman(constrain(raw_data[8], 0.0, 1023.0));
            joy_offset[JOY_LY] +=  filter[JOY_LY].kalman(constrain(raw_data[6], 0.0, 1023.0));
        }
        count++;
    }
    
    int Serial::joyDataFilter(float new_data, JoyData_e joy_num){
        new_data = constrain(new_data, JOY_MIN_OFFSET, JOY_MAX_OFFSET);
        new_data = filter[joy_num].kalman(new_data);
        if((new_data > (joy_offset[joy_num] - JOY_OFFSET)) && (new_data < (joy_offset[joy_num] + JOY_OFFSET))){
            new_data = 512;
        }else if(new_data <= (joy_offset[joy_num] - JOY_OFFSET)){
            new_data = map(new_data, JOY_MIN_OFFSET, joy_offset[joy_num] - JOY_OFFSET, 0.0, 511.0);        
        }else{
            new_data = map(new_data, joy_offset[joy_num] + JOY_OFFSET, JOY_MAX_OFFSET, 513.0, 1023.0);
        }
        new_data = map(new_data, 0, 1023, 0.0, 150.0);
        return (int)new_data;
    }
    
    void Serial::initializationData(DataReset_e n_data){
        switch (n_data){
            case RAW_DATA_R:
                std::fill(raw_data.begin(), raw_data.end(), 0);
                break;
            case STABLE_DATA_R:
                std::fill(stable_data.begin(), stable_data.end(), 0); 
                break;
            case JOY_OFFSET_R:
                std::fill(joy_offset.begin(), joy_offset.end(), 512);
                break;
            case JOY_OFFSET_Z:
                std::fill(joy_offset.begin(), joy_offset.end(), 0);
                calibrated = true; 
                count = 0;
                break;
            case RESET_ALL:
                std::fill(raw_data.begin(), raw_data.end(), 0);
                std::fill(stable_data.begin(), stable_data.end(), 0); 
                std::fill(joy_offset.begin(), joy_offset.end(), 512);
                break;
            default:
                break;
        }
    }
    
    
    void MainRos::updateData(){
        serial_comm.bufferCopy(m_data);
        joyCallback(m_data);
        m_data[QGC_RX] = map(m_data[QGC_RX], 0.0, 150.0, 150.0, 0.0);
        m_data[QGC_RY] = map(m_data[QGC_RY], 0.0, 150.0, 0.0, 150.0);
        m_data[QGC_LX] = map(m_data[QGC_LX], 0.0, 150.0, 150.0, 0.0);
        m_data[QGC_LY] = map(m_data[QGC_LY], 0.0, 150.0, 0.0, 150.0);
        axisProtection(m_data[QGC_LX],  m_data[QGC_LY], true);
        // axisProtection(m_data);
        setData(m_data);
    }
    
    void MainRos::axisProtection(float y, float x, bool flag){
        x = abs(x - 75);
        y = abs(y - 75);
        if((x * x + y * y) > 75 * 75){
            double angleRadians = atan2f(x, y);
            m_data[QGC_LY] = 75 * sinf(angleRadians);
            m_data[QGC_LX] = 75 * cosf(angleRadians);
        }
        // float tan_derece = 45;
        // m_data[QGC_RX] = map(m_data[QGC_RX], 0.0, 150.0, 150.0, 0.0);
        // m_data[QGC_RY] = map(m_data[QGC_RY], 0.0, 150.0, 0.0, 150.0);
        // m_data[QGC_LX] = map(m_data[QGC_LX], 0.0, 150.0, 150.0, 0.0);
        // m_data[QGC_LY] = map(m_data[QGC_LY], 0.0, 150.0, 0.0, 150.0);
        // if(sqrt(m_data[QGC_RX] * m_data[QGC_RX] + m_data[QGC_RY] * m_data[QGC_RY]) > 75.0){
        //     double angleRadians = std::atan2(m_data[QGC_RX], m_data[QGC_RY]);
        //     double angleDegrees = angleRadians * (180.0 / M_PI);
        //     m_data[QGC_RX] = 75.0 * std::sin(angleRadians);
        //     m_data[QGC_RY] = 75.0 * std::cos(angleRadians);
        // }
        // if(sqrt(m_data[QGC_RX] * m_data[QGC_RX] + m_data[QGC_RY] * m_data[QGC_RY]) > 75.0){
        //     double angleRadians = std::atan2(m_data[QGC_LX], m_data[QGC_LY]);
        //     double angleDegrees = angleRadians * (180.0 / M_PI);
        //     m_data[QGC_RX] = 75.0 * std::sin(angleRadians);
        //     m_data[QGC_RY] = 75.0 * std::cos(angleRadians);
        // }
    
        // qDebug() << m_data[QGC_RX] <<  m_data[QGC_RY] << m_data[QGC_LX] << m_data[QGC_LY];
    }
    
    

    qml:

     Rectangle{
            id:left_joy_rec
            anchors.top:left_top_slider.bottom
            anchors.topMargin:45
            anchors.left: parent.left
            anchors.leftMargin: 80
            width: joy_size
            height:joy_size
            radius:joy_size/2
            clip: true
            color:"#D9D9D9"
            Rectangle{
                id:line1
                anchors.centerIn:parent
                width: parent.width
                height: 2
                color: "black"
            }
            Rectangle{
                id:line2
                anchors.centerIn:parent
                width: 2
                height: parent.height
                color: "black"
            }
            Rectangle{
                id:left_joy
                width: joy_point_size
                height:joy_point_size
                radius:joy_point_size
                visible: true
                x: main_ros.data[6] - 10
                y: main_ros.data[8] - 10
                color:/*"#222222"*/ "red"
            }
    
        }
    
        Rectangle{
            id:right_joy_rec
            anchors.top:left_top_slider.bottom
            anchors.topMargin:45
            anchors.right: parent.right
            anchors.rightMargin: 80
            width: joy_size
            height:joy_size
            radius:joy_size/2
            clip: true
            color:"#D9D9D9"
            Rectangle{
                id:line3
                anchors.centerIn:parent
                width: parent.width
                height: 2
                color: "black"
            }
            Rectangle{
                id:line4
                anchors.centerIn:parent
                width: 2
                height: parent.height
                color: "black"
            }
            Rectangle{
                id:right_joy
                width: joy_point_size
                height:joy_point_size
                radius:joy_point_size
                visible: true
                x: main_ros.data[4] - 10
                y: main_ros.data[5] - 10
                color:/*"#222222"*/ "red"
                }
        }
    
    1 Reply Last reply
    0
    • serkan_trS Offline
      serkan_trS Offline
      serkan_tr
      wrote on last edited by
      #2

      I made a joystick as I wanted. You can check the code on this page.

      1 Reply Last reply
      0
      • serkan_trS serkan_tr has marked this topic as solved on

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved