Tag: windows

(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

Bioloid Workbench Windows C++ examples

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

This post presents the Windows version of two examples/utilities built, this time, with MS Visual C++ and QT Creator, a great open source IDE and framework.

The first utility has a comand line user interface, being an easy example with only two DLL dependencies to the Visual C++ runtimes.

Screenshot-Terminal

The second example utility has a graphic user interface created with QT Creator.

QTWorkbench

Here you can find the bin executables and the projects with the source code.

This is the main function of the first example, the command line:

int _tmain(int argc, _TCHAR* argv[])
{
  cout << "AXControl_v2_VS_CPP test v0" << endl;

  bool quit=false;
  MyBasicSystem::BasicSystem mySystem;
  UI ui(mySystem);
  do
  {
    ui.showMenu();
    int selected=ui.selectOption();
    if (selected==ui.OptionQuit)
	quit=true;
    ui.executeSelectedOption(selected);
  }while (!quit);

  mySystem.dynamixelCommunication.close();

	return 0;
}

[Update] Yesterday I discovered a subtle but ugly bug. Can you spot it? Send an email to if you can’t find it but you want to know the danger bug.

It use two classes, the “BasicSystem” (in the library “VS_CPP_AXControl_lib.lib”) and a simple “UI” class that receives the input from the user and use the operations offered by the “BasicSystem” class.

For example:

int UI::getPosition()
{
  int position=0;

  do
  {
    cout << "Type a value between 0 and 1023 to set the AX-12 in that position" << endl;     cin>>position;

  }while(!validRange(position, 0, 1023));

  cout << "Position:" <<  position << endl;

  return position;
}
...
void UI::doSetPosition()
{
  int ax12Id=getId();
  int position=getPosition();

  mySystem.dynamixelCommunication.sendOrder(ax12Id, MyCommunications::GoalPosition,(short) position);
}

And all the cource code:

/*------------------------------------------------------------------------------*\
 * This source file is subject to the GPLv3 license that is bundled with this   *
 * package in the file COPYING.                                                 *
 * It is also available through the world-wide-web at this URL:                 *
 * http://www.gnu.org/licenses/gpl-3.0.txt                                      *
 * If you did not receive a copy of the license and are unable to obtain it     *
 * through the world-wide-web, please send an email to                          *
 * siempre.aprendiendo@gmail.com so we can send you a copy immediately.         *
 *                                                                              *
 * @category  Robotics                                                          *
 * @copyright Copyright (c) 2011 Jose Cortes (http://www.siempreaprendiendo.es) *
 * @license   http://www.gnu.org/licenses/gpl-3.0.txt GNU v3 Licence            *
 *                                                                              *
\*------------------------------------------------------------------------------*/

#include "stdafx.h"
#include
#include "BasicSystem.h"
#include "Util.h"

using namespace std;

class UI
{
public:
  static const int OptionQuit=8;

  UI(MyBasicSystem::BasicSystem& aMySystem) : mySystem(aMySystem) {}

  void showMenu();
  int selectOption();
  bool executeSelectedOption(int selected);
  void doBeep();

private:
  MyBasicSystem::BasicSystem mySystem;

  static const int OptionSetLEDOnOff=1;
  static const int OptionQueryAX12=2;
  static const int OptionMoveAX12=3;
  static const int OptionTorqueAX12=4;
  static const int OptionQuerySensor=5;
  static const int OptionShowMenu=6;
  static const int OptionBeep=7;

  static const int MinOption=OptionSetLEDOnOff;
  static const int MaxOption=OptionQuit;

  bool validRange(int value, int MinValue, int MaxValue);
  bool nonValidOption(int option);
  int getPosition();
  int getId();
  int getSensorPort();
  void doGetPosition();
  void doSetPosition();
  void doQuerySensor();
  void doSetLEDOnOff();
  void doSetTorqueOnOff();

};

void UI::showMenu()
{
  cout << "V02" << endl;

  cout << OptionSetLEDOnOff << ".- Toggle AX-12 LED" << endl;
  cout << OptionQueryAX12 << ".- Query AX-12" << endl;
  cout << OptionMoveAX12 << ".- Move AX-12" << endl;
  cout << OptionTorqueAX12 << ".- Torque AX-12" << endl;
  cout << OptionQuerySensor << ".- Query CM-510 sensor" << endl;
  cout << OptionShowMenu << ".- Show menu" << endl;
  cout << OptionBeep << ".- Beep" << endl;
  cout << OptionQuit << ".- Quit" << endl;
}

bool UI::nonValidOption(int option)
{
  return (optionMaxOption);
}

int UI::selectOption()
{
  int option=-1;

  while (nonValidOption(option))
  {
    cout << "Select option (" << MinOption << "-" << MaxOption << ")" << endl;     cin >> option;
    if (nonValidOption(option))
    {
      cout << endl;
      cout << endl;
      cout << "(" << option << ") is NOT a valid option" << endl;     }     }   return option; } bool UI::validRange(int value, int MinValue, int MaxValue) {		   return (value>=MinValue && value<=MaxValue);
}

int UI::getPosition()
{
  int position=0;

  do
  {
    cout << "Type a value between 0 and 1023 to set the AX-12 in that position" << endl;     cin>>position;

  }while(!validRange(position, 0, 1023));

  cout << "Position:" <<  position << endl;   return position; } int UI::getId() {   int ax12Id=1;        do    {	     puts ("Type the ID of the AX-12 to use, a value between 1 and 18, ");     cin >> ax12Id;

  }while(!validRange(ax12Id, 1, 18));

  cout << "AX12 Id:" << ax12Id << endl;   return ax12Id; } int UI::getSensorPort() {   int sensorPort=1;        do    {	     puts ("Type the sensor Port to read, a value between 1 and 6, ");     cin >> sensorPort;

  }while(!validRange(sensorPort, 1, 6));

  cout << "Sensor Port number:" << sensorPort << endl;

  return sensorPort;
}

void UI::doBeep()
{
  cout << "Beep" << endl;
  mySystem.dynamixelCommunication.sendOrder(100, AXS1_Buzzer, (byte) DO, (short) 500);
  Sleep (2);
  mySystem.dynamixelCommunication.sendOrder(200, MyCommunications::Beep, (byte) 5);
}

void UI::doGetPosition()
{
  int ax12Id=getId();

  int position = mySystem.dynamixelCommunication.readValue(ax12Id, MyCommunications::PresentPosition);
  cout << "the position is: [" << position << "] " << endl << endl << endl;
}

void UI::doSetPosition()
{
  int ax12Id=getId();
  int position=getPosition();

  mySystem.dynamixelCommunication.sendOrder(ax12Id, MyCommunications::GoalPosition,(short) position);
}

void UI::doQuerySensor()
{
  int sensorPort=getSensorPort();

  int value=mySystem.dynamixelCommunication.readSensorValue (200, ReadCM510SensorRaw, sensorPort);
  cout << "the sensor reads: [" << value << "] " << endl << endl << endl;
}

void UI::doSetLEDOnOff()
{
  byte lByte=0, hByte=0;
  int ledValue;

  int ax12Id=getId();

  ledValue=mySystem.dynamixelCommunication.readValue(ax12Id, MyCommunications::LED);
  Hex::toHexHLConversion(ledValue, hByte, lByte);

  bool onOff=false;
  if (lByte!=0)
    onOff=true;

  cout << "The LED is: [" << (onOff?"on":"off") << "], putting it: [" << (onOff?"Off":"on") << "] " << endl << endl << endl;
  mySystem.dynamixelCommunication.sendOrder(ax12Id, MyCommunications::LED, byte(onOff?0:1));
}

void UI::doSetTorqueOnOff()
{
  byte lByte=0, hByte=0;
  int ax12Id=getId();

  int torque=mySystem.dynamixelCommunication.readValue(ax12Id, MyCommunications::Torque);
  Hex::toHexHLConversion(torque, hByte, lByte);
  bool onOff=(lByte!=0?true:false);

  cout << "The Torque is: [" << (onOff?"on":"off") << "], putting it: [" << (onOff?"Off":"on") << "] " << endl << endl << endl;

  mySystem.dynamixelCommunication.sendOrder(ax12Id, MyCommunications::Torque,(byte) (onOff?0:1));
}

bool UI::executeSelectedOption(int option)
{
  bool isOk=true;
  cout << endl;
  cout << endl;

  cout << "Selected option: [" << option << "] " << endl;   switch(option)   {     case OptionSetLEDOnOff:          doSetLEDOnOff();           break;     case OptionQueryAX12:          doGetPosition();          break;     case OptionMoveAX12:          doSetPosition();           break;     case OptionTorqueAX12:          doSetTorqueOnOff();          break;     case OptionQuerySensor:          doQuerySensor();          break;     case OptionShowMenu: 	 showMenu(); 	 break;     case OptionBeep:          doBeep();          break;   }   return isOk; } 

The code for the Qt version is more complex, but as an example, the same operation that the example for the command line:

 int MainWindow::getAX12_1_Id() {     // Get the value from the edit control for the first AX-12     QString qStr=ui->SB_AX12_1_ID->text();
    int id=Util::convertToInt(qStr.toStdString());

    return id;
}
...
void MainWindow::on_B_AX12_1_SET_POS_clicked()
{
    int id = getAX12_1_Id();

    // Get the target position from the UI edit control as string and a convert it to int
    short position= ui->SB_AX12_1_POS->text().toInt();

    // Send the order to the AX-12 with the "id" to go to "position"
    pDynComm->sendOrder(id, MyCommunications::GoalPosition,position);
}

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: