Servo и ошибка при передаче значения 128 градусов

eugene_ins
Offline
Зарегистрирован: 13.09.2014

Доброго времени суток! Проблема почти полностью описана в теме. Если подробнее: есть манипулятор с 4мя сервами (база, плече, локоть и кисть). Подключены они к Ардуино Уно. На Уне изначально был примерно такой скетч:

#include <Firmata.h>
#include <Servo.h>

Servo servo8;
Servo servo9;
Servo servo10;
Servo servo11;

void analogWriteCallback(byte pin, int value)
{
    if ( pin == 8 ) {
        servo8.write(value);
    }

    if ( pin == 9 ) {
        servo9.write(value);
    }

    if ( pin == 10 ) {
        servo10.write(value);
    }

    if ( pin == 11 ) {
        servo11.write(value);
    }
}

void setup()
{
    Firmata.setFirmwareVersion(0, 2);
    Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);

    servo8.attach(8);
    servo9.attach(9);
    servo10.attach(10);
    servo11.attach(11);

    Firmata.begin(9600);
}

void loop() {
    while(Firmata.available())
    Firmata.processInput();
}

Отдельная програмка, написанная в Qt, передает через класс Serial значения углов. Примерно так:

#define FRST_PORT 8
#define SRVS_AMOUNT 4
#define DELAY1 10
#define DELAY2 500

void MainWindow::handler() {
    if (!outputFile->open(QIODevice::ReadOnly | QIODevice::Text)) {
        statusLbl->setText("Can't open file");
    }
    while ( !outputFile->atEnd()) {
        QString str = outputFile->readLine();

        QTextStream stream(&str);
        QList<int> intList;

        for (int i = 0; i < SRVS_AMOUNT; i++) {
            int number;
            stream >> number;
            intList.append(number);
        }

        uint8_t buf[3];

        for (int i = 0; i < SRVS_AMOUNT; i++) {
            buf[0] = 0xE0 | (i + FRST_PORT);
            buf[1] = intList[i] & 0x7F;
            buf[2] = intList[i] >> (i + FRST_PORT) & 0x7F;
            serial->Send(buf, 4);
            Sleep(DELAY1);
        }
        Sleep(DELAY2);
        statusLbl->setText("Keep moving...");

    }
        outputFile->close();
        statusLbl->setText("Reading is finished");
}

Дальше, serial.Send() отправляет эту красоту в файл (com-порт).

Как я понимаю, проблема в том, что 01111111 = 127 - это обрабатывается, а 10000000 - 128 и больше - нет. То есть, 8й бит отдается под знак. 

Внимание вопрос: как обработать эту ошибку?

Всем спасибо:)

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Поковырял Firmata

      case ANALOG_MESSAGE:
        if(currentAnalogCallback) {
          (*currentAnalogCallback)(multiByteChannel,
                                   (storedInputData[0] << 7)
                                   + storedInputData[1]);

значение передается двумя байтами(вначале старший, потом младший), а у вас что-то неясное ограниченное по 127  и не в нужном порядке:

            buf[1] = intList[i] & 0x7F;
            buf[2] = intList[i] >> (i + FRST_PORT) & 0x7F;

другой протокол. Наверно нужно что-то вроде этого. И тип беззнаковый   QList<uint16_t> intList

            buf[1] = (intList[i] >> 7) & 0xFF;
            buf[2] = intList[i] & 0xFF;

а байт команды совмещен с номером порта так:

    if(inputData < 0xF0) {
      command = inputData & 0xF0;
      multiByteChannel = inputData & 0x0F;
    } else {
      command = inputData;
      // commands in the 0xF* range don't use channel data
    }

С этим в вашем исходнике порядок.
 

eugene_ins
Offline
Зарегистрирован: 13.09.2014

Ух ты. Спасибо) Темный лес пока что работа с COM.

QList<uint16_t> intList ? Данные на на условие i>=0 && i<=180 проверяются на предыдущих этапах. Или я что-то неправильно понял? И какого типа buf?  Может это таки он uint16_t?

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

uint8_t - 8 бит без знака тоесть 0x00...0xFF

uint16_t - 16 бит - 0x0000...0xFFFF

тоесть 8*2=16

2 байта дляпередачи инфы, содержащийся в одной переменной uint16_t.

eugene_ins
Offline
Зарегистрирован: 13.09.2014

2 байта, а не бита. Я туплю