Simple C or C++ example for Raspberry?

General discussion of using Roboclaw motor controllers
ecorrales
Posts: 33
Joined: Sun May 06, 2018 5:06 am
Simple C or C++ example for Raspberry?

Post by ecorrales »

Hi, sorry for having to post this but the search feature rejects some words as too common.

I am also heading in the direction of C / C++ to communicate with Roboclaw, after I get the python examples to work (or not).

I understand due to bottleneck being elsewhere, that there's no speed advantage over python.

However, there IS a speed advantage when doing other gpio with Raspberry for other sensors, interrupts, etc... and I really didn't want to have to mix C/C++ having to somehow call Python just to communicate with Roboclaw.

So looking for working examples for Raspberry from anyone, before having to dig into the Arduino stuff.

any pointers appreciated.

thanks
User avatar
Basicmicro Support
Posts: 1594
Joined: Thu Feb 26, 2015 9:45 pm
Re: Simple C or C++ example for Raspberry?

Post by Basicmicro Support »

We currently do not have a C/C++ RPi specific library. However the arduino library was written to be generic. It should take much effort to port that to RPi. Unfortunately we are not in a position to do that right now. At best its several months if not longer so if you need C/C++ I recommend taking what you need out of the arduino library and modifying it for the RPi.
ecorrales
Posts: 33
Joined: Sun May 06, 2018 5:06 am
Re: Simple C or C++ example for Raspberry?

Post by ecorrales »

Hi, I took a look at the arduino source you guys have. This disconnect between hardware and software.. geez.

Just looking at RoboClaw.h and RoboClaw.cpp.. they seem to reference what I assume to be arduino headers?

I thought, ok, I will try to find arduino.h. But no, now there's more. Streams.. and on and on.

I would think there's quite a few people doing this with Raspberry.

Between not getting python to work, and now all the unknowns with arduino ... I feel like I have an expensive piece of hardware I can't use.
ecorrales
Posts: 33
Joined: Sun May 06, 2018 5:06 am
Re: Simple C or C++ example for Raspberry?

Post by ecorrales »

i have had some success with an old tutorial that uses Boost C++ serial on Raspberry.

At least I can read from the Roboclaw. Now the long road to try to come up with CRC and all the commands, etc.. and try to steal what I can from the arduino files. things shouldn't be this hard.
User avatar
Basicmicro Support
Posts: 1594
Joined: Thu Feb 26, 2015 9:45 pm
Re: Simple C or C++ example for Raspberry?

Post by Basicmicro Support »

Your over thinking what is in the library.

The headers are required because we use a reference to the hardwareserial and softwareserial classes but you could remove the arduino headers and make your own hardwareserial class for your system. I dont recommend trying to write a softwareserial class(eg bit banged serial). So remove the arduino.h header and remove the sserial/#ifdef __AVR__ cide.

Then all your really need in your hardware serial class is:
1. a constructor to set which serial port to use on your hardware
2. a begin() function, sets the baudrate
3. a peek() function, reads the next byte from the receive buffer without taking it out of the buffer
4. a write() function, writes a byte to the serial port
5. an available() function, checks if a byte is available in the receive buffer
6. a read() function, reads the next byte in the receive buffer
7. a flush() function, reads any/all bytes in the receive buffer and throws them away.

That should be alot easier than trying to write your own library from scratch.
ecorrales
Posts: 33
Joined: Sun May 06, 2018 5:06 am
Re: Simple C or C++ example for Raspberry?

Post by ecorrales »

Hi, thank you that really helped.


Q: I noticed a micros() in the RoboClaw.cpp. Is that from the wiringPi library? If so, I didn't see an include for that.


Here's some of the top portion of RoboClaw.h:

//these two below I understand
#include <stdarg.h> // this is ok - I got it
#include <inttypes.h> // this is ok - I got it

Q:
// this one I don't know how to replace - are you saying i don't need it?
#include <Stream.h>

// this is the hardware serial class I need to implement.
#include <HardwareSerial.h>

Q:
// below, the RC_... and the GCC_... ... do I need this one portion? by the way, I was planning on using cmake.
#define _RC_VERSION 10 // software version of this library
#ifndef GCC_VERSION
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#endif

#define _SS_VERSION 16

