I'm working on an interface for the irobot create 2 and am having trouble reading a single incoming data packet. Where can I find more detailed information about doing this via the use of termios, read(), write(), and printf()? I'm fairly new to this kind of programming, aside from some robotics projects during college, and am probably missing some key points. Please spare my ignorance.
So far I've successfully confirmed sending of commands which initialize the robot, start it in various modes, start/stop the IO, and turn the robot off. To read the data, which comes in as a single byte, I've sent the commands to locate the designated sensor packet via the write function and this is where I get confused. I've allocated a vector for a single byte and am trying to read() the returned value and then printf() it. I'm not sure which data types to use when printing the value or if I'm even getting what I want.
*yungBot.cpp*
#include "yungBot.h"
#include <iostream>
/*initialize robot*/
int yungBot::init(const char *yungin){
fd = open(yungin, O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1){
perror("Error, failed to connect");
}
else{
fcntl(fd,F_SETFL,0);
tcflush (fd, TCIFLUSH);
}
struct termios parameters;
int get = tcgetattr(fd, ¶meters);
if(get == -1){
perror("Error getting attributes");
}
else{
printf("%s\n", "Get attributes: success");
}
cfmakeraw (¶meters);
//sets input and output baud rate
cfsetispeed(¶meters,B115200);
cfsetospeed(¶meters,B115200);
// or forces values to 1; and forces all values to 0 (off);
parameters.c_iflag &= ~(IXON | IXOFF); //flow control off;
parameters.c_cflag |=(CLOCAL | CREAD);
parameters.c_cflag &= ~(PARENB | CSTOPB);//no parity
parameters.c_cflag &= ~CSIZE; //mask the character bits
parameters.c_cflag |= (CS8); //8 bit character size
parameters.c_oflag = 0;
parameters.c_lflag = 0;//ICANON=canonical mode
parameters.c_cc[VMIN] = 0; // 1 input byte is enough to return from read()
parameters.c_cc[VTIME] = 1;// Timer off
//set attribute immediately
int set = tcsetattr(fd, TCSANOW, ¶meters);
if(set == -1){
perror("Error setting attributes \n");
}
if (fd == -1){
perror(yungin);
return -1;
}
usleep(200000);
return fd;
}
/*stream desired data packets of 1 unsigned byte*/
int yungBot::stream(int packet){
unsigned char command[]={142,packet};
if(write(fd, command, sizeof(command))==-1){
perror("failed to retrieve data packet");
return -1;
}
unsigned char response[1];
if(read(fd,response,sizeof(response))!=1){
perror("failed to write data packet");
return -1;
}
//shift through the byte for individual bits
/*unsigned char bit = response[1];
for(int i = 0; i < CHAR_BIT; i++){
printf("%d", (bit>>i)&1);
}
*/
printf("%i",response[0]);
return response[0];
}
I'm honestly not sure what to expect. If I read something such as the charge state it seems to work returning a value of 0 when not charged and currently 3 when charged bc the battery is full. When returning something such as the bump and wheel drops sensors (which are sent as a single byte and have a range of 0-15, i'm not sure what to do. I get different values within that range when pressing different parts of the bumper etc..but 4 bits of the byte correspond to 4 different values and the other 4 are "reserved". How do I go about reading something like this? I've noticed for the wheel drop/bump sensors that i get certain values depending where I press/lift the robot, for example:
right bump=1
left bump=2
middle bump=3
right drop=4
left drop =8
both dropped = 12
Is this all i need?
Oh, this is pretty simple. You can read those bits with something like...
#define LEFT_BUMPER 1
#define RIGHT_BUMPER 2
#define REAR_BUMPER 4
#define FRONT_BUMPER 8
if(bumper_state & LEFT_BUMPER){ printf("left bumper actuated\n") }
if(bumper_state & RIGHT_BUMPER){ printf("right bumper actuated\n") }
The best data type to use us usually an unsigned type of the same size as the thing you're reading, in this case a uint8_t would be good.
Also, you don't need an array, you could read into a single byte if you wanted. It'll probably help avoid confusion later.