Фон
Я делаю порт кода Arduino в C ++ и у меня возникают проблемы с данными, отправляемыми в виде unsigned char. Мне нужно отправить 8-байтовый пакет без знака, состоящий из:
Byte 1 - Header - 0xFF
Byte 2 - Right Joy Vertical - value between -100 to 100 shifted up by 128
Byte 3 - Right Joy Horizontal - value between -100 to 100 shifted up by 128
Byte 4 - Left Joy Vertical - value between -100 to 100 shifted up by 128
Byte 5 - Right Joy Horizontal - value between -100 to 100 shifted up by 128
Byte 6 - Button Values - 8 bit byte where each bit is mapped to a button
Byte 7 - Extended Inst. - "0" not needed
Byte 8 - Checksum
У кода arduino был код, написанный как:
Serial.write((unsigned char)right_V);
Serial.write((unsigned char)buttons);
Это явно не так просто в C ++.
Проблемы:
1) Как правильно настроить тип для отправки 8 байтов неподписанного символа с помощью моей функции sp-> write ()?
2) Какие модификаторы printf я использую для отображения данных в виде беззнаковых байтов в HEX?
Разъяснение кода
btn
является структурой, состоящей из значений джойстика двойной точности
cmd[]
массив без знака размера 8
sp->write(const char * data, int length)
является оберткой для функции записи fstream Я включил определение на всякий случай.
ROS_INFO
это оболочка для printf для вывода на консоль ROS
КОД
// *****************************************************************************
// Create the Commander unsigned char packet as per the Arbotix Commander specifications
int PhantomXROS::arbotixCmdPackage(cont_value btn)
{
int d_cmd=0;
unsigned char st_code;
std::stringstream ss;
ss << std::hex << "0xFF";
ss >> st_code;
//Mapping joystick values to the servo values of the robot arm
int right_V=this->map(btn.rightV, -1, 1, -100, 100)+128;
int right_H=this->map(btn.rightH, -1, 1, -100, 100)+128;
int left_V=this->map(btn.leftV, -1, 1, -100, 100)+128;
int left_H=this->map(btn.leftH, -1, 1, -100, 100)+128;//Bytes 1-5 Convert integers to bytes
this->cmd[0] = (unsigned char)st_code;
this->cmd[1] = (unsigned char)right_V;
this->cmd[2] = (unsigned char)right_H;
this->cmd[3] = (unsigned char)left_V;
this->cmd[4] = (unsigned char)left_H;
//Byte 6 - Assign a button ON/OFF to its corresponding bit
d_cmd += (btn.R1 > 0) ? 1 : 0;
d_cmd += (btn.R2 > 0) ? 2 : 0;
d_cmd += (btn.R3 > 0) ? 4 : 0;
d_cmd += (btn.L4 > 0) ? 8 : 0;
d_cmd += (btn.L5 > 0) ? 16 : 0;
d_cmd += (btn.L6 > 0) ? 32 : 0;
d_cmd += (btn.RT > 0) ? 64 : 0;
d_cmd += (btn.LT > 0) ? 128 : 0;
this->cmd[5] = (unsigned char)d_cmd;
//Byte 7 - Extended instruction - none, therefore 0
this->cmd[6] = (unsigned char)0;
//Byte 8 - Checksum
this->cmd[7] = (unsigned char)((255 - (right_V+right_H+left_V+left_H+d_cmd)%256));
//Reinterpret the cmd byte array to an 8 char string
std::string buf(reinterpret_cast<const char*>(cmd), 8);
//write to the arbotix serial handle
try{
sp_->write(buf.c_str(),buf.size());
}
catch(cereal::Exception& e){
ROS_INFO("Could not write to Arbotix:");
ROS_BREAK();
return(-1);
}//Output data to the ROS console
if(this->timer > 500)
{ROS_INFO("Arbotix Cmd right_v has written: %d", right_V);
ROS_INFO("Arbotix Cmd right_h has written: %d", right_H);
ROS_INFO("Arbotix Cmd left_v has written: %d", left_V);
ROS_INFO("Arbotix Cmd left_h has written: %d", left_H);
ROS_INFO("Arbotix Cmd d_cmd has written: %d", d_cmd);
ROS_INFO("String command: %s",buf.c_str());
this->timer = 0;
}return 0;}
Ниже приведен код записи
int cereal::CerealPort::write(const char * data, int length)
00146 {
00147 int len = length==-1 ? strlen(data) : length;
00148
00149 // IO is currently non-blocking. This is what we want for the more cerealon read case.
00150 int origflags = fcntl(fd_, F_GETFL, 0);
00151 fcntl(fd_, F_SETFL, origflags & ~O_NONBLOCK); // TODO: @todo can we make this all work in non-blocking?
00152 int retval = ::write(fd_, data, len);
00153 fcntl(fd_, F_SETFL, origflags | O_NONBLOCK);
00154
00155 if(retval == len) return retval;
00156 else CEREAL_EXCEPT(cereal::Exception, "write failed");
00157 }
Ваше приведение типов правильное, но с использованием std:string
здесь не нужно Вы можете использовать cmd
буфер прямо в вашем вызове sp_->write()
//write to the arbotix serial handle
try
{
sp_->write(reinterpret_cast<const char*>(cmd), 8);
}
catch(cereal::Exception& e){
ROS_INFO("Could not write to Arbotix:");
ROS_BREAK();
return(-1);
}
Для печати данных в шестнадцатеричном формате вы можете использовать %02x
или же %02X
спецификаторы формата вроде так
ROS_INFO("Arbotix Cmd right_v has written: %02X", right_V);
Это говорит printf
функция (используется ROS_INFO
) распечатать как минимум две шестнадцатеричные цифры и добавить нулевой символ, если выводится менее двух цифр.
Других решений пока нет …