Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
10 years, 2 months ago.
Importing custom serial library from Arduino, getting a little confused
Hello all,
I come from Arduino-land where things are made just a little easier. I just got my first mbed platform, an LPC4088, to use a new brain for my hexapod robot. I'm a hack of a programmer at best and have hit a bit of a wall.
I'm trying to port over a "Commander" library that is used with the Arbotix Commander remote controller. The library's purpose is to open the serial connection to the Xbee and decipher the controller's messages.
Here are the original Arduino files:
Commander.h:
#ifndef Commander_h #define Commander_h /* bitmasks for buttons array */ #define BUT_R1 0x01 #define BUT_R2 0x02 #define BUT_R3 0x04 #define BUT_L4 0x08 #define BUT_L5 0x10 #define BUT_L6 0x20 #define BUT_RT 0x40 #define BUT_LT 0x80 /* the Commander will send out a frame at about 30hz, this class helps decipher the output. */ class Commander { public: Commander(); void begin(int baud); void UseSouthPaw(); // enable southpaw configuration int ReadMsgs(); // must be called regularly to clean out Serial buffer // joystick values are -125 to 125 signed char leftV; // vertical stick movement = forward speed signed char leftH; // horizontal stick movement = sideways or angular speed signed char rightV; // vertical stick movement = tilt signed char rightH; // horizontal stick movement = pan (when we run out of pan, turn body?) // 0-1023, use in extended mode int pan; int tilt; // buttons are 0 or 1 (PRESSED), and bitmapped unsigned char buttons; // unsigned char ext; // Extended function set // Hooks are used as callbacks for button presses -- NOT IMPLEMENT YET private: // internal variables used for reading messages unsigned char vals[7]; // temporary values, moved after we confirm checksum int index; // -1 = waiting for new packet int checksum; unsigned char status; }; #endif
Commander.cpp:
#include <Arduino.h> #include "Commander.h" /* Constructor */ Commander::Commander(){ index = -1; status = 0; } void Commander::begin(int baud){ Serial.begin(baud); } /* SouthPaw Support */ void Commander::UseSouthPaw(){ status |= 0x01; } /* process messages coming from Commander * format = 0xFF RIGHT_H RIGHT_V LEFT_H LEFT_V BUTTONS EXT CHECKSUM */ int Commander::ReadMsgs(){ while(Serial.available() > 0){ if(index == -1){ // looking for new packet if(Serial.read() == 0xff){ index = 0; checksum = 0; } }else if(index == 0){ vals[index] = (unsigned char) Serial.read(); if(vals[index] != 0xff){ checksum += (int) vals[index]; index++; } }else{ vals[index] = (unsigned char) Serial.read(); checksum += (int) vals[index]; index++; if(index == 7){ // packet complete if(checksum%256 != 255){ // packet error! index = -1; return 0; }else{ if((status&0x01) > 0){ // SouthPaw walkV = (signed char)( (int)vals[0]-128 ); walkH = (signed char)( (int)vals[1]-128 ); lookV = (signed char)( (int)vals[2]-128 ); lookH = (signed char)( (int)vals[3]-128 ); }else{ lookV = (signed char)( (int)vals[0]-128 ); lookH = (signed char)( (int)vals[1]-128 ); walkV = (signed char)( (int)vals[2]-128 ); walkH = (signed char)( (int)vals[3]-128 ); } pan = (vals[0]<<8) + vals[1]; tilt = (vals[2]<<8) + vals[3]; buttons = vals[4]; ext = vals[5]; } index = -1; Serial.flush(); return 1; } } } return 0; }
So normally in my main ardinuo program, i just do a:
Commander command = Commander();
And then a:
command.begin(38400); // setup serial for Xbee on USART2
In my setup() function.
The problem i'm having now with mbed, is that i'm using:
Serial xbee(p4_22, p4_23);
to create the xbee object of type Serial for the UART that the Xbee is on. However, if i do this in my main.cpp, "xbee" is undefined over in my Commander.cpp. Creating the object in Commander.cpp doesn't seem right, because that's a library i shouldn't need to touch.
I did try to have the commander object create the serial anyway like this:
void Commander::begin(int pTX, int pRX, int baud){ Serial xbee(pTX, pRX);// setup serial for Xbee on USART2 xbee.baud(baud); }
But that didn't work either.
What am i missing here? I'm getting lost in the Arudino to standard C++ translation.
Thanks a lot, Dan
2 Answers
10 years, 2 months ago.
You will have to modify the Commander class to make it compatible with the mbed Serial lib, There are several solutions, but in case you dont need the xbee Serial port anywhere else, the easiest fix is to declare the serial port as private inside Commander.
#ifndef Commander_h #define Commander_h //NEW #include "mbed.h" /* bitmasks for buttons array */ #define BUT_R1 0x01 #define BUT_R2 0x02 #define BUT_R3 0x04 #define BUT_L4 0x08 #define BUT_L5 0x10 #define BUT_L6 0x20 #define BUT_RT 0x40 #define BUT_LT 0x80 /* the Commander will send out a frame at about 30hz, this class helps decipher the output. */ class Commander { public: Commander(); void begin(int baud); void UseSouthPaw(); // enable southpaw configuration int ReadMsgs(); // must be called regularly to clean out Serial buffer // joystick values are -125 to 125 signed char leftV; // vertical stick movement = forward speed signed char leftH; // horizontal stick movement = sideways or angular speed signed char rightV; // vertical stick movement = tilt signed char rightH; // horizontal stick movement = pan (when we run out of pan, turn body?) // 0-1023, use in extended mode int pan; int tilt; // buttons are 0 or 1 (PRESSED), and bitmapped unsigned char buttons; // unsigned char ext; // Extended function set // Hooks are used as callbacks for button presses -- NOT IMPLEMENT YET private: // internal variables used for reading messages unsigned char vals[7]; // temporary values, moved after we confirm checksum int index; // -1 = waiting for new packet int checksum; unsigned char status; Serial xbee(p4_22, p4_23); // <== NEW }; #endif
You also need to change some calls to Serial port methods inside the Commander.cpp: baud, read
#include <Arduino.h> // <== probably get rid of that #include "Commander.h" //NEW #include "mbed.h" /* Constructor */ Commander::Commander(){ index = -1; status = 0; } void Commander::begin(int baudrate){ // Serial.begin(baud); xbee.baud(baudrate); //<== NEW } /* SouthPaw Support */ void Commander::UseSouthPaw(){ status |= 0x01; } /* process messages coming from Commander * format = 0xFF RIGHT_H RIGHT_V LEFT_H LEFT_V BUTTONS EXT CHECKSUM */ int Commander::ReadMsgs(){ // while(Serial.available() > 0){ while(xbee.readable() > 0){ ///<==NEW if(index == -1){ // looking for new packet // if(Serial.read() == 0xff){ if(xbee.getc() == 0xff){ // <==NEW index = 0; checksum = 0; } }else if(index == 0){ // vals[index] = (unsigned char) Serial.read(); vals[index] = (unsigned char) xbee.getc(); //<=== NEW if(vals[index] != 0xff){ checksum += (int) vals[index]; index++; } }else{ // vals[index] = (unsigned char) Serial.read(); vals[index] = (unsigned char) xbee.getc(); //<=== NEW checksum += (int) vals[index]; index++; if(index == 7){ // packet complete if(checksum%256 != 255){ // packet error! index = -1; return 0; }else{ if((status&0x01) > 0){ // SouthPaw walkV = (signed char)( (int)vals[0]-128 ); walkH = (signed char)( (int)vals[1]-128 ); lookV = (signed char)( (int)vals[2]-128 ); lookH = (signed char)( (int)vals[3]-128 ); }else{ lookV = (signed char)( (int)vals[0]-128 ); lookH = (signed char)( (int)vals[1]-128 ); walkV = (signed char)( (int)vals[2]-128 ); walkH = (signed char)( (int)vals[3]-128 ); } pan = (vals[0]<<8) + vals[1]; tilt = (vals[2]<<8) + vals[3]; buttons = vals[4]; ext = vals[5]; } index = -1; //// Serial.flush(); xbee.flush(); // <=== NEW return 1; } } } return 0; }
Note: I didnt compile any of this. There are probably some more errors due to Arduino/mbed differences
10 years, 2 months ago.
Awesome, thanks for taking the time to look this over. I was actually somewhat close to what you had, i just copied in the originals to start from square one. I hadn't thought to create the xbee Serial object in the Commander.h which makes sense in hindsight. It only needs to exist in Commander. I access the xbee through the Commander object which is created in main.cpp.
I do have a new issue though:
Error: Identifier "p4_22" is undefined in "Commander/Commander.h", Line: 65, Col: 17 Error: Identifier "p4_23" is undefined in "Commander/Commander.h", Line: 65, Col: 24
I am including "mbed.h" in the Commander.h file. I can't remember where i found those pin names, but somewhere deep in the guts of the mbed repository on this site under the LPC4088 stuff. Is there an easy place for me to find what handy pin definition/macros have been created for my board? I'm also not 100% sure those are the correct UART pins for the Xbee port, but i think so based on the "lpc4088_qsb_pinning.xlsx" file i found in the documentation.
I'm also getting a lot of:
Error: Expression must have class type in "Commander/Commander.cpp", Line: 39, Col: 11
referencing xbee.getc(), xbee.readable(), etc
Latest Commander.h:
#ifndef Commander_h #define Commander_h #include "mbed.h" /* bitmasks for buttons array */ #define BUT_R1 0x01 #define BUT_R2 0x02 #define BUT_R3 0x04 #define BUT_L4 0x08 #define BUT_L5 0x10 #define BUT_L6 0x20 #define BUT_RT 0x40 #define BUT_LT 0x80 /* the Commander will send out a frame at about 30hz, this class helps decipher the output. */ class Commander { public: Commander(); void begin(int baud); int ReadMsgs(); // must be called regularly to clean out Serial buffer // joystick values are -125 to 125 signed char leftV; // vertical stick movement = forward speed signed char leftH; // horizontal stick movement = sideways or angular speed signed char rightV; // vertical stick movement = tilt signed char rightH; // horizontal stick movement = pan (when we run out of pan, turn body?) // 0-1023, use in extended mode int pan; int tilt; // buttons are 0 or 1 (PRESSED), and bitmapped unsigned char buttons; // unsigned char ext; // Extended function set // Hooks are used as callbacks for button presses -- NOT IMPLEMENT YET private: // internal variables used for reading messages unsigned char vals[7]; // temporary values, moved after we confirm checksum int index; // -1 = waiting for new packet int checksum; unsigned char status; Serial xbee(p4_22, p4_23); // <== NEW }; #endif
Latest Commander.cpp:
#include "mbed.h" #include "Commander.h" #include "init.h" /* Constructor */ Commander::Commander(){ index = -1; status = 0; } void Commander::begin(int baud){ xbee.baud(baud); } /* process messages coming from Commander * format = 0xFF RIGHT_H RIGHT_V LEFT_H LEFT_V BUTTONS EXT CHECKSUM */ int Commander::ReadMsgs(){ while(xbee.readable() > 0){ if(index == -1){ // looking for new packet if(xbee.getc() == 0xff){ index = 0; checksum = 0; } }else if(index == 0){ vals[index] = (unsigned char) xbee.getc(); if(vals[index] != 0xff){ checksum += (int) vals[index]; index++; } }else{ vals[index] = (unsigned char) xbee.getc(); checksum += (int) vals[index]; index++; if(index == 7){ // packet complete if(checksum%256 != 255){ // packet error! index = -1; return 0; }else{ rightV = (signed char)( (int)vals[0]-128 ); rightH = (signed char)( (int)vals[1]-128 ); leftV = (signed char)( (int)vals[2]-128 ); leftH = (signed char)( (int)vals[3]-128 ); pan = (vals[0]<<8) + vals[1]; tilt = (vals[2]<<8) + vals[3]; buttons = vals[4]; ext = vals[5]; } index = -1; xbee.flush(); return 1; } } } return 0; }
FFS attempt 3 at an answer (no backspace this time, or pressing wrong button):
In your header file it shouldn't set the serial pins, so make it:
Serial xbee; // <== NEW
Now in your cpp constructor make it:
Commander::Commander() : xbee(P4_22, P4_23) {
Notice the capital P's, I assume here you got the numbers correct. Generally boards only have their external pins, and then you don't need to worry about those names, and you can simply use the names on the pinout picture (although I see the LPC4088 accidently has those with capitals, while they should be small ones). Here you got the complete list: http://mbed.org/users/mbed_official/code/mbed-src/file/5a6f638110fe/targets/hal/TARGET_NXP/TARGET_LPC408X/PinNames.h.
Finally you say Arduino is easier. However you just switched over, and didn't exactly start with blinking an LED ;). On some points Arduino has it easier, but at the same time mbed is easier on other points. When I do something with Arduino I really miss the Timer and Ticker libraries for example. So give it some time ;).
posted by 01 Feb 2014Thanks! This is really cleaning up. The only problem left is that there doesn't seem to be a Serial .flush() function. I searched a bit and people (at least a few years ago) agree that there is not and that you should write one like:
void flushSerialBuffer(void) { char char1 = 0; while (device.readable()) { char1 = device.getc(); } return; }
Is this the best way?
Thanks again!
Oh, i'm looking forward to getting back to a more standard programming environment. Arduino can hurt in that it hides a lot of things from you. My issues here are simply lack of solid programming foundation, but i have several books that i keep reading over and over. someday. Thanks again.
posted by 01 Feb 2014