Tag: serial port

CM-510 firmware for using as multiple sensor item updated

CM-510 firmware and post updated

 

 

(I) Programming serial port communications

This entry is part 1 of 2 in the series Serial communications

250px-Serial_portConnections and operating system symbolic names

A serial port is a communication physical interface through which information  transfers in or out one bit at a time (in contrast to a parallel port) being, more or less compliant, with the RS-232 standard.

But serial port communications aren’t only useful for wired DE-9 connectors. it also allows us to use it with USB (ftdi), Bluetooth (serial profile) and Zigbee using virtual serial ports.

·

Types-usbSerial and virtual serial ports appear as  COMx in Windows operating systems (COM1, COM2, …) andin UNIX/Linux as ttySx or ttyUSBx or even ttyACMx (ttyS0, ttyS1, ttyUSB0, ttyUSB1, ttyACM0, ttyACM1,…).

For programming purposes we usually want to communicate computers with others computers, microcontrollers or other devices like GPS, LED or LCD displays.

·

Serial port programming in C/C++, Windows and Linux

Using the serial port is a lot  easier, but sometimes tricky. The basic commands are to open a connection, read and write over this connection and, finally, tom close it, better if using the C++ RAII idiom.

winWindows commands:
Here you can find a complete C++ for Windows example.

With these next two definitions (among others needed):

HANDLE
serialPortHandle
wchar_t* device

serialPortHandle = CreateFile(device, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, NULL, NULL);
if (serialPortHandle!=INVALID_HANDLE_VALUE)
ReadFile(serialPortHandle, buffer, len, &read_nbr, NULL);

if (serialPortHandle!=INVALID_HANDLE_VALUE)
WriteFile(serialPortHandle, buffer, len, &result, NULL);
CloseHandle(serialPortHandle);

linuxUnix/Linux commands:
Here you can find a complete C++ for Linux example.

With these two definitions:

·
int fileDescriptor;
char *device;
·
·
  • Opening a connection, open
struct termios terminalAttributes;

fileDescriptor = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_FSYNC );

// clear terminalAttributes data
memset(&terminalAttributes, 0, sizeof(struct termios));

terminalAttributes.c_cflag = B57600 | CS8 | CLOCAL | CREAD; 
terminalAttributes.c_iflag = IGNPAR |  ONLCR;
terminalAttributes.c_oflag = OPOST;
terminalAttributes.c_cc[VTIME] = 0;
terminalAttributes.c_cc[VMIN] = 1;

tcsetattr(fileDescriptor, TCSANOW, &terminalAttributes);
int n=read(fileDescriptor, buffer, len);

int n=write(fileDescriptor, buffer, len);
  • Closing the connection, close
close(fileDescriptor);

More information:

https://en.wikipedia.org/wiki/Serial_communication
http://en.wikipedia.org/wiki/Serial_port

http://www.lvr.com/serport.htm
http://digilander.libero.it/robang/rubrica/serial.htm
http://en.wikibooks.org/wiki/Serial_Programming

http://msdn.microsoft.com/en-us/library/ff802693.aspx

Workshop: USB, serial and remote communications with C#

This entry is part 2 of 6 in the series Bioloid Workshop

