Author Topic: Servo controller.  (Read 2486 times)

0 Members and 1 Guest are viewing this topic.

Offline Kristian

  • Newbie
  • Posts: 2
    • View Profile
Servo controller.
« on: January 26, 2019, 07:04:45 pm »
Hello


Is there a way I can controll my Servo-Controller (https://www.pololu.com/product/1352) using QB64?

I found this example on their page, can this be integrated into my QB64 program?

Code: QB64: [Select]
  1. /* MaestroSerialExampleCWindows:
  2.  *  Example program for sending and receiving bytes from the Maestro over a serial port
  3.  *  in C on Windows.
  4.  *
  5.  *  This program reads the position of channel 0.
  6.  *  If the position is less than 6000, it sets the target to 7000.
  7.  *  If the position is 6000 or more, it sets the target to 5000.
  8.  *  
  9.  *  If channel 0 is configured as a servo channel, the servo should move
  10.  *  when you run this program (except perhaps the first time you run it).
  11.  *  If channel 0 is configured as a digital output, the output should toggle
  12.  *  when you run this program.
  13.  *
  14.  *  All the Windows functions called by the program are documented on MSDN:
  15.  *  http://msdn.microsoft.com/
  16.  *
  17.  *  The error codes that this program may output are documented on MSDN:
  18.  *  http://msdn.microsoft.com/en-us/library/ms681381%28v=vs.85%29.aspx
  19.  *
  20.  *  The Maestro's serial commands are documented in the "Serial Interface"
  21.  *  section of the Maestro user's guide:
  22.  *  http://www.pololu.com/docs/0J40
  23.  *
  24.  *  For an advanced guide to serial port communication in Windows, see:
  25.  *  http://msdn.microsoft.com/en-us/library/ms810467
  26.  *
  27.  *  REQUIREMENT: The Maestro's Serial Mode must be set to "USB Dual Port"
  28.  *  or "USB Chained" for this program to work.
  29.  */
  30.  
  31. #include <stdio.h>
  32. #include <windows.h>
  33.  
  34. /** Opens a handle to a serial port in Windows using CreateFile.
  35.  * portName: The name of the port.
  36.  * baudRate: The baud rate in bits per second.
  37.  * Returns INVALID_HANDLE_VALUE if it fails.  Otherwise returns a handle to the port.
  38.  *   Examples: "COM4", "\\\\.\\USBSER000", "USB#VID_1FFB&PID_0089&MI_04#6&3ad40bf600004# */
  39. HANDLE openPort(const char * portName, unsigned int baudRate)
  40. {
  41.         HANDLE port;
  42.         DCB commState;
  43.         BOOL success;
  44.         COMMTIMEOUTS timeouts;
  45.  
  46.         /* Open the serial port. */
  47.         port = CreateFileA(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  48.         if (port == INVALID_HANDLE_VALUE)
  49.         {
  50.                 switch(GetLastError())
  51.                 {
  52.                 case ERROR_ACCESS_DENIED:      
  53.                         fprintf(stderr, "Error: Access denied.  Try closing all other programs that are using the device.\n");
  54.                         break;
  55.                 case ERROR_FILE_NOT_FOUND:
  56.                         fprintf(stderr, "Error: Serial port not found.  "
  57.                                 "Make sure that \"%s\" is the right port name.  "
  58.                                 "Try closing all programs using the device and unplugging the "
  59.                                 "device, or try rebooting.\n", portName);
  60.                         break;
  61.                 default:
  62.                         fprintf(stderr, "Error: Unable to open serial port.  Error code 0x%x.\n", GetLastError());
  63.                         break;
  64.                 }
  65.                 return INVALID_HANDLE_VALUE;
  66.         }
  67.  
  68.         /* Set the timeouts. */
  69.         success = GetCommTimeouts(port, &timeouts);
  70.         if (!success)
  71.         {
  72.                 fprintf(stderr, "Error: Unable to get comm timeouts.  Error code 0x%x.\n", GetLastError());
  73.                 CloseHandle(port);
  74.                 return INVALID_HANDLE_VALUE;
  75.         }
  76.         timeouts.ReadIntervalTimeout = 1000;
  77.         timeouts.ReadTotalTimeoutConstant = 1000;
  78.         timeouts.ReadTotalTimeoutMultiplier = 0;
  79.         timeouts.WriteTotalTimeoutConstant = 1000;
  80.         timeouts.WriteTotalTimeoutMultiplier = 0;
  81.         success = SetCommTimeouts(port, &timeouts);
  82.         if (!success)
  83.         {
  84.                 fprintf(stderr, "Error: Unable to set comm timeouts.  Error code 0x%x.\n", GetLastError());
  85.                 CloseHandle(port);
  86.                 return INVALID_HANDLE_VALUE;
  87.         }
  88.  
  89.         /* Set the baud rate. */
  90.         success = GetCommState(port, &commState);
  91.         if (!success)
  92.         {
  93.                 fprintf(stderr, "Error: Unable to get comm state.  Error code 0x%x.\n", GetLastError());
  94.                 CloseHandle(port);
  95.                 return INVALID_HANDLE_VALUE;
  96.         }
  97.         commState.BaudRate = baudRate;
  98.         success = SetCommState(port, &commState);
  99.         if (!success)
  100.         {
  101.                 fprintf(stderr, "Error: Unable to set comm state.  Error code 0x%x.\n", GetLastError());
  102.                 CloseHandle(port);
  103.                 return INVALID_HANDLE_VALUE;
  104.         }
  105.  
  106.         /* Flush out any bytes received from the device earlier. */
  107.         success = FlushFileBuffers(port);
  108.         if (!success)
  109.         {
  110.                 fprintf(stderr, "Error: Unable to flush port buffers.  Error code 0x%x.\n", GetLastError());
  111.                 CloseHandle(port);
  112.                 return INVALID_HANDLE_VALUE;
  113.         }
  114.  
  115.         return port;
  116. }
  117.  
  118. /** Implements the Maestro's Get Position serial command.
  119. * channel: Channel number from 0 to 23
  120. * position: A pointer to the returned position value (for a servo channel, the units are quarter-milliseconds)
  121. * Returns 1 on success, 0 on failure.
  122. * For more information on this command, see the "Serial Servo Commands"
  123. * section of the Maestro User's Guide: http://www.pololu.com/docs/0J40 */
  124. BOOL maestroGetPosition(HANDLE port, unsigned char channel, unsigned short * position)
  125. {
  126.         unsigned char command[2];
  127.         unsigned char response[2];
  128.         BOOL success;
  129.         DWORD bytesTransferred;
  130.  
  131.         // Compose the command.
  132.         command[0] = 0x90;
  133.         command[1] = channel;
  134.  
  135.         // Send the command to the device.
  136.         success = WriteFile(port, command, sizeof(command), &bytesTransferred, NULL);
  137.         if (!success)
  138.         {
  139.                 fprintf(stderr, "Error: Unable to write Get Position command to serial port.  Error code 0x%x.", GetLastError());
  140.                 return 0;
  141.         }
  142.         if (sizeof(command) != bytesTransferred)
  143.         {
  144.                 fprintf(stderr, "Error: Expected to write %d bytes but only wrote %d.", sizeof(command), bytesTransferred);
  145.                 return 0;
  146.         }
  147.  
  148.         // Read the response from the device.
  149.         success = ReadFile(port, response, sizeof(response), &bytesTransferred, NULL);
  150.         if (!success)
  151.         {
  152.                 fprintf(stderr, "Error: Unable to read Get Position response from serial port.  Error code 0x%x.", GetLastError());
  153.                 return 0;
  154.         }
  155.         if (sizeof(response) != bytesTransferred)
  156.         {
  157.                 fprintf(stderr, "Error: Expected to read %d bytes but only read %d (timeout). "
  158.                         "Make sure the Maestro's serial mode is USB Dual Port or USB Chained.", sizeof(command), bytesTransferred);
  159.                 return 0;
  160.         }
  161.  
  162.         // Convert the bytes received in to a position.
  163.         *position = response[0] + 256*response[1];
  164.  
  165.         return 1;
  166. }
  167.  
  168. /** Implements the Maestro's Set Target serial command.
  169.  * channel: Channel number from 0 to 23
  170.  * target: The target value (for a servo channel, the units are quarter-milliseconds)
  171.  * Returns 1 on success, 0 on failure.
  172.  * Fore more information on this command, see the "Serial Servo Commands"
  173.  * section of the Maestro User's Guide: http://www.pololu.com/docs/0J40 */
  174. BOOL maestroSetTarget(HANDLE port, unsigned char channel, unsigned short target)
  175. {
  176.         unsigned char command[4];
  177.         DWORD bytesTransferred;
  178.         BOOL success;
  179.  
  180.         // Compose the command.
  181.         command[0] = 0x84;
  182.         command[1] = channel;
  183.         command[2] = target & 0x7F;
  184.         command[3] = (target >> 7) & 0x7F;
  185.  
  186.         // Send the command to the device.
  187.         success = WriteFile(port, command, sizeof(command), &bytesTransferred, NULL);
  188.         if (!success)
  189.         {
  190.                 fprintf(stderr, "Error: Unable to write Set Target command to serial port.  Error code 0x%x.", GetLastError());
  191.                 return 0;
  192.         }
  193.         if (sizeof(command) != bytesTransferred)
  194.         {
  195.                 fprintf(stderr, "Error: Expected to write %d bytes but only wrote %d.", sizeof(command), bytesTransferred);
  196.                 return 0;
  197.         }
  198.  
  199.         return 1;
  200. }
  201.  
  202. /** This is the first function to run when the program starts. */
  203. int main(int argc, char * argv[])
  204. {
  205.         HANDLE port;
  206.         char * portName;
  207.         int baudRate;
  208.         BOOL success;
  209.         unsigned short target, position;
  210.  
  211.         /* portName should be the name of the Maestro's Command Port (e.g. "COM4")
  212.          * as shown in your computer's Device Manager.
  213.          * Alternatively you can use \\.\USBSER000 to specify the first virtual COM
  214.          * port that uses the usbser.sys driver.  This will usually be the Maestro's
  215.          * command port. */
  216.         portName = "\\\\.\\USBSER000";  // Each double slash in this source code represents one slash in the actual name.
  217.  
  218.         /* Choose the baud rate (bits per second).
  219.          * If the Maestro's serial mode is USB Dual Port, this number does not matter. */
  220.         baudRate = 9600;
  221.  
  222.         /* Open the Maestro's serial port. */
  223.         port = openPort(portName, baudRate);
  224.         if (port == INVALID_HANDLE_VALUE){ return -1; }
  225.  
  226.         /* Get the current position of channel 0. */
  227.         success = maestroGetPosition(port, 0, &position);
  228.         if (!success){ return -1; }
  229.         printf("Current position is %d.\n", position);
  230.  
  231.         /* Choose a new target based on the current position. */
  232.         target = (position < 6000) ? 7000 : 5000;
  233.         printf("Setting target to %d (%d us).\n", target, target/4);
  234.  
  235.         /* Set the target of channel 0. */
  236.         success = maestroSetTarget(port, 0, target);
  237.         if (!success){ return -1; }
  238.  
  239.         /* Close the serial port so other programs can use it.
  240.          * Alternatively, you can just terminate the process (return from main). */
  241.         CloseHandle(port);
  242.  
  243.         return 0;
  244. }
  245.  

Offline Kristian

  • Newbie
  • Posts: 2
    • View Profile
Re: Servo controller.
« Reply #1 on: January 26, 2019, 11:16:28 pm »
Looks like i figured it out myself.
Sorry for posting before reading the manual...

Second byte is Servo channel (0-11) and third byte is position (0-255)



Code: QB64: [Select]
  1. DIM SHARED Byte AS STRING * 4
  2.  
  3. OPEN "COM3:9600,N,8,1,BIN,CS0,DS0" FOR RANDOM AS #1
  4.  
  5. Byte = CHR$(255) + CHR$(2) + CHR$(127)
  6.  
  7. PUT #1, , Byte
  8.  
  9.  

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Servo controller.
« Reply #2 on: January 27, 2019, 08:22:09 am »
Don't apologize at all... The fact that you're using QB64 for such a thing is great. Tell us more about it!
You're not done when it works, you're done when it's right.

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Servo controller.
« Reply #3 on: January 28, 2019, 11:10:33 am »
Use old Fischertechnik interfaces for my robotics work.
though the prices on that site are not that bad. will have to look it over later.
Granted after becoming radioactive I only have a half-life!