class RoboClaw : public Stream {

// blah blah blah
ecorrales
Posts: 33
Joined: Sun May 06, 2018 5:06 am
Re: Simple C or C++ example for Raspberry?

Post by ecorrales »

Hi, I made some progress. I know you're busy..

I'm just trying to get the "ReadVersion()" to work.

(when I try to attach files via this forum, I keep getting invalid file extension. I've tried '.txt' and '.hpp'.

(unless i dump all the text in here - that's quite a bit)
ecorrales
Posts: 33
Joined: Sun May 06, 2018 5:06 am
Re: Simple C or C++ example for Raspberry?

Post by ecorrales »

" Resource temporarily unavailable"

Any tips appreciated. thank you.

i was able to upload to github.

here's the program output:

https://github.com/elicorrales/roboclaw ... boclaw.log

my current HardwareSerial:

(method names changed to not conflict with read() system call - didnt want to bother with namespaces for now)

https://github.com/elicorrales/roboclaw ... Serial.hpp
https://github.com/elicorrales/roboclaw ... Serial.cpp

(I made sure to also change RoboClaw.cpp accordingly)

current main.cpp:
https://github.com/elicorrales/roboclaw ... c/main.cpp

project root:
https://github.com/elicorrales/roboclaw
User avatar
Basicmicro Support
Posts: 1594
Joined: Thu Feb 26, 2015 9:45 pm
Re: Simple C or C++ example for Raspberry?

Post by Basicmicro Support »

1. I missed the micros() call when I scanned through the lirary. That is a command to get the time in microseconds. You should be able to replace with that something in a standard library.

2. You should be ablet o remove the Stream.h and ": public Stream" from the class definition. We subclassed Roboclaw to Stream to allow the arduino code to use some of the stream operators but I dont think we actually did anything with it in the end. ALl the functions used by the library itself are defined in the library except the serial port functions and micros() unless I missed anything else.

3. You can remove the GCC_VERSION and _SS_VESION definitions and references(eg library_version()).

4. We recently moved the forums to a new server. This may have broken something. Please email support@basicmicro.com. The webmaster will need to look at the setup in more depth.

5. This, "Error Reading Byte : /dev/ttyACM0 : errno is [ 11] : Resource temporarily unavailable" would indicate something else has control of the port exclusively. Make sure your code isn't trying to open the port more than once and make sure nothing else has opened the port.
ecorrales
Posts: 33
Joined: Sun May 06, 2018 5:06 am
Re: Simple C or C++ example for Raspberry?

Post by ecorrales »

Hi, thought I would try pasting here. (having trouble formatting it) (my apologies)

Test output:
============================================
HardwareSerial::HardwareSerial(/dev/ttyACM0)
_fd is [3]
RoboClaw::RoboClaw()
RoboClaw::begin()
HardwareSerial::hwSerialBegin(9600)
inSpeed : 13
outSpeed : 13
inSpeed : 13
outSpeed : 13
RoboClaw::ReadVersion()
RoboClaw::flush()
HardwareSerial::hwSerialFlush()
RoboClaw::crc_clear()
RoboClaw::write()
HardwareSerial::hwSerialWrite(80)
RoboClaw::crc_update()
RoboClaw::write()
HardwareSerial::hwSerialWrite(15)
RoboClaw::crc_update()
RoboClaw::ReadVersion():for loop(0)
RoboClaw::ReadVersion():gna read()...
RoboClaw::read()
RoboClaw::ReadVersion():read():data = ff
RoboClaw::crc_update()
RoboClaw::ReadVersion():for loop(1)
RoboClaw::ReadVersion():gna read()...
RoboClaw::read()
RoboClaw::ReadVersion():read():data = ff
RoboClaw::crc_update()
RoboClaw::ReadVersion():for loop(2)
RoboClaw::ReadVersion():gna read()...
RoboClaw::read()
RoboClaw::ReadVersion():read():data = ff






Portion of RoboClaw:
============================================

Code: Select all

bool RoboClaw::ReadVersion(uint8_t address,char *version){

	cout << "RoboClaw::ReadVersion()\n";

	uint8_t data;
	uint8_t trys=MAXRETRY;
	do{
		flush();

		data = 0;
		
		crc_clear();
		write(address);
		crc_update(address);
		write(GETVERSION);
		crc_update(GETVERSION);
	
		uint8_t i;
		for(i=0;i<48;i++){
			//cout << "\tRoboClaw::ReadVersion():for loop(" << i << ")..\n";
			printf("\tRoboClaw::ReadVersion():for loop(%d)\n",i);
			if(data!=-1){
				cout << "\t\tRoboClaw::ReadVersion():gna read()...\n";
				data=read(timeout);
				//cout << "\t\tRoboClaw::ReadVersion():read():data = " << hex << data << '\n';
				printf("\t\tRoboClaw::ReadVersion():read():data = %x\n", data);
				version[i] = data;
				crc_update(version[i]);
				if(version[i]==0){
					cout << "\t\t\tRoboClaw::ReadVersion():version[" << i << "] is 0 \n";
					uint16_t ccrc;
					data = read(timeout);
					if(data!=-1){
						cout << "\t\t\tRoboClaw::ReadVersion(): read next byte.. \n";
						ccrc = data << 8;
						data = read(timeout);
						if(data!=-1){
							cout << "\t\t\t\tRoboClaw::ReadVersion(): returning true or false.. \n";
							ccrc |= data;
							return crc_get()==ccrc;
						}
					}
					cout << "\t\t\tRoboClaw::ReadVersion():break after 2nd read..";
					break;
				}
			}
			else{
				printf("\t\tRoboClaw::ReadVersion():read():data was %x", data);
				break;
			}
		}
	}while(trys--);
	
	return false;
}



HardwareSerial:
============================================
void HardwareSerial::hwSerialHandleError(const string& message, int errnum) {

	ostringstream msgstream("");

	msgstream << message <<  " : " << _serialDeviceName << " : ";
       	if (errnum) {
			msgstream <<  "errno is [ " << errnum << "]  :  " << strerror(errnum);
		}
	msgstream << '\n';

	throw runtime_error(msgstream.str());
}

//constructor to set which serial port to use on your hardware
HardwareSerial::HardwareSerial(const string& serialDeviceName) {

	cout << "HardwareSerial::HardwareSerial(" << serialDeviceName << ")\n";

	_serialDeviceName = serialDeviceName;




	errno = 0;

	// I've tried all these ..

	//_fd = open(_serialDeviceName.c_str(),O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
	//_fd = open(_serialDeviceName.c_str(),O_RDWR | O_NOCTTY | O_NONBLOCK);
	//_fd = open(_serialDeviceName.c_str(),O_RDWR | O_NOCTTY | O_NDELAY);
	_fd = open(_serialDeviceName.c_str(),O_RDWR | O_NOCTTY );

	if (1 > _fd or 0 != errno) {

		hwSerialHandleError("Error opening",errno);
	}

	cout << "_fd is [" << _fd << "]\n";

	tcgetattr(_fd,&_settings);

	//exit(1);
}

//begin() function, sets the baudrate
void HardwareSerial::hwSerialBegin(long speed) {


	cout << "HardwareSerial::hwSerialBegin(" << speed << ")\n";

	speed_t inSpeed = cfgetispeed(&_settings);
	speed_t outSpeed = cfgetospeed(&_settings);

	cout << "inSpeed : " << inSpeed << '\n';
	cout << "outSpeed : " << outSpeed << '\n';

	switch (speed) {
		case 4800:
			cfsetispeed(&_settings,B4800);
			cfsetospeed(&_settings,B4800);
			break;
		case 9600:
			cfsetispeed(&_settings,B9600);
			cfsetospeed(&_settings,B9600);
			break;
		case 19200:
			cfsetispeed(&_settings,B19200);
			cfsetospeed(&_settings,B19200);
			break;
		case 38400:
			cfsetispeed(&_settings,B38400);
			cfsetospeed(&_settings,B38400);
			break;
		case 115200:
			cfsetispeed(&_settings,B115200);
			cfsetospeed(&_settings,B115200);
			break;
	}

	//cfsetispeed(&_settings,B38400);
	//cfsetospeed(&_settings,B38400);
	//cfsetispeed(&_settings,B115200);
	//cfsetospeed(&_settings,B115200);

	tcsetattr(_fd,TCSANOW,&_settings);

	delay(200);

	inSpeed = cfgetispeed(&_settings);
	outSpeed = cfgetospeed(&_settings);

	cout << "inSpeed : " << inSpeed << '\n';
	cout << "outSpeed : " << outSpeed << '\n';

	//string input;
	//cin >>  input;
}

//peek() function, reads the next byte from the receive buffer without taking it out of the buffer
int HardwareSerial::hwSerialPeek() {


	cout << "HardwareSerial::hwSerialPeek()\n";

	FILE* f = fdopen(_fd,"r+");
	int byte = getc(f);
	ungetc(byte,f);

	//string input;
	//cin >>  input;

	return byte;
}

//write() function, writes a byte to the serial port
size_t HardwareSerial::hwSerialWrite(uint8_t byte) {


	//cout << "HardwareSerial::hwSerialWrite(" << setbase(16) << byte << ")\n";
	printf("HardwareSerial::hwSerialWrite(%x)\n", byte);

	int bytesWritten = write(_fd,&byte,sizeof(byte));

	//string input;
	//cin >>  input;

	return bytesWritten;
}

//available() function, checks if a byte is available in the receive buffer
int HardwareSerial::hwSerialBytesAvailable() {


	//cout << "HardwareSerial::hwSerialBytesAvailable()\n";

	int bytes = 0;

	errno = 0;
	int bytesAvailable = ioctl(_fd,FIONREAD, &bytes);
	if (0 > bytesAvailable or 0 != errno) {

		hwSerialHandleError("Error Getting Bytes Available",errno);

	}


	//string input;
	//cin >>  input;

	//cout << "bytes available: ";
	//cout << bytesAvailable;
	//cout << '\n';
	return bytesAvailable;
}

//read() function, reads the next byte in the receive buffer
int HardwareSerial::hwSerialRead() {


	cout << "HardwareSerial::hwSerialRead()\n";

	int byte = 0;
	errno = 0;
	int bytesRead = read(_fd,&byte,sizeof(byte));

	if (0 > bytesRead or 0 != errno) {

		hwSerialHandleError("Error Reading Byte",errno);

	}


	cout << byte;
	return byte;
}

//flush() function, reads any/all bytes in the receive buffer and throws them away.
void HardwareSerial::hwSerialFlush() {


	cout << "HardwareSerial::hwSerialFlush()\n";

	while (hwSerialBytesAvailable() and hwSerialRead());
/*
	errno = 0;
	int rtn = tcflush(_fd,TCIOFLUSH);
	if (0 > rtn or 0 != errno) {
		hwSerialHandleError("Error Flushing",errno);
	}
	//delay(100);
	//string input;
	//cin >>  input;
*/
}

Post Reply