[Previous post: Workshop: Dynamixel communications with C#]

Bioloid SerialPort2Dynamixel C#

Bioloid SerialPort2Dynamixel C#

SerialPort2Dynamixel

Encapsulating  the SerialPort .Net class offers an easy way to use the serial port and receive Dynamixel Zig messages with the Dynamixel protocol.

.

.

Collaborator classes:

Bioloid SerialPort2Dynamixel C# Collaborators

Bioloid SerialPort2Dynamixel C# Collaborators

– The SerialPort .Net class.

RCDataReader class, which unpack the Dynamixel Zigbee sequence offering the clean data received.

Operations:

The public interface that others classes will use offers principally these operations:

public void setRemoteControlMode(bool on), which sets on or off the reception of data


public void setRemoteControlMode(bool on)
{
if (on)
setReceiveDataMethod(rdDataReader.rawRemoteDataReceived);
else
setReceiveDataMethod(null);
}

public void setReceiveDataMethod(remoteControlDataReceived rcDataReceived), that sets the method that will be called when serial port data is received.

And some basics serial port data operations:

Raspberry Pi - USB2Dynamixel - CM510

Raspberry Pi – USB2Dynamixel – CM510

public bool open(String com, int speed), to open the serial port which name is in the com parameter. Wireless communications and USB ports, as used by Zig or USB2Dynaniel, are also serial ports  (COM1, COM2, … or /ttyUSB0, ttyUSB1).

public void close(), it will do nothing if the port is already closed.

public byte[] query(byte[] buffer, int pos, int wait), send (write) a query and gets (read) the result.

public void rawWrite(byte[] buffer, int pos), well… it will write whatever contains the buffer in the first pos positions

public byte[] rawRead() , read and returns the data received.

Notes:

To avoid concurrency problems all the operations that use the Dynamixel bus are protected with a Mutex object that avoids that two or more concurrent objects use SerialPort2Dynamixel simultaneously entering the same operation or using the same resources, like variables, objects or the Dynamixel bus.

Xevel USB2AX

Xevel USB2AX

USB2AX over USB2DYNAMIXEL

USB2AX over USB2DYNAMIXEL

RCDataReader

Bioloid RCDataReader C#

Bioloid RCDataReader C#

Remote communications

RemoteCommunications

Its responsability is to receive the Dynamixel Zig packets and extract the data.

Collaborator class:

– The ZigSequence enum, with the Dynamixels protocols data sections

RC-100 packet

RC-100 packet

Operations:

Robotis RC-100 remote controller values

Robotis RC-100 remote controller values

public void rawRemoteDataReceived(byte[] rcData), receives the Zigbee data.

public int getValue(), returns the last value received

Workshop: Dynamixel communications with C#

[Next post: Workshop: USB, serial and remote communications with C#]

As I wrote in the previous post, I am not using Robotis Dynamixel SDK USB2Dynamixelbecause it only works with the  USB2Dynamixel, and I need that it also should work with the serial port and with zigbee or bluetooth (really all 4 use the serial connection). Also I want to query sensors connected to the CM-510.

Zigbee device

Zigbee

Using the CM-510 and computer serial port (or USB to serial) connection you are free to use any wired or wireless device. Really there are a lot of possibilities.

We will start connecting to the Dynamixel bus and sending commands and queries. These classes do the work:

DynamixelCommunication

SerialPort2Dynamixel

RCDataReader

But there are other classes that offer to them some additional services, like Configuration, Utils, Hex and several enumeration types.

I will use the Class-Responsability-Collaboration template to present the classes.

DynamixelCommunicationBioloid DynamixelCommunication class C#

The main responsibility of this class is sending commands and queries to any Dynamixel device, including the sensors, sound and other capabilities of the CM-510 controller.

Collaborator classes:

– SerialPort2Dynamixel,  that offers operations to use the serial port encapsulating .Net SerialPort class

– Three enums for easy use and avoid errors, using an specific type is safer that using simple integers.

    public enum AXS1_IRSensor { Left, Center, Right, None };
    public enum AXS1_SoundNote { LA, LA_, SI, DO, DO_, RE }; //Only the first six 
    public enum DynamixelFunction, with all the Dynamixel protocols codes and some that I added for the CM-510.

Configuration class, that reads a file where are stored basic configuration parameters. like:

        private static string ParameterSerialPortName
        private static string ParameterSerialPortBaudRate
        private static string ParameterWaitTime_ms
        private static string ParameterWaitTimeForSensors_ms

Bioloid communications C#

Operations:

The public operations are the interface that other classes will use, like:

short readValue(int id, DynamixelFunction address), reads the value of any AX-12 parameter (or other Dynamixels)

bool sendOrder(int id, DynamixelFunction address, int value), send commands, like position, speed or torque.

And the private that do internal work supporting the public interface, like:

–  static int getReadWordCommand(byte[] buffer, byte id, DynamixelFunction address), create the Dynamixel hexadecimal sequence (FF FF 0F 05 03 1E CB 01 FE)

static short getQueryResult(byte[] res), once the query or command is sent it gets the result.

Let’s see readValue and two other called functions:


public short readValue(int id, DynamixelFunction address)
{
mutex.WaitOne();
short position = -1;

try
{
int size = getReadWordCommand(buffer, (byte)id, address);
byte[] res = serialPort.query(buffer, size, WaitTimeReadSensor);

position = getQueryResult(res);
if (position < 0)
Debug.show("DynamixelCommunication.readValue", position);

}
catch (Exception e)
{
Debug.show("DynamixelCommunication.readValue", e.Message);
}

mutex.ReleaseMutex();

return position;
}

private static int getReadWordCommand(byte[] buffer, byte id, DynamixelFunction address)
{
//OXFF 0XFF ID LENGTH INSTRUCTION PARAMETER1 …PARAMETER N CHECK SUM
int pos = 0;

buffer[pos++] = 0xff;
buffer[pos++] = 0xff;
buffer[pos++] = id;

// bodyLength = 4
buffer[pos++] = 4;

//the instruction, read => 2
buffer[pos++] = 2;

// AX12 register
buffer[pos++] = (byte)address;

//bytes to read
buffer[pos++] = 2;

byte checksum = Utils.checkSumatory(buffer, pos);
buffer[pos++] = checksum;

return pos;
}

private static short getQueryResult(byte[] res)
{
short value = -1;

if (res != null)
{
int length = res.Length;
if (res != null && length > 5 && res[4] == 0)
{
byte l = 0;
byte h = res[5];
if (length > 6)
{
l = res[6];
}

value = Hex.fromHexHLConversionToShort(h, l);
}
}
return value;
}

Notes:

To avoid concurrency problems all the operations that use the Dynamixel bus are protected with a Mutex object that avoids that two or more concurrent objects use DynamixelCommunication simultaneously entering the same operation or using the same resources, like variables, objects or the Dynamixel bus.

All the operations use the same buffer, but being protected with the Mutex object I think that is the better option, although in a previous version I used a very different approach where there were AX12 objects with their own buffer.

[Next post: Workshop: USB, serial and remote communications with C#]

Simple C++ class example using serial port, USB, wireless…

This entry is part 2 of 2 in the series Serial communications

This post is part of the Practical C++ programming tutorial for Bioloid

Here you can find a post serie about using serial port communications with C/C++ and C#, for Windows, Linux and microcontrollers.
This code is for Windows and Visual Studio and can be used for serial cable communications, USB2Dynamixel and indeed Zigbee:

Header:

class SerialPort {
private:
HANDLE serialPortHandle;

public:
SerialPort();
~SerialPort();

int connect ();
int connect (wchar_t *device);
//int connect (char *deviceName, int baudRate, SerialParity parity);
void disconnect(void);

int sendArray(unsigned char *buffer, int len);
int getArray (unsigned char *buffer, int len);

void clear();
};

Body:


SerialPort::SerialPort() {
serialPortHandle = INVALID_HANDLE_VALUE;
}

SerialPort::~SerialPort() {
if (serialPortHandle!=INVALID_HANDLE_VALUE)
CloseHandle(serialPortHandle);

serialPortHandle = INVALID_HANDLE_VALUE;
}

int SerialPort::connect() {
return connect(L"COM1");
}

int SerialPort::connect( wchar_t* device) {
int error=0;
DCB dcb;

memset(&dcb,0,sizeof(dcb));

dcb.DCBlength = sizeof(dcb);

dcb.BaudRate = 57600;
dcb.Parity = NOPARITY;
dcb.fParity = 0;
dcb.StopBits = ONESTOPBIT;
dcb.ByteSize = 8;

serialPortHandle = CreateFile(device, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, NULL, NULL);

if (serialPortHandle != INVALID_HANDLE_VALUE) {
if(!SetCommState(serialPortHandle,&dcb))
error=2;
}
else {
error=1;
}

if (error!=0) {
disconnect();
}
else {
clear();
}

return error;
}

void SerialPort::disconnect(void) {
CloseHandle(serialPortHandle);
serialPortHandle = INVALID_HANDLE_VALUE;

//printf("Port 1 has been CLOSED and %d is the file descriptionn", fileDescriptor);
}

int SerialPort::sendArray(unsigned char *buffer, int len) {
unsigned long result;

if (serialPortHandle!=INVALID_HANDLE_VALUE)
WriteFile(serialPortHandle, buffer, len, &result, NULL);

return result;
}

int SerialPort::getArray (unsigned char *buffer, int len) {
unsigned long read_nbr;

read_nbr = 0;
if (serialPortHandle!=INVALID_HANDLE_VALUE)
{
ReadFile(serialPortHandle, buffer, len, &read_nbr, NULL);
}

return((int) read_nbr);
}

void SerialPort::clear() {
PurgeComm (serialPortHandle, PURGE_RXCLEAR | PURGE_TXCLEAR);
}
%d bloggers like this: