<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.satnogs.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=G7kse1</id>
	<title>SatNOGS Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.satnogs.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=G7kse1"/>
	<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/Special:Contributions/G7kse1"/>
	<updated>2026-04-07T05:54:34Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.32.0</generator>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=SatNOGS_Arduino_Uno/CNC_Shield_Based_Rotator_Controller&amp;diff=2663</id>
		<title>SatNOGS Arduino Uno/CNC Shield Based Rotator Controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=SatNOGS_Arduino_Uno/CNC_Shield_Based_Rotator_Controller&amp;diff=2663"/>
		<updated>2019-03-12T18:06:39Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:SatNOGS Arduino Uno CNC Shield Based Rotator Controller}}&lt;br /&gt;
&lt;br /&gt;
=== Controlling the rotator as a stand alone system using GPredict ===&lt;br /&gt;
The SatNOGS rotator is primarily designed to be used as a system component that is part of a SatNOGS ground station. There may be occasion when it is desirable to have a stand alone ground station that is removed from the SatNOGS network. This can be done using existing equipment but can also be simplified using off the shelf components.&lt;br /&gt;
&lt;br /&gt;
The following information is to connect your Rotator controller DIRECTLY TO A PC. If you'd like to still use it with the Raspberry Pi then you must keep the RS485 protocol in place.&lt;br /&gt;
&lt;br /&gt;
We will need slightly different hardware and modified software to achieve this, the main changes will be to remove the RS485 and watchdog parts of the firmware. We will be using the following items:&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
# SatNOGS Rotator V3.1 hardware&lt;br /&gt;
# Arduino Uno R3&lt;br /&gt;
# CNC Shield V3 with A4988 drivers&lt;br /&gt;
# NEMA 17 Stepper Motors&lt;br /&gt;
# 2x microswitches&lt;br /&gt;
# Suitable 12v power supply (The shield will accept between 12v and 36v)&lt;br /&gt;
# Cables to connect the Arduino to the PC&lt;br /&gt;
&lt;br /&gt;
[[File:Arduino CNC Shield.png|centre|Bare CNC Shield]]&lt;br /&gt;
&lt;br /&gt;
[[File:A4988 Drivers.png|centre]]&lt;br /&gt;
&lt;br /&gt;
==== Software ====&lt;br /&gt;
For the purposes of this article we will be using Windows software. The same result can be achieved with Linux or Mac OS but for clarity these options have been ignored for the time being. We will need:&lt;br /&gt;
# A copy of the Arduino IDE (version 1.8.5 has been used as part of this tutorial)&lt;br /&gt;
# GPredict&lt;br /&gt;
# Hamlib&lt;br /&gt;
# A text editor such as Notepad++ for a small script&lt;br /&gt;
# [https://gitlab.com/Quartapound/satnogs-rotator-firmware You can find the edited sketch and libraries in the following Fork :  https://gitlab.com/Quartapound/satnogs-rotator-firmware]&lt;br /&gt;
&lt;br /&gt;
=== Method ===&lt;br /&gt;
&lt;br /&gt;
==== Hardware setup ====&lt;br /&gt;
We will not be using the custom SatNOGS PCB. Instead this set up uses an Arduino Uno and CNC motor shield. There is very little assembly required but depending on how and where you buy from will depend on the amount of assembly is required. Typically the Arduino will need no assembly, The motor shield will need two A4988 drivers (these can come as part of the package). These are used in the X &amp;amp; Y headers as per the photograph below. The drivers fit into the female headers, note that there are jumper headers below these drivers that are used for stepping control. We will also be attaching the stepper motor cables to the male headers to the left of the driver boards.&lt;br /&gt;
[[File:Assembled CNC Shield.png|centre]]&lt;br /&gt;
&lt;br /&gt;
Pinout of the 4 headers is as follows starting from the top (4 vertical pins to the left of the A4988 motor driver board, marked X,Y &amp;amp; Z)&lt;br /&gt;
&lt;br /&gt;
Pin 1 - A&lt;br /&gt;
&lt;br /&gt;
Pin 2 - A+&lt;br /&gt;
&lt;br /&gt;
Pin 3 - B&lt;br /&gt;
&lt;br /&gt;
Pin 4 - B+&lt;br /&gt;
&lt;br /&gt;
This follows a convention so most steppers should plug directly into the header without any changes, but be aware that this is not always the case and that there may be some cases where pins are incorrectly noted and the steppers will drive in the opposite direction.&lt;br /&gt;
&lt;br /&gt;
The setup is very basic but be careful not to bend pins as this can be easily done if too much pressure is put on the boards when things are no aligned. They aren't always perfect!&lt;br /&gt;
&lt;br /&gt;
In the end you should have:&lt;br /&gt;
* Azimuth Stepper Driver/motor connected to Y port on CNC Board&lt;br /&gt;
* Elevation Stepper Driver/motor connected to X port on CNC Board&lt;br /&gt;
* The End stop switch for elevation is connected to the X end stop on the CNC board (+ or -)&lt;br /&gt;
* The End stop switch for azimuth is connected to the Y end stop on the CNC board (+ or -)&lt;br /&gt;
&lt;br /&gt;
==== Software setup ====&lt;br /&gt;
&lt;br /&gt;
===== Code modifications =====&lt;br /&gt;
For the time being there is no fork of the firmware in the repositories. This may change in the future but for the time being a small series of changes are required to achieve results. We will need to modify two elements of the firmware, easycomm.h and rotator_pins.h. These changes are necessary to stop their being conflicts with the communication between boards and PC as well as re-assigning pins to match the CNC shield. We'll modify the rotator_pins.h first. Note the use of comments (//) to remove lines of code. We have also changed pin designation to match the shield.&lt;br /&gt;
&lt;br /&gt;
    /*!&lt;br /&gt;
    * @file rotator_pins.h&lt;br /&gt;
    *&lt;br /&gt;
    * It is a header file for pin mapping.&lt;br /&gt;
    *&lt;br /&gt;
    * Licensed under the GPLv3&lt;br /&gt;
    *&lt;br /&gt;
    */&lt;br /&gt;
&lt;br /&gt;
    #ifndef ROTATOR_PINS_H_&lt;br /&gt;
    #define ROTATOR_PINS_H_&lt;br /&gt;
&lt;br /&gt;
    //#define M1IN1 10 ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1IN1 2 ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1IN2 5  ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1SF  7  ///&amp;lt; Motor 1 digital input, status flag for DC Motor Drivers&lt;br /&gt;
    #define M1FB  A1 ///&amp;lt; Motor 1 analog input, current/load feedback for DC Motor Drivers&lt;br /&gt;
&lt;br /&gt;
    #define M2IN1 3 ///&amp;lt; Motor 2 PWM pin&lt;br /&gt;
    #define M2IN2 6  ///&amp;lt; Motor 2 PWM pin&lt;br /&gt;
    #define M2SF  7 ///&amp;lt; Motor 2 digital input, status flag for DC Motor Drivers&lt;br /&gt;
    #define M2FB  A0 ///&amp;lt; Motor 2 analog input, current/load feedback for DC Motor Drivers&lt;br /&gt;
&lt;br /&gt;
    #define MOTOR_EN 8 ///&amp;lt; Digital output, to enable the motors&lt;br /&gt;
&lt;br /&gt;
    #define SW1 11 ///&amp;lt; Digital input, to read the status of end-stop for motor 1&lt;br /&gt;
    #define SW2 9 ///&amp;lt; Digital input, to read the status of end-stop for motor 2&lt;br /&gt;
&lt;br /&gt;
    #define RS485_DIR 2 ///&amp;lt; Digital output, to set the direction of RS485 communication&lt;br /&gt;
&lt;br /&gt;
    #define SDA_PIN 3 ///&amp;lt; I2C data pin&lt;br /&gt;
    #define SCL_PIN 4 ///&amp;lt; I2C clock pin&lt;br /&gt;
&lt;br /&gt;
    #define PIN12 12 ///&amp;lt; General purpose I/O pin&lt;br /&gt;
    #define PIN13 13 ///&amp;lt; General purpose I/O pin&lt;br /&gt;
    #define A2    A2 ///&amp;lt; General purpose I/O &amp;amp; analog pin&lt;br /&gt;
    #define A3    A3 ///&amp;lt; General purpose I/O &amp;amp; analog pin&lt;br /&gt;
&lt;br /&gt;
    #endif /* ROTATOR_PINS_H_ */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The next code edit will remove both the RS485 and watchdog elements from the easycomm.h code. This will allow the PC to talk directly to the Arduino and as such bypass the RPi. The edited code is below, note again the use of comments (//) to remove the lines&lt;br /&gt;
    /*!&lt;br /&gt;
    * @file easycomm.h&lt;br /&gt;
    *&lt;br /&gt;
    * It is a driver for easycomm 3 protocol as referred, in Hamlib.&lt;br /&gt;
    *&lt;br /&gt;
    * Licensed under the GPLv3&lt;br /&gt;
    *&lt;br /&gt;
    */&lt;br /&gt;
&lt;br /&gt;
    #ifndef LIBRARIES_EASYCOMM_H_&lt;br /&gt;
    #define LIBRARIES_EASYCOMM_H_&lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;Arduino.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;WString.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;avr/wdt.h&amp;gt;&lt;br /&gt;
    //#include &amp;quot;rs485.h&amp;quot;&lt;br /&gt;
    #include &amp;quot;rotator_pins.h&amp;quot;&lt;br /&gt;
    #include &amp;quot;globals.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    #define RS485_TX_TIME 9     ///&amp;lt; Delay &amp;quot;t&amp;quot;ms to write in serial for RS485 implementation&lt;br /&gt;
    #define BUFFER_SIZE   256   ///&amp;lt; Set the size of serial buffer&lt;br /&gt;
    #define BAUDRATE      19200 ///&amp;lt; Set the Baudrate of easycomm 3 protocol&lt;br /&gt;
&lt;br /&gt;
    //rs485 rs485(RS485_DIR, RS485_TX_TIME);&lt;br /&gt;
&lt;br /&gt;
    /**************************************************************************/&lt;br /&gt;
    /*!&lt;br /&gt;
        @brief    Class that functions for easycomm 3 implementation&lt;br /&gt;
    */&lt;br /&gt;
    /**************************************************************************/&lt;br /&gt;
    class easycomm {&lt;br /&gt;
    public:&lt;br /&gt;
&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        /*!&lt;br /&gt;
            @brief    Initialize the RS485 bus&lt;br /&gt;
        */&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        void easycomm_init() {&lt;br /&gt;
           // rs485.begin(BAUDRATE);&lt;br /&gt;
    	    Serial.begin(9600);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        /*!&lt;br /&gt;
            @brief    Get the commands from RS485 and response to the client&lt;br /&gt;
        */&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        void easycomm_proc() {&lt;br /&gt;
            char buffer[BUFFER_SIZE];&lt;br /&gt;
            char incomingByte;&lt;br /&gt;
            char *Data = buffer;&lt;br /&gt;
            char *rawData;&lt;br /&gt;
            static uint16_t BufferCnt = 0;&lt;br /&gt;
            char data[100];&lt;br /&gt;
            String str1, str2, str3, str4, str5, str6;&lt;br /&gt;
&lt;br /&gt;
            // Read from serial&lt;br /&gt;
            while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
                incomingByte = Serial.read();&lt;br /&gt;
&lt;br /&gt;
                // Read new data, '\n' means new pacakage&lt;br /&gt;
                if (incomingByte == '\n' || incomingByte == '\r') {&lt;br /&gt;
                    buffer[BufferCnt] = 0;&lt;br /&gt;
                    if (buffer[0] == 'A' &amp;amp;&amp;amp; buffer[1] == 'Z') {&lt;br /&gt;
                        if (buffer[2] == ' ' &amp;amp;&amp;amp; buffer[3] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                            buffer[4] == 'L') {&lt;br /&gt;
                            // Send current absolute position in deg&lt;br /&gt;
                            str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.input, 1);&lt;br /&gt;
                            str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                            str4 = String(control_el.input, 1);&lt;br /&gt;
                            str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            // Get the absolute position in deg for azimuth&lt;br /&gt;
                            rotator.control_mode = position;&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 2, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.setpoint = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                            // Get the absolute position in deg for elevation&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            if (rawData[0] == 'E' &amp;amp;&amp;amp; rawData[1] == 'L') {&lt;br /&gt;
                                strncpy(data, rawData + 2, 10);&lt;br /&gt;
                                if (isNumber(data)) {&lt;br /&gt;
                                    control_el.setpoint = atof(data);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'E' &amp;amp;&amp;amp; buffer[1] == 'L') {&lt;br /&gt;
                            // Get the absolute position in deg for elevation&lt;br /&gt;
                            rotator.control_mode = position;&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            if (rawData[0] == 'E' &amp;amp;&amp;amp; rawData[1] == 'L') {&lt;br /&gt;
                                strncpy(data, rawData + 2, 10);&lt;br /&gt;
                                if (isNumber(data)) {&lt;br /&gt;
                                    control_el.setpoint = atof(data);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'U') {&lt;br /&gt;
                        // Elevation increase speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_el.setpoint_speed = atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'D') {&lt;br /&gt;
                        // Elevation decrease speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_el.setpoint_speed = - atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'L') {&lt;br /&gt;
                        // Azimuth increase speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_az.setpoint_speed = atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'R') {&lt;br /&gt;
                        // Azimuth decrease speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_az.setpoint_speed = - atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'S' &amp;amp;&amp;amp; buffer[1] == 'A' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == ' ' &amp;amp;&amp;amp; buffer[3] == 'S' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[4] == 'E') {&lt;br /&gt;
                        // Stop Moving&lt;br /&gt;
                        rotator.control_mode = position;&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        control_az.setpoint = control_az.input;&lt;br /&gt;
                        control_el.setpoint = control_el.input;&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == 'S' &amp;amp;&amp;amp; buffer[3] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[4] == 'T') {&lt;br /&gt;
                        // Reset the rotator, go to home position&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        rotator.homing_flag = false;&lt;br /&gt;
                    } else if (buffer[0] == 'P' &amp;amp;&amp;amp; buffer[1] == 'A' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == 'R' &amp;amp;&amp;amp; buffer[3] == 'K' ) {&lt;br /&gt;
                        // Park the rotator&lt;br /&gt;
                        rotator.control_mode = position;&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        control_az.setpoint = rotator.park_az;&lt;br /&gt;
                        control_el.setpoint = rotator.park_el;&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'E') {&lt;br /&gt;
                        // Get the version if rotator controller&lt;br /&gt;
                        str1 = String(&amp;quot;VE&amp;quot;);&lt;br /&gt;
                        str2 = String(&amp;quot;SatNOGS-v2.2&amp;quot;);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '0') {&lt;br /&gt;
                        // Get the inside temperature&lt;br /&gt;
                        str1 = String(&amp;quot;IP0,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.inside_temperature, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '1') {&lt;br /&gt;
                        // Get the status of end-stop, azimuth&lt;br /&gt;
                        str1 = String(&amp;quot;IP1,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.switch_az, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '2') {&lt;br /&gt;
                        // Get the status of end-stop, elevation&lt;br /&gt;
                        str1 = String(&amp;quot;IP2,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.switch_el, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '3') {&lt;br /&gt;
                        // Get the current position of azimuth in deg&lt;br /&gt;
                        str1 = String(&amp;quot;IP3,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '4') {&lt;br /&gt;
                        // Get the current position of elevation in deg&lt;br /&gt;
                        str1 = String(&amp;quot;IP4,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.input, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '5') {&lt;br /&gt;
                        // Get the load of azimuth, in range of 0-1023&lt;br /&gt;
                        str1 = String(&amp;quot;IP5,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.load, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '6') {&lt;br /&gt;
                        // Get the load of elevation, in range of 0-1023&lt;br /&gt;
                        str1 = String(&amp;quot;IP6,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.load, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '7') {&lt;br /&gt;
                        // Get the speed of azimuth in deg/s&lt;br /&gt;
                        str1 = String(&amp;quot;IP7,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.speed, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '8') {&lt;br /&gt;
                        // Get the speed of elevation in deg/s&lt;br /&gt;
                        str1 = String(&amp;quot;IP8,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.speed, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'G' &amp;amp;&amp;amp; buffer[1] == 'S') {&lt;br /&gt;
                        // Get the status of rotator&lt;br /&gt;
                        str1 = String(&amp;quot;GS&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.rotator_status, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'G' &amp;amp;&amp;amp; buffer[1] == 'E') {&lt;br /&gt;
                        // Get the error of rotator&lt;br /&gt;
                        str1 = String(&amp;quot;GE&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.rotator_error, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if(buffer[0] == 'C' &amp;amp;&amp;amp; buffer[1] == 'R') {&lt;br /&gt;
                        // Get Configuration of rotator&lt;br /&gt;
                        if (buffer[3] == '1') {&lt;br /&gt;
                            // Get Kp Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;1,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.p, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '2') {&lt;br /&gt;
                            // Get Ki Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;2,&amp;quot;);&lt;br /&gt;
                             str2 = String(control_az.i, 2);&lt;br /&gt;
                             str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                             Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '3') {&lt;br /&gt;
                            // Get Kd Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;3,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.d, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '4') {&lt;br /&gt;
                            // Get Kp Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;4,&amp;quot;);&lt;br /&gt;
                             str2 = String(control_el.p, 2);&lt;br /&gt;
                             str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                             Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '5') {&lt;br /&gt;
                            // Get Ki Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;5,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_el.i, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '6') {&lt;br /&gt;
                            // Get Kd Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;6,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_el.d, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '7') {&lt;br /&gt;
                            // Get Azimuth park position&lt;br /&gt;
                            str1 = String(&amp;quot;7,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.park_az, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '8') {&lt;br /&gt;
                            // Get Elevation park position&lt;br /&gt;
                            str1 = String(&amp;quot;8,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.park_el, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '9') {&lt;br /&gt;
                            // Get control mode&lt;br /&gt;
                            str1 = String(&amp;quot;9,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.control_mode);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'C' &amp;amp;&amp;amp; buffer[1] == 'W') {&lt;br /&gt;
                        // Set Config&lt;br /&gt;
                        if (buffer[2] == '1') {&lt;br /&gt;
                            // Set Kp Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.p = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '2') {&lt;br /&gt;
                            // Set Ki Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.i = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '3') {&lt;br /&gt;
                            // Set Kd Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.d = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '4') {&lt;br /&gt;
                            // Set Kp Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.p = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '5') {&lt;br /&gt;
                            // Set Ki Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.i = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '6') {&lt;br /&gt;
                            // Set Kd Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.d = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        }  else if (buffer[2] == '7') {&lt;br /&gt;
                            // Set the Azimuth park position&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                rotator.park_az = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '8') {&lt;br /&gt;
                            // Set the Elevation park position&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                rotator.park_el = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'S'&lt;br /&gt;
                            &amp;amp;&amp;amp; buffer[2] == 'T') {&lt;br /&gt;
                        // Custom command to test the watchdog timer routine&lt;br /&gt;
                        while(1)&lt;br /&gt;
                            ;&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'B') {&lt;br /&gt;
                        // Custom command to reboot the uC&lt;br /&gt;
                        wdt_enable(WDTO_2S);&lt;br /&gt;
                        while(1);&lt;br /&gt;
                    }&lt;br /&gt;
                    // Reset the buffer an clean the serial buffer&lt;br /&gt;
                    BufferCnt = 0;&lt;br /&gt;
                    Serial.flush();&lt;br /&gt;
                } else {&lt;br /&gt;
                    // Fill the buffer with incoming data&lt;br /&gt;
                    buffer[BufferCnt] = incomingByte;&lt;br /&gt;
                    BufferCnt++;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    private:&lt;br /&gt;
        bool isNumber(char *input) {&lt;br /&gt;
            for (uint16_t i = 0; input[i] != '\0'; i++) {&lt;br /&gt;
                if (isalpha(input[i]))&lt;br /&gt;
                    return false;&lt;br /&gt;
            }&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    #endif /* LIBRARIES_EASYCOMM_H_ */&lt;br /&gt;
&lt;br /&gt;
===== Software to install =====&lt;br /&gt;
&lt;br /&gt;
Final pieces to the preparation work are to install a couple of pieces of software. firstly Hamlib. This will be used to communicate between GPredict and the Arduino. Secondly we will install the main prediction software, GPredict. We will not be going into detail about setup of GPredict but assume that you have followed the installation guide and had a play around with it so you can understand what it is and how it works.&lt;br /&gt;
&lt;br /&gt;
'''Install hamlib'''&lt;br /&gt;
&lt;br /&gt;
Download the [https://sourceforge.net/projects/hamlib/ Hamblib] software and follow the installation process. this may require you installing it with Administrator rights. using device manager find the port for the Arduino, for the purposes of this we will assume it is COM7&lt;br /&gt;
&lt;br /&gt;
Using a text editor, like Notepad++, to create a file with the code below in it. Note where COM7 is and amend with your own COM port. Save as a batch file (i.e. with th extension .bat file in the same folder as rotctld  (Usually found in C:\Program Files (x86)\hamlib-w64-3.2\bin )&lt;br /&gt;
 rotctld -m 202 -r COM7 -s 9600 -T 127.0.0.1 -t 4533 -C timeout=500 -C retry=0 -vvvvvvvv &amp;gt; pause&lt;br /&gt;
&lt;br /&gt;
'''Install GPredict'''&lt;br /&gt;
&lt;br /&gt;
Download and install [https://sourceforge.net/projects/gpredict/ GPredict]. Next we will need to add a rotator. Go to Edit &amp;gt; Preferences &amp;gt; Interfaces &amp;gt; Rotators &amp;gt; Add New&lt;br /&gt;
[[File:GPredict Interfaces.png|centre]]&lt;br /&gt;
[[File:Gpredict Rotator Config.png|centre]]&lt;br /&gt;
&lt;br /&gt;
Give it a name. For example Arduino. The port is localhost 4533&lt;br /&gt;
&lt;br /&gt;
That's it for setup. next we will test the system&lt;br /&gt;
&lt;br /&gt;
=== Testing ===&lt;br /&gt;
We will need to do a few things to get the system running. &lt;br /&gt;
&lt;br /&gt;
# Start the .bat file&lt;br /&gt;
# In GPredict open up the Antenna module and click Engage&lt;br /&gt;
# You should see that in the batch file output a series of commands being sent to the Arduino&lt;br /&gt;
# Check that both the Az and Ele work correctly by manually driving the rotator&lt;br /&gt;
[[File:GPredict Antenna Control.png|centre]]&lt;br /&gt;
&lt;br /&gt;
Occasionally this might not work first time. A restart of both hamlib and Gpredict worked &lt;br /&gt;
&lt;br /&gt;
=== Tweaks ===&lt;br /&gt;
There is a huge variety in parts that can get bought, here are a few tweaks that may be necessary.&lt;br /&gt;
&lt;br /&gt;
'''''Motors are turning the wrong way''''' - This may need the pins checking &lt;br /&gt;
&lt;br /&gt;
'''''It is only moving half the distance''''' - Change the gear ratio in the main sketch&lt;br /&gt;
&lt;br /&gt;
'''''The limit switches are not working''''' - Change the following code in the main sketch&lt;br /&gt;
 define DEFAULT_HOME_STATE LOW ///&amp;lt; Change to LOW according to Home sensor&lt;br /&gt;
&lt;br /&gt;
=== Operation ===&lt;br /&gt;
&lt;br /&gt;
Operating is as simple as selecting a satellite from GPredict and then selecting track. The rotator will then follow that satellite or object.&lt;br /&gt;
&lt;br /&gt;
{{DEFAULTSORT:SatNOGS Arduino Uno CNC Shield Based Rotator Controller}}&lt;br /&gt;
__FORCETOC__&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=SatNOGS_Arduino_Uno/CNC_Shield_Based_Rotator_Controller&amp;diff=2662</id>
		<title>SatNOGS Arduino Uno/CNC Shield Based Rotator Controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=SatNOGS_Arduino_Uno/CNC_Shield_Based_Rotator_Controller&amp;diff=2662"/>
		<updated>2019-03-12T18:06:12Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: Added some images&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:SatNOGS Arduino Uno CNC Shield Based Rotator Controller}}&lt;br /&gt;
&lt;br /&gt;
=== Controlling the rotator as a stand alone system using GPredict ===&lt;br /&gt;
The SatNOGS rotator is primarily designed to be used as a system component that is part of a SatNOGS ground station. There may be occasion when it is desirable to have a stand alone ground station that is removed from the SatNOGS network. This can be done using existing equipment but can also be simplified using off the shelf components.&lt;br /&gt;
&lt;br /&gt;
The following information is to connect your Rotator controller DIRECTLY TO A PC. If you'd like to still use it with the Raspberry Pi then you must keep the RS485 protocol in place.&lt;br /&gt;
&lt;br /&gt;
We will need slightly different hardware and modified software to achieve this, the main changes will be to remove the RS485 and watchdog parts of the firmware. We will be using the following items:&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
# SatNOGS Rotator V3.1 hardware&lt;br /&gt;
# Arduino Uno R3&lt;br /&gt;
# CNC Shield V3 with A4988 drivers&lt;br /&gt;
# NEMA 17 Stepper Motors&lt;br /&gt;
# 2x microswitches&lt;br /&gt;
# Suitable 12v power supply (The shield will accept between 12v and 36v)&lt;br /&gt;
# Cables to connect the Arduino to the PC&lt;br /&gt;
&lt;br /&gt;
[[File:Arduino CNC Shield.png|centre|Bare CNC Shield]]&lt;br /&gt;
&lt;br /&gt;
[[File:A4988 Drivers.png|centre]]&lt;br /&gt;
&lt;br /&gt;
==== Software ====&lt;br /&gt;
For the purposes of this article we will be using Windows software. The same result can be achieved with Linux or Mac OS but for clarity these options have been ignored for the time being. We will need:&lt;br /&gt;
# A copy of the Arduino IDE (version 1.8.5 has been used as part of this tutorial)&lt;br /&gt;
# GPredict&lt;br /&gt;
# Hamlib&lt;br /&gt;
# A text editor such as Notepad++ for a small script&lt;br /&gt;
# [https://gitlab.com/Quartapound/satnogs-rotator-firmware You can find the edited sketch and libraries in the following Fork :  https://gitlab.com/Quartapound/satnogs-rotator-firmware]&lt;br /&gt;
&lt;br /&gt;
=== Method ===&lt;br /&gt;
&lt;br /&gt;
==== Hardware setup ====&lt;br /&gt;
We will not be using the custom SatNOGS PCB. Instead this set up uses an Arduino Uno and CNC motor shield. There is very little assembly required but depending on how and where you buy from will depend on the amount of assembly is required. Typically the Arduino will need no assembly, The motor shield will need two A4988 drivers (these can come as part of the package). These are used in the X &amp;amp; Y headers as per the photograph below. The drivers fit into the female headers, note that there are jumper headers below these drivers that are used for stepping control. We will also be attaching the stepper motor cables to the male headers to the left of the driver boards.&lt;br /&gt;
[[File:Assembled CNC Shield.png|centre]]&lt;br /&gt;
&lt;br /&gt;
Pinout of the 4 headers is as follows starting from the top (4 vertical pins to the left of the A4988 motor driver board, marked X,Y &amp;amp; Z)&lt;br /&gt;
&lt;br /&gt;
Pin 1 - A&lt;br /&gt;
&lt;br /&gt;
Pin 2 - A+&lt;br /&gt;
&lt;br /&gt;
Pin 3 - B&lt;br /&gt;
&lt;br /&gt;
Pin 4 - B+&lt;br /&gt;
&lt;br /&gt;
This follows a convention so most steppers should plug directly into the header without any changes, but be aware that this is not always the case and that there may be some cases where pins are incorrectly noted and the steppers will drive in the opposite direction.&lt;br /&gt;
&lt;br /&gt;
The setup is very basic but be careful not to bend pins as this can be easily done if too much pressure is put on the boards when things are no aligned. They aren't always perfect!&lt;br /&gt;
&lt;br /&gt;
In the end you should have:&lt;br /&gt;
* Azimuth Stepper Driver/motor connected to Y port on CNC Board&lt;br /&gt;
* Elevation Stepper Driver/motor connected to X port on CNC Board&lt;br /&gt;
* The End stop switch for elevation is connected to the X end stop on the CNC board (+ or -)&lt;br /&gt;
* The End stop switch for azimuth is connected to the Y end stop on the CNC board (+ or -)&lt;br /&gt;
&lt;br /&gt;
==== Software setup ====&lt;br /&gt;
&lt;br /&gt;
===== Code modifications =====&lt;br /&gt;
For the time being there is no fork of the firmware in the repositories. This may change in the future but for the time being a small series of changes are required to achieve results. We will need to modify two elements of the firmware, easycomm.h and rotator_pins.h. These changes are necessary to stop their being conflicts with the communication between boards and PC as well as re-assigning pins to match the CNC shield. We'll modify the rotator_pins.h first. Note the use of comments (//) to remove lines of code. We have also changed pin designation to match the shield.&lt;br /&gt;
&lt;br /&gt;
    /*!&lt;br /&gt;
    * @file rotator_pins.h&lt;br /&gt;
    *&lt;br /&gt;
    * It is a header file for pin mapping.&lt;br /&gt;
    *&lt;br /&gt;
    * Licensed under the GPLv3&lt;br /&gt;
    *&lt;br /&gt;
    */&lt;br /&gt;
&lt;br /&gt;
    #ifndef ROTATOR_PINS_H_&lt;br /&gt;
    #define ROTATOR_PINS_H_&lt;br /&gt;
&lt;br /&gt;
    //#define M1IN1 10 ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1IN1 2 ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1IN2 5  ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1SF  7  ///&amp;lt; Motor 1 digital input, status flag for DC Motor Drivers&lt;br /&gt;
    #define M1FB  A1 ///&amp;lt; Motor 1 analog input, current/load feedback for DC Motor Drivers&lt;br /&gt;
&lt;br /&gt;
    #define M2IN1 3 ///&amp;lt; Motor 2 PWM pin&lt;br /&gt;
    #define M2IN2 6  ///&amp;lt; Motor 2 PWM pin&lt;br /&gt;
    #define M2SF  7 ///&amp;lt; Motor 2 digital input, status flag for DC Motor Drivers&lt;br /&gt;
    #define M2FB  A0 ///&amp;lt; Motor 2 analog input, current/load feedback for DC Motor Drivers&lt;br /&gt;
&lt;br /&gt;
    #define MOTOR_EN 8 ///&amp;lt; Digital output, to enable the motors&lt;br /&gt;
&lt;br /&gt;
    #define SW1 11 ///&amp;lt; Digital input, to read the status of end-stop for motor 1&lt;br /&gt;
    #define SW2 9 ///&amp;lt; Digital input, to read the status of end-stop for motor 2&lt;br /&gt;
&lt;br /&gt;
    #define RS485_DIR 2 ///&amp;lt; Digital output, to set the direction of RS485 communication&lt;br /&gt;
&lt;br /&gt;
    #define SDA_PIN 3 ///&amp;lt; I2C data pin&lt;br /&gt;
    #define SCL_PIN 4 ///&amp;lt; I2C clock pin&lt;br /&gt;
&lt;br /&gt;
    #define PIN12 12 ///&amp;lt; General purpose I/O pin&lt;br /&gt;
    #define PIN13 13 ///&amp;lt; General purpose I/O pin&lt;br /&gt;
    #define A2    A2 ///&amp;lt; General purpose I/O &amp;amp; analog pin&lt;br /&gt;
    #define A3    A3 ///&amp;lt; General purpose I/O &amp;amp; analog pin&lt;br /&gt;
&lt;br /&gt;
    #endif /* ROTATOR_PINS_H_ */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The next code edit will remove both the RS485 and watchdog elements from the easycomm.h code. This will allow the PC to talk directly to the Arduino and as such bypass the RPi. The edited code is below, note again the use of comments (//) to remove the lines&lt;br /&gt;
    /*!&lt;br /&gt;
    * @file easycomm.h&lt;br /&gt;
    *&lt;br /&gt;
    * It is a driver for easycomm 3 protocol as referred, in Hamlib.&lt;br /&gt;
    *&lt;br /&gt;
    * Licensed under the GPLv3&lt;br /&gt;
    *&lt;br /&gt;
    */&lt;br /&gt;
&lt;br /&gt;
    #ifndef LIBRARIES_EASYCOMM_H_&lt;br /&gt;
    #define LIBRARIES_EASYCOMM_H_&lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;Arduino.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;WString.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;avr/wdt.h&amp;gt;&lt;br /&gt;
    //#include &amp;quot;rs485.h&amp;quot;&lt;br /&gt;
    #include &amp;quot;rotator_pins.h&amp;quot;&lt;br /&gt;
    #include &amp;quot;globals.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    #define RS485_TX_TIME 9     ///&amp;lt; Delay &amp;quot;t&amp;quot;ms to write in serial for RS485 implementation&lt;br /&gt;
    #define BUFFER_SIZE   256   ///&amp;lt; Set the size of serial buffer&lt;br /&gt;
    #define BAUDRATE      19200 ///&amp;lt; Set the Baudrate of easycomm 3 protocol&lt;br /&gt;
&lt;br /&gt;
    //rs485 rs485(RS485_DIR, RS485_TX_TIME);&lt;br /&gt;
&lt;br /&gt;
    /**************************************************************************/&lt;br /&gt;
    /*!&lt;br /&gt;
        @brief    Class that functions for easycomm 3 implementation&lt;br /&gt;
    */&lt;br /&gt;
    /**************************************************************************/&lt;br /&gt;
    class easycomm {&lt;br /&gt;
    public:&lt;br /&gt;
&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        /*!&lt;br /&gt;
            @brief    Initialize the RS485 bus&lt;br /&gt;
        */&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        void easycomm_init() {&lt;br /&gt;
           // rs485.begin(BAUDRATE);&lt;br /&gt;
    	    Serial.begin(9600);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        /*!&lt;br /&gt;
            @brief    Get the commands from RS485 and response to the client&lt;br /&gt;
        */&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        void easycomm_proc() {&lt;br /&gt;
            char buffer[BUFFER_SIZE];&lt;br /&gt;
            char incomingByte;&lt;br /&gt;
            char *Data = buffer;&lt;br /&gt;
            char *rawData;&lt;br /&gt;
            static uint16_t BufferCnt = 0;&lt;br /&gt;
            char data[100];&lt;br /&gt;
            String str1, str2, str3, str4, str5, str6;&lt;br /&gt;
&lt;br /&gt;
            // Read from serial&lt;br /&gt;
            while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
                incomingByte = Serial.read();&lt;br /&gt;
&lt;br /&gt;
                // Read new data, '\n' means new pacakage&lt;br /&gt;
                if (incomingByte == '\n' || incomingByte == '\r') {&lt;br /&gt;
                    buffer[BufferCnt] = 0;&lt;br /&gt;
                    if (buffer[0] == 'A' &amp;amp;&amp;amp; buffer[1] == 'Z') {&lt;br /&gt;
                        if (buffer[2] == ' ' &amp;amp;&amp;amp; buffer[3] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                            buffer[4] == 'L') {&lt;br /&gt;
                            // Send current absolute position in deg&lt;br /&gt;
                            str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.input, 1);&lt;br /&gt;
                            str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                            str4 = String(control_el.input, 1);&lt;br /&gt;
                            str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            // Get the absolute position in deg for azimuth&lt;br /&gt;
                            rotator.control_mode = position;&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 2, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.setpoint = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                            // Get the absolute position in deg for elevation&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            if (rawData[0] == 'E' &amp;amp;&amp;amp; rawData[1] == 'L') {&lt;br /&gt;
                                strncpy(data, rawData + 2, 10);&lt;br /&gt;
                                if (isNumber(data)) {&lt;br /&gt;
                                    control_el.setpoint = atof(data);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'E' &amp;amp;&amp;amp; buffer[1] == 'L') {&lt;br /&gt;
                            // Get the absolute position in deg for elevation&lt;br /&gt;
                            rotator.control_mode = position;&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            if (rawData[0] == 'E' &amp;amp;&amp;amp; rawData[1] == 'L') {&lt;br /&gt;
                                strncpy(data, rawData + 2, 10);&lt;br /&gt;
                                if (isNumber(data)) {&lt;br /&gt;
                                    control_el.setpoint = atof(data);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'U') {&lt;br /&gt;
                        // Elevation increase speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_el.setpoint_speed = atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'D') {&lt;br /&gt;
                        // Elevation decrease speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_el.setpoint_speed = - atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'L') {&lt;br /&gt;
                        // Azimuth increase speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_az.setpoint_speed = atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'R') {&lt;br /&gt;
                        // Azimuth decrease speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_az.setpoint_speed = - atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'S' &amp;amp;&amp;amp; buffer[1] == 'A' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == ' ' &amp;amp;&amp;amp; buffer[3] == 'S' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[4] == 'E') {&lt;br /&gt;
                        // Stop Moving&lt;br /&gt;
                        rotator.control_mode = position;&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        control_az.setpoint = control_az.input;&lt;br /&gt;
                        control_el.setpoint = control_el.input;&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == 'S' &amp;amp;&amp;amp; buffer[3] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[4] == 'T') {&lt;br /&gt;
                        // Reset the rotator, go to home position&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        rotator.homing_flag = false;&lt;br /&gt;
                    } else if (buffer[0] == 'P' &amp;amp;&amp;amp; buffer[1] == 'A' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == 'R' &amp;amp;&amp;amp; buffer[3] == 'K' ) {&lt;br /&gt;
                        // Park the rotator&lt;br /&gt;
                        rotator.control_mode = position;&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        control_az.setpoint = rotator.park_az;&lt;br /&gt;
                        control_el.setpoint = rotator.park_el;&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'E') {&lt;br /&gt;
                        // Get the version if rotator controller&lt;br /&gt;
                        str1 = String(&amp;quot;VE&amp;quot;);&lt;br /&gt;
                        str2 = String(&amp;quot;SatNOGS-v2.2&amp;quot;);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '0') {&lt;br /&gt;
                        // Get the inside temperature&lt;br /&gt;
                        str1 = String(&amp;quot;IP0,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.inside_temperature, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '1') {&lt;br /&gt;
                        // Get the status of end-stop, azimuth&lt;br /&gt;
                        str1 = String(&amp;quot;IP1,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.switch_az, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '2') {&lt;br /&gt;
                        // Get the status of end-stop, elevation&lt;br /&gt;
                        str1 = String(&amp;quot;IP2,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.switch_el, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '3') {&lt;br /&gt;
                        // Get the current position of azimuth in deg&lt;br /&gt;
                        str1 = String(&amp;quot;IP3,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '4') {&lt;br /&gt;
                        // Get the current position of elevation in deg&lt;br /&gt;
                        str1 = String(&amp;quot;IP4,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.input, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '5') {&lt;br /&gt;
                        // Get the load of azimuth, in range of 0-1023&lt;br /&gt;
                        str1 = String(&amp;quot;IP5,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.load, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '6') {&lt;br /&gt;
                        // Get the load of elevation, in range of 0-1023&lt;br /&gt;
                        str1 = String(&amp;quot;IP6,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.load, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '7') {&lt;br /&gt;
                        // Get the speed of azimuth in deg/s&lt;br /&gt;
                        str1 = String(&amp;quot;IP7,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.speed, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '8') {&lt;br /&gt;
                        // Get the speed of elevation in deg/s&lt;br /&gt;
                        str1 = String(&amp;quot;IP8,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.speed, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'G' &amp;amp;&amp;amp; buffer[1] == 'S') {&lt;br /&gt;
                        // Get the status of rotator&lt;br /&gt;
                        str1 = String(&amp;quot;GS&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.rotator_status, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'G' &amp;amp;&amp;amp; buffer[1] == 'E') {&lt;br /&gt;
                        // Get the error of rotator&lt;br /&gt;
                        str1 = String(&amp;quot;GE&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.rotator_error, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if(buffer[0] == 'C' &amp;amp;&amp;amp; buffer[1] == 'R') {&lt;br /&gt;
                        // Get Configuration of rotator&lt;br /&gt;
                        if (buffer[3] == '1') {&lt;br /&gt;
                            // Get Kp Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;1,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.p, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '2') {&lt;br /&gt;
                            // Get Ki Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;2,&amp;quot;);&lt;br /&gt;
                             str2 = String(control_az.i, 2);&lt;br /&gt;
                             str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                             Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '3') {&lt;br /&gt;
                            // Get Kd Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;3,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.d, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '4') {&lt;br /&gt;
                            // Get Kp Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;4,&amp;quot;);&lt;br /&gt;
                             str2 = String(control_el.p, 2);&lt;br /&gt;
                             str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                             Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '5') {&lt;br /&gt;
                            // Get Ki Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;5,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_el.i, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '6') {&lt;br /&gt;
                            // Get Kd Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;6,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_el.d, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '7') {&lt;br /&gt;
                            // Get Azimuth park position&lt;br /&gt;
                            str1 = String(&amp;quot;7,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.park_az, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '8') {&lt;br /&gt;
                            // Get Elevation park position&lt;br /&gt;
                            str1 = String(&amp;quot;8,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.park_el, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '9') {&lt;br /&gt;
                            // Get control mode&lt;br /&gt;
                            str1 = String(&amp;quot;9,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.control_mode);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'C' &amp;amp;&amp;amp; buffer[1] == 'W') {&lt;br /&gt;
                        // Set Config&lt;br /&gt;
                        if (buffer[2] == '1') {&lt;br /&gt;
                            // Set Kp Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.p = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '2') {&lt;br /&gt;
                            // Set Ki Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.i = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '3') {&lt;br /&gt;
                            // Set Kd Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.d = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '4') {&lt;br /&gt;
                            // Set Kp Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.p = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '5') {&lt;br /&gt;
                            // Set Ki Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.i = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '6') {&lt;br /&gt;
                            // Set Kd Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.d = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        }  else if (buffer[2] == '7') {&lt;br /&gt;
                            // Set the Azimuth park position&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                rotator.park_az = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '8') {&lt;br /&gt;
                            // Set the Elevation park position&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                rotator.park_el = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'S'&lt;br /&gt;
                            &amp;amp;&amp;amp; buffer[2] == 'T') {&lt;br /&gt;
                        // Custom command to test the watchdog timer routine&lt;br /&gt;
                        while(1)&lt;br /&gt;
                            ;&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'B') {&lt;br /&gt;
                        // Custom command to reboot the uC&lt;br /&gt;
                        wdt_enable(WDTO_2S);&lt;br /&gt;
                        while(1);&lt;br /&gt;
                    }&lt;br /&gt;
                    // Reset the buffer an clean the serial buffer&lt;br /&gt;
                    BufferCnt = 0;&lt;br /&gt;
                    Serial.flush();&lt;br /&gt;
                } else {&lt;br /&gt;
                    // Fill the buffer with incoming data&lt;br /&gt;
                    buffer[BufferCnt] = incomingByte;&lt;br /&gt;
                    BufferCnt++;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    private:&lt;br /&gt;
        bool isNumber(char *input) {&lt;br /&gt;
            for (uint16_t i = 0; input[i] != '\0'; i++) {&lt;br /&gt;
                if (isalpha(input[i]))&lt;br /&gt;
                    return false;&lt;br /&gt;
            }&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    #endif /* LIBRARIES_EASYCOMM_H_ */&lt;br /&gt;
&lt;br /&gt;
===== Software to install =====&lt;br /&gt;
&lt;br /&gt;
Final pieces to the preparation work are to install a couple of pieces of software. firstly Hamlib. This will be used to communicate between GPredict and the Arduino. Secondly we will install the main prediction software, GPredict. We will not be going into detail about setup of GPredict but assume that you have followed the installation guide and had a play around with it so you can understand what it is and how it works.&lt;br /&gt;
&lt;br /&gt;
'''Install hamlib'''&lt;br /&gt;
&lt;br /&gt;
Download the [https://sourceforge.net/projects/hamlib/ Hamblib] software and follow the installation process. this may require you installing it with Administrator rights. using device manager find the port for the Arduino, for the purposes of this we will assume it is COM7&lt;br /&gt;
&lt;br /&gt;
Using a text editor, like Notepad++, to create a file with the code below in it. Note where COM7 is and amend with your own COM port. Save as a batch file (i.e. with th extension .bat file in the same folder as rotctld  (Usually found in C:\Program Files (x86)\hamlib-w64-3.2\bin )&lt;br /&gt;
 rotctld -m 202 -r COM7 -s 9600 -T 127.0.0.1 -t 4533 -C timeout=500 -C retry=0 -vvvvvvvv &amp;gt; pause&lt;br /&gt;
&lt;br /&gt;
'''Install GPredict'''&lt;br /&gt;
&lt;br /&gt;
Download and install [https://sourceforge.net/projects/gpredict/ GPredict]. Next we will need to add a rotator. Go to Edit &amp;gt; Preferences &amp;gt; Interfaces &amp;gt; Rotators &amp;gt; Add New&lt;br /&gt;
[[File:GPredict Interfaces.png|centre]]&lt;br /&gt;
[[File:Gpredict Rotator Config.png|centre]]&lt;br /&gt;
&lt;br /&gt;
Give it a name. For example Arduino. The port is localhost 4533&lt;br /&gt;
&lt;br /&gt;
That's it for setup. next we will test the system&lt;br /&gt;
&lt;br /&gt;
=== Testing ===&lt;br /&gt;
We will need to do a few things to get the system running. &lt;br /&gt;
&lt;br /&gt;
# Start the .bat file&lt;br /&gt;
# In GPredict open up the Antenna module and click Engage&lt;br /&gt;
# You should see that in the batch file output a series of commands being sent to the Arduino&lt;br /&gt;
# Check that both the Az and Ele work correctly by manually driving the rotator&lt;br /&gt;
[[File:GPredict Antenna Control.png|centre]]&lt;br /&gt;
&lt;br /&gt;
Occasionally this might not work first time. A restart of both hamlib and Gpredict worked &lt;br /&gt;
&lt;br /&gt;
=== Tweaks ===&lt;br /&gt;
There is a huge variety in parts that can get bought, here are a few tweaks that may be necessary.&lt;br /&gt;
&lt;br /&gt;
'''''Motors are turning the wrong way''''' - This may need the pins checking &lt;br /&gt;
&lt;br /&gt;
'''''It is only moving half the distance''''' - Change the gear ratio in the main sketch&lt;br /&gt;
&lt;br /&gt;
'''''The limit switches are not working''''' - Change the following code in the main sketch&lt;br /&gt;
 define DEFAULT_HOME_STATE LOW ///&amp;lt; Change to LOW according to Home sensor&lt;br /&gt;
&lt;br /&gt;
=== Operation ===&lt;br /&gt;
&lt;br /&gt;
Operating is as simple as selecting a satellite from GPredict and then selecting track. The rotator will then follow that satellite or object.f&lt;br /&gt;
&lt;br /&gt;
{{DEFAULTSORT:SatNOGS Arduino Uno CNC Shield Based Rotator Controller}}&lt;br /&gt;
__FORCETOC__&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=File:Assembled_CNC_Shield.png&amp;diff=2661</id>
		<title>File:Assembled CNC Shield.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=File:Assembled_CNC_Shield.png&amp;diff=2661"/>
		<updated>2019-03-12T18:02:42Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Completed board&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=File:A4988_Drivers.png&amp;diff=2660</id>
		<title>File:A4988 Drivers.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=File:A4988_Drivers.png&amp;diff=2660"/>
		<updated>2019-03-12T17:12:37Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Bare motor drivers&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=File:Arduino_CNC_Shield.png&amp;diff=2659</id>
		<title>File:Arduino CNC Shield.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=File:Arduino_CNC_Shield.png&amp;diff=2659"/>
		<updated>2019-03-12T17:11:48Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Bare Arduino Shield&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=File:GPredict_Antenna_Control.png&amp;diff=2658</id>
		<title>File:GPredict Antenna Control.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=File:GPredict_Antenna_Control.png&amp;diff=2658"/>
		<updated>2019-03-12T17:03:26Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;GPredict &amp;amp; Arduino CNC Shield manual drive&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=File:Gpredict_Rotator_Config.png&amp;diff=2657</id>
		<title>File:Gpredict Rotator Config.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=File:Gpredict_Rotator_Config.png&amp;diff=2657"/>
		<updated>2019-03-12T17:02:13Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Set up for GPredict &amp;amp; Arduino CNC Shield&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=File:GPredict_Interfaces.png&amp;diff=2656</id>
		<title>File:GPredict Interfaces.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=File:GPredict_Interfaces.png&amp;diff=2656"/>
		<updated>2019-03-12T16:59:55Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Set up for GPredict &amp;amp; Arduino CNC Shield&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=SatNOGS_Arduino_Uno/CNC_Shield_Based_Rotator_Controller&amp;diff=2651</id>
		<title>SatNOGS Arduino Uno/CNC Shield Based Rotator Controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=SatNOGS_Arduino_Uno/CNC_Shield_Based_Rotator_Controller&amp;diff=2651"/>
		<updated>2019-03-11T13:09:22Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: Update to testing&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:SatNOGS Arduino Uno CNC Shield Based Rotator Controller}}&lt;br /&gt;
&lt;br /&gt;
=== Controlling the rotator as a stand alone system using GPredict ===&lt;br /&gt;
The SatNOGS rotator is primarily designed to be used as a system component that is part of a SatNOGS ground station. There may be occasion when it is desirable to have a stand alone ground station that is removed from the SatNOGS network. This can be done using existing equipment but can also be simplified using off the shelf components.&lt;br /&gt;
&lt;br /&gt;
The following information is to connect your Rotator controller DIRECTLY TO A PC. If you'd like to still use it with the Raspberry Pi then you must keep the RS485 protocol in place.&lt;br /&gt;
&lt;br /&gt;
We will need slightly different hardware and modified software to achieve this, the main changes will be to remove the RS485 and watchdog parts of the firmware. We will be using the following items:&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
# SatNOGS Rotator V3.1 hardware&lt;br /&gt;
# Arduino Uno R3&lt;br /&gt;
# CNC Shield V3 with A4988 drivers&lt;br /&gt;
# NEMA 17 Stepper Motors&lt;br /&gt;
# 2x microswitches&lt;br /&gt;
# Suitable 12v power supply (The shield will accept between 12v and 36v)&lt;br /&gt;
# Cables to connect the Arduino to the PC&lt;br /&gt;
&lt;br /&gt;
==== Software ====&lt;br /&gt;
For the purposes of this article we will be using Windows software. The same result can be achieved with Linux or Mac OS but for clarity these options have been ignored for the time being. We will need:&lt;br /&gt;
# A copy of the Arduino IDE (version 1.8.5 has been used as part of this tutorial)&lt;br /&gt;
# GPredict&lt;br /&gt;
# Hamlib&lt;br /&gt;
# A text editor such as Notepad++ for a small script&lt;br /&gt;
&lt;br /&gt;
=== Method ===&lt;br /&gt;
&lt;br /&gt;
==== Hardware setup ====&lt;br /&gt;
We will not be using the custom SatNOGS PCB. Instead this set up uses an Arduino Uno and CNC motor shield. There is very little assembly required but depending on how and where you buy from will depend on the amount of assembly is required. Typically the Arduino will need no assembly, The motor shield will need two A4988 drivers (these can come as part of the package). These are used in the X &amp;amp; Y headers as per the photograph below. The drivers fit into the female headers, note that there are jumper headers below these drivers that are used for stepping control. We will also be attaching the stepper motor cables to the male headers to the left of the driver boards.&lt;br /&gt;
&lt;br /&gt;
Photo of board&lt;br /&gt;
&lt;br /&gt;
Pinout of the 4 headers is as follows starting from the top&lt;br /&gt;
&lt;br /&gt;
Pin 1 - A&lt;br /&gt;
&lt;br /&gt;
Pin 2 - A+&lt;br /&gt;
&lt;br /&gt;
Pin 3 - B&lt;br /&gt;
&lt;br /&gt;
Pin 4 - B+&lt;br /&gt;
&lt;br /&gt;
This follows a convention so most steppers should plug directly into the header without any changes, but be aware that this is not always the case and that there may be some cases where pins are incorrectly noted and the steppers will drive in the opposite direction.&lt;br /&gt;
&lt;br /&gt;
The setup is very basic but be careful not to bend pins as this can be easily done if too much pressure is put on the boards when things are no aligned. They aren't always perfect!&lt;br /&gt;
&lt;br /&gt;
In the end you should have:&lt;br /&gt;
* Azimuth Stepper Driver/motor connected to Y port on CNC Board&lt;br /&gt;
* Elevation Stepper Driver/motor connected to X port on CNC Board&lt;br /&gt;
* The End stop switch for elevation is connected to the X end stop on the CNC board (+ or -)&lt;br /&gt;
* The End stop switch for azimuth is connected to the Y end stop on the CNC board (+ or -)&lt;br /&gt;
&lt;br /&gt;
==== Software setup ====&lt;br /&gt;
&lt;br /&gt;
===== Code modifications =====&lt;br /&gt;
For the time being there is no fork of the firmware in the repositories. This may change in the future but for the time being a small series of changes are required to achieve results. We will need to modify two elements of the firmware, easycomm.h and rotator_pins.h. These changes are necessary to stop their being conflicts with the communication between boards and PC as well as re-assigning pins to match the CNC shield. We'll modify the rotator_pins.h first. Note the use of comments (//) to remove lines of code. We have also changed pin designation to match the shield.&lt;br /&gt;
&lt;br /&gt;
    /*!&lt;br /&gt;
    * @file rotator_pins.h&lt;br /&gt;
    *&lt;br /&gt;
    * It is a header file for pin mapping.&lt;br /&gt;
    *&lt;br /&gt;
    * Licensed under the GPLv3&lt;br /&gt;
    *&lt;br /&gt;
    */&lt;br /&gt;
&lt;br /&gt;
    #ifndef ROTATOR_PINS_H_&lt;br /&gt;
    #define ROTATOR_PINS_H_&lt;br /&gt;
&lt;br /&gt;
    //#define M1IN1 10 ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1IN1 2 ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1IN2 5  ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1SF  7  ///&amp;lt; Motor 1 digital input, status flag for DC Motor Drivers&lt;br /&gt;
    #define M1FB  A1 ///&amp;lt; Motor 1 analog input, current/load feedback for DC Motor Drivers&lt;br /&gt;
&lt;br /&gt;
    #define M2IN1 3 ///&amp;lt; Motor 2 PWM pin&lt;br /&gt;
    #define M2IN2 6  ///&amp;lt; Motor 2 PWM pin&lt;br /&gt;
    #define M2SF  7 ///&amp;lt; Motor 2 digital input, status flag for DC Motor Drivers&lt;br /&gt;
    #define M2FB  A0 ///&amp;lt; Motor 2 analog input, current/load feedback for DC Motor Drivers&lt;br /&gt;
&lt;br /&gt;
    #define MOTOR_EN 8 ///&amp;lt; Digital output, to enable the motors&lt;br /&gt;
&lt;br /&gt;
    #define SW1 11 ///&amp;lt; Digital input, to read the status of end-stop for motor 1&lt;br /&gt;
    #define SW2 9 ///&amp;lt; Digital input, to read the status of end-stop for motor 2&lt;br /&gt;
&lt;br /&gt;
    #define RS485_DIR 2 ///&amp;lt; Digital output, to set the direction of RS485 communication&lt;br /&gt;
&lt;br /&gt;
    #define SDA_PIN 3 ///&amp;lt; I2C data pin&lt;br /&gt;
    #define SCL_PIN 4 ///&amp;lt; I2C clock pin&lt;br /&gt;
&lt;br /&gt;
    #define PIN12 12 ///&amp;lt; General purpose I/O pin&lt;br /&gt;
    #define PIN13 13 ///&amp;lt; General purpose I/O pin&lt;br /&gt;
    #define A2    A2 ///&amp;lt; General purpose I/O &amp;amp; analog pin&lt;br /&gt;
    #define A3    A3 ///&amp;lt; General purpose I/O &amp;amp; analog pin&lt;br /&gt;
&lt;br /&gt;
    #endif /* ROTATOR_PINS_H_ */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The next code edit will remove both the RS485 and watchdog elements from the easycomm.h code. This will allow the PC to talk directly to the Arduino and as such bypass the RPi. The edited code is below, note again the use of comments (//) to remove the lines&lt;br /&gt;
    /*!&lt;br /&gt;
    * @file easycomm.h&lt;br /&gt;
    *&lt;br /&gt;
    * It is a driver for easycomm 3 protocol as referred, in Hamlib.&lt;br /&gt;
    *&lt;br /&gt;
    * Licensed under the GPLv3&lt;br /&gt;
    *&lt;br /&gt;
    */&lt;br /&gt;
&lt;br /&gt;
    #ifndef LIBRARIES_EASYCOMM_H_&lt;br /&gt;
    #define LIBRARIES_EASYCOMM_H_&lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;Arduino.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;WString.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;avr/wdt.h&amp;gt;&lt;br /&gt;
    //#include &amp;quot;rs485.h&amp;quot;&lt;br /&gt;
    #include &amp;quot;rotator_pins.h&amp;quot;&lt;br /&gt;
    #include &amp;quot;globals.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    #define RS485_TX_TIME 9     ///&amp;lt; Delay &amp;quot;t&amp;quot;ms to write in serial for RS485 implementation&lt;br /&gt;
    #define BUFFER_SIZE   256   ///&amp;lt; Set the size of serial buffer&lt;br /&gt;
    #define BAUDRATE      19200 ///&amp;lt; Set the Baudrate of easycomm 3 protocol&lt;br /&gt;
&lt;br /&gt;
    //rs485 rs485(RS485_DIR, RS485_TX_TIME);&lt;br /&gt;
&lt;br /&gt;
    /**************************************************************************/&lt;br /&gt;
    /*!&lt;br /&gt;
        @brief    Class that functions for easycomm 3 implementation&lt;br /&gt;
    */&lt;br /&gt;
    /**************************************************************************/&lt;br /&gt;
    class easycomm {&lt;br /&gt;
    public:&lt;br /&gt;
&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        /*!&lt;br /&gt;
            @brief    Initialize the RS485 bus&lt;br /&gt;
        */&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        void easycomm_init() {&lt;br /&gt;
           // rs485.begin(BAUDRATE);&lt;br /&gt;
    	    Serial.begin(9600);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        /*!&lt;br /&gt;
            @brief    Get the commands from RS485 and response to the client&lt;br /&gt;
        */&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        void easycomm_proc() {&lt;br /&gt;
            char buffer[BUFFER_SIZE];&lt;br /&gt;
            char incomingByte;&lt;br /&gt;
            char *Data = buffer;&lt;br /&gt;
            char *rawData;&lt;br /&gt;
            static uint16_t BufferCnt = 0;&lt;br /&gt;
            char data[100];&lt;br /&gt;
            String str1, str2, str3, str4, str5, str6;&lt;br /&gt;
&lt;br /&gt;
            // Read from serial&lt;br /&gt;
            while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
                incomingByte = Serial.read();&lt;br /&gt;
&lt;br /&gt;
                // Read new data, '\n' means new pacakage&lt;br /&gt;
                if (incomingByte == '\n' || incomingByte == '\r') {&lt;br /&gt;
                    buffer[BufferCnt] = 0;&lt;br /&gt;
                    if (buffer[0] == 'A' &amp;amp;&amp;amp; buffer[1] == 'Z') {&lt;br /&gt;
                        if (buffer[2] == ' ' &amp;amp;&amp;amp; buffer[3] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                            buffer[4] == 'L') {&lt;br /&gt;
                            // Send current absolute position in deg&lt;br /&gt;
                            str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.input, 1);&lt;br /&gt;
                            str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                            str4 = String(control_el.input, 1);&lt;br /&gt;
                            str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            // Get the absolute position in deg for azimuth&lt;br /&gt;
                            rotator.control_mode = position;&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 2, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.setpoint = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                            // Get the absolute position in deg for elevation&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            if (rawData[0] == 'E' &amp;amp;&amp;amp; rawData[1] == 'L') {&lt;br /&gt;
                                strncpy(data, rawData + 2, 10);&lt;br /&gt;
                                if (isNumber(data)) {&lt;br /&gt;
                                    control_el.setpoint = atof(data);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'E' &amp;amp;&amp;amp; buffer[1] == 'L') {&lt;br /&gt;
                            // Get the absolute position in deg for elevation&lt;br /&gt;
                            rotator.control_mode = position;&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            if (rawData[0] == 'E' &amp;amp;&amp;amp; rawData[1] == 'L') {&lt;br /&gt;
                                strncpy(data, rawData + 2, 10);&lt;br /&gt;
                                if (isNumber(data)) {&lt;br /&gt;
                                    control_el.setpoint = atof(data);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'U') {&lt;br /&gt;
                        // Elevation increase speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_el.setpoint_speed = atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'D') {&lt;br /&gt;
                        // Elevation decrease speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_el.setpoint_speed = - atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'L') {&lt;br /&gt;
                        // Azimuth increase speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_az.setpoint_speed = atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'R') {&lt;br /&gt;
                        // Azimuth decrease speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_az.setpoint_speed = - atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'S' &amp;amp;&amp;amp; buffer[1] == 'A' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == ' ' &amp;amp;&amp;amp; buffer[3] == 'S' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[4] == 'E') {&lt;br /&gt;
                        // Stop Moving&lt;br /&gt;
                        rotator.control_mode = position;&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        control_az.setpoint = control_az.input;&lt;br /&gt;
                        control_el.setpoint = control_el.input;&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == 'S' &amp;amp;&amp;amp; buffer[3] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[4] == 'T') {&lt;br /&gt;
                        // Reset the rotator, go to home position&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        rotator.homing_flag = false;&lt;br /&gt;
                    } else if (buffer[0] == 'P' &amp;amp;&amp;amp; buffer[1] == 'A' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == 'R' &amp;amp;&amp;amp; buffer[3] == 'K' ) {&lt;br /&gt;
                        // Park the rotator&lt;br /&gt;
                        rotator.control_mode = position;&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        control_az.setpoint = rotator.park_az;&lt;br /&gt;
                        control_el.setpoint = rotator.park_el;&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'E') {&lt;br /&gt;
                        // Get the version if rotator controller&lt;br /&gt;
                        str1 = String(&amp;quot;VE&amp;quot;);&lt;br /&gt;
                        str2 = String(&amp;quot;SatNOGS-v2.2&amp;quot;);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '0') {&lt;br /&gt;
                        // Get the inside temperature&lt;br /&gt;
                        str1 = String(&amp;quot;IP0,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.inside_temperature, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '1') {&lt;br /&gt;
                        // Get the status of end-stop, azimuth&lt;br /&gt;
                        str1 = String(&amp;quot;IP1,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.switch_az, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '2') {&lt;br /&gt;
                        // Get the status of end-stop, elevation&lt;br /&gt;
                        str1 = String(&amp;quot;IP2,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.switch_el, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '3') {&lt;br /&gt;
                        // Get the current position of azimuth in deg&lt;br /&gt;
                        str1 = String(&amp;quot;IP3,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '4') {&lt;br /&gt;
                        // Get the current position of elevation in deg&lt;br /&gt;
                        str1 = String(&amp;quot;IP4,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.input, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '5') {&lt;br /&gt;
                        // Get the load of azimuth, in range of 0-1023&lt;br /&gt;
                        str1 = String(&amp;quot;IP5,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.load, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '6') {&lt;br /&gt;
                        // Get the load of elevation, in range of 0-1023&lt;br /&gt;
                        str1 = String(&amp;quot;IP6,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.load, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '7') {&lt;br /&gt;
                        // Get the speed of azimuth in deg/s&lt;br /&gt;
                        str1 = String(&amp;quot;IP7,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.speed, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '8') {&lt;br /&gt;
                        // Get the speed of elevation in deg/s&lt;br /&gt;
                        str1 = String(&amp;quot;IP8,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.speed, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'G' &amp;amp;&amp;amp; buffer[1] == 'S') {&lt;br /&gt;
                        // Get the status of rotator&lt;br /&gt;
                        str1 = String(&amp;quot;GS&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.rotator_status, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'G' &amp;amp;&amp;amp; buffer[1] == 'E') {&lt;br /&gt;
                        // Get the error of rotator&lt;br /&gt;
                        str1 = String(&amp;quot;GE&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.rotator_error, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if(buffer[0] == 'C' &amp;amp;&amp;amp; buffer[1] == 'R') {&lt;br /&gt;
                        // Get Configuration of rotator&lt;br /&gt;
                        if (buffer[3] == '1') {&lt;br /&gt;
                            // Get Kp Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;1,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.p, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '2') {&lt;br /&gt;
                            // Get Ki Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;2,&amp;quot;);&lt;br /&gt;
                             str2 = String(control_az.i, 2);&lt;br /&gt;
                             str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                             Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '3') {&lt;br /&gt;
                            // Get Kd Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;3,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.d, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '4') {&lt;br /&gt;
                            // Get Kp Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;4,&amp;quot;);&lt;br /&gt;
                             str2 = String(control_el.p, 2);&lt;br /&gt;
                             str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                             Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '5') {&lt;br /&gt;
                            // Get Ki Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;5,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_el.i, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '6') {&lt;br /&gt;
                            // Get Kd Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;6,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_el.d, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '7') {&lt;br /&gt;
                            // Get Azimuth park position&lt;br /&gt;
                            str1 = String(&amp;quot;7,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.park_az, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '8') {&lt;br /&gt;
                            // Get Elevation park position&lt;br /&gt;
                            str1 = String(&amp;quot;8,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.park_el, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '9') {&lt;br /&gt;
                            // Get control mode&lt;br /&gt;
                            str1 = String(&amp;quot;9,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.control_mode);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'C' &amp;amp;&amp;amp; buffer[1] == 'W') {&lt;br /&gt;
                        // Set Config&lt;br /&gt;
                        if (buffer[2] == '1') {&lt;br /&gt;
                            // Set Kp Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.p = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '2') {&lt;br /&gt;
                            // Set Ki Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.i = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '3') {&lt;br /&gt;
                            // Set Kd Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.d = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '4') {&lt;br /&gt;
                            // Set Kp Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.p = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '5') {&lt;br /&gt;
                            // Set Ki Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.i = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '6') {&lt;br /&gt;
                            // Set Kd Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.d = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        }  else if (buffer[2] == '7') {&lt;br /&gt;
                            // Set the Azimuth park position&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                rotator.park_az = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '8') {&lt;br /&gt;
                            // Set the Elevation park position&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                rotator.park_el = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'S'&lt;br /&gt;
                            &amp;amp;&amp;amp; buffer[2] == 'T') {&lt;br /&gt;
                        // Custom command to test the watchdog timer routine&lt;br /&gt;
                        while(1)&lt;br /&gt;
                            ;&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'B') {&lt;br /&gt;
                        // Custom command to reboot the uC&lt;br /&gt;
                        wdt_enable(WDTO_2S);&lt;br /&gt;
                        while(1);&lt;br /&gt;
                    }&lt;br /&gt;
                    // Reset the buffer an clean the serial buffer&lt;br /&gt;
                    BufferCnt = 0;&lt;br /&gt;
                    Serial.flush();&lt;br /&gt;
                } else {&lt;br /&gt;
                    // Fill the buffer with incoming data&lt;br /&gt;
                    buffer[BufferCnt] = incomingByte;&lt;br /&gt;
                    BufferCnt++;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    private:&lt;br /&gt;
        bool isNumber(char *input) {&lt;br /&gt;
            for (uint16_t i = 0; input[i] != '\0'; i++) {&lt;br /&gt;
                if (isalpha(input[i]))&lt;br /&gt;
                    return false;&lt;br /&gt;
            }&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    #endif /* LIBRARIES_EASYCOMM_H_ */&lt;br /&gt;
&lt;br /&gt;
===== Software to install =====&lt;br /&gt;
&lt;br /&gt;
Final pieces to the preparation work are to install a couple of pieces of software. firstly Hamlib. This will be used to communicate between GPredict and the Arduino. Secondly we will install the main prediction software, GPredict. We will not be going into detail about setup of GPredict but assume that you have followed the installation guide and had a play around with it so you can understand what it is and how it works.&lt;br /&gt;
&lt;br /&gt;
'''Install hamlib'''&lt;br /&gt;
&lt;br /&gt;
Download the [https://sourceforge.net/projects/hamlib/ Hamblib] software and follow the installation process. this may require you installing it with Administrator rights. using device manager find the port for the Arduino, for the purposes of this we will assume it is COM7&lt;br /&gt;
&lt;br /&gt;
Using a text editor, like Notepad++, to create a file with the code below in it. Note where COM7 is and amend with your own COM port. Save as a batch file (i.e. with th extension .bat file in the same folder as rotctld  (Usually found in C:\Program Files (x86)\hamlib-w64-3.2\bin )&lt;br /&gt;
 rotctld -m 202 -r COM7 -s 9600 -T 127.0.0.1 -t 4533 -C timeout=500 -C retry=0 -vvvvvvvv &amp;gt; pause&lt;br /&gt;
&lt;br /&gt;
'''Install GPredict'''&lt;br /&gt;
&lt;br /&gt;
Download and install [https://sourceforge.net/projects/gpredict/ GPredict]. Next we will need to add a rotator. Go to Edit &amp;gt; Preferences &amp;gt; Interfaces &amp;gt; Rotators &amp;gt; Add New&lt;br /&gt;
&lt;br /&gt;
Give it a name. For example Arduino. The port is localhost 4533&lt;br /&gt;
&lt;br /&gt;
That's it for setup. next we will test the system&lt;br /&gt;
&lt;br /&gt;
=== Testing ===&lt;br /&gt;
We will need to do a few things to get the system running. &lt;br /&gt;
&lt;br /&gt;
# Start the .bat file&lt;br /&gt;
# In GPredict open up the Antenna module and click Engage&lt;br /&gt;
# You should see that in the batch file output a series of commands being sent to the Arduino&lt;br /&gt;
# Check that both the Az and Ele work correctly by manually driving the rotator&lt;br /&gt;
&lt;br /&gt;
Occasionally this might not work first time. A restart of both hamlib and Gpredict worked &lt;br /&gt;
&lt;br /&gt;
=== Tweaks ===&lt;br /&gt;
There is a huge variety in parts that can get bought, here are a few tweaks that may be necessary.&lt;br /&gt;
&lt;br /&gt;
'''''Motors are turning the wrong way''''' - This may need the pins checking &lt;br /&gt;
&lt;br /&gt;
'''''It is only moving half the distance''''' - Change the gear ratio in the main sketch&lt;br /&gt;
&lt;br /&gt;
'''''The limit switches are not working''''' - Change the following code in the main sketch&lt;br /&gt;
 define DEFAULT_HOME_STATE LOW ///&amp;lt; Change to LOW according to Home sensor&lt;br /&gt;
&lt;br /&gt;
=== Operation ===&lt;br /&gt;
&lt;br /&gt;
Operating is as simple as selecting a satellite from GPredict and then selecting track. The rotator will then follow that satellite or object.f&lt;br /&gt;
&lt;br /&gt;
{{DEFAULTSORT:SatNOGS Arduino Uno CNC Shield Based Rotator Controller}}&lt;br /&gt;
__FORCETOC__&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=SatNOGS_Arduino_Uno/CNC_Shield_Based_Rotator_Controller&amp;diff=2650</id>
		<title>SatNOGS Arduino Uno/CNC Shield Based Rotator Controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=SatNOGS_Arduino_Uno/CNC_Shield_Based_Rotator_Controller&amp;diff=2650"/>
		<updated>2019-03-11T12:55:08Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: Further updates to develop the wiki&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:SatNOGS Arduino Uno CNC Shield Based Rotator Controller}}&lt;br /&gt;
&lt;br /&gt;
=== Controlling the rotator as a stand alone system using GPredict ===&lt;br /&gt;
The SatNOGS rotator is primarily designed to be used as a system component that is part of a SatNOGS ground station. There may be occasion when it is desirable to have a stand alone ground station that is removed from the SatNOGS network. This can be done using existing equipment but can also be simplified using off the shelf components.&lt;br /&gt;
&lt;br /&gt;
The following information is to connect your Rotator controller DIRECTLY TO A PC. If you'd like to still use it with the Raspberry Pi then you must keep the RS485 protocol in place.&lt;br /&gt;
&lt;br /&gt;
We will need slightly different hardware and modified software to achieve this, the main changes will be to remove the RS485 and watchdog parts of the firmware. We will be using the following items:&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
# SatNOGS Rotator V3.1 hardware&lt;br /&gt;
# Arduino Uno R3&lt;br /&gt;
# CNC Shield V3 with A4988 drivers&lt;br /&gt;
# NEMA 17 Stepper Motors&lt;br /&gt;
# 2x microswitches&lt;br /&gt;
# Suitable 12v power supply (The shield will accept between 12v and 36v)&lt;br /&gt;
# Cables to connect the Arduino to the PC&lt;br /&gt;
&lt;br /&gt;
==== Software ====&lt;br /&gt;
For the purposes of this article we will be using Windows software. The same result can be achieved with Linux or Mac OS but for clarity these options have been ignored for the time being. We will need:&lt;br /&gt;
# A copy of the Arduino IDE (version 1.8.5 has been used as part of this tutorial)&lt;br /&gt;
# GPredict&lt;br /&gt;
# Hamlib&lt;br /&gt;
# A text editor such as Notepad++ for a small script&lt;br /&gt;
&lt;br /&gt;
=== Method ===&lt;br /&gt;
&lt;br /&gt;
==== Hardware setup ====&lt;br /&gt;
We will not be using the custom SatNOGS PCB. Instead this set up uses an Arduino Uno and CNC motor shield. There is very little assembly required but depending on how and where you buy from will depend on the amount of assembly is required. Typically the Arduino will need no assembly, The motor shield will need two A4988 drivers (these can come as part of the package). These are used in the X &amp;amp; Y headers as per the photograph below. The drivers fit into the female headers, note that there are jumper headers below these drivers that are used for stepping control. We will also be attaching the stepper motor cables to the male headers to the left of the driver boards.&lt;br /&gt;
&lt;br /&gt;
Photo of board&lt;br /&gt;
&lt;br /&gt;
Pinout of the 4 headers is as follows starting from the top&lt;br /&gt;
&lt;br /&gt;
Pin 1 - A&lt;br /&gt;
&lt;br /&gt;
Pin 2 - A+&lt;br /&gt;
&lt;br /&gt;
Pin 3 - B&lt;br /&gt;
&lt;br /&gt;
Pin 4 - B+&lt;br /&gt;
&lt;br /&gt;
This follows a convention so most steppers should plug directly into the header without any changes, but be aware that this is not always the case and that there may be some cases where pins are incorrectly noted and the steppers will drive in the opposite direction.&lt;br /&gt;
&lt;br /&gt;
The setup is very basic but be careful not to bend pins as this can be easily done if too much pressure is put on the boards when things are no aligned. They aren't always perfect!&lt;br /&gt;
&lt;br /&gt;
In the end you should have:&lt;br /&gt;
* Azimuth Stepper Driver/motor connected to Y port on CNC Board&lt;br /&gt;
* Elevation Stepper Driver/motor connected to X port on CNC Board&lt;br /&gt;
* The End stop switch for elevation is connected to the X end stop on the CNC board (+ or -)&lt;br /&gt;
* The End stop switch for azimuth is connected to the Y end stop on the CNC board (+ or -)&lt;br /&gt;
&lt;br /&gt;
==== Software setup ====&lt;br /&gt;
&lt;br /&gt;
===== Code modifications =====&lt;br /&gt;
For the time being there is no fork of the firmware in the repositories. This may change in the future but for the time being a small series of changes are required to achieve results. We will need to modify two elements of the firmware, easycomm.h and rotator_pins.h. These changes are necessary to stop their being conflicts with the communication between boards and PC as well as re-assigning pins to match the CNC shield. We'll modify the rotator_pins.h first. Note the use of comments (//) to remove lines of code. We have also changed pin designation to match the shield.&lt;br /&gt;
&lt;br /&gt;
    /*!&lt;br /&gt;
    * @file rotator_pins.h&lt;br /&gt;
    *&lt;br /&gt;
    * It is a header file for pin mapping.&lt;br /&gt;
    *&lt;br /&gt;
    * Licensed under the GPLv3&lt;br /&gt;
    *&lt;br /&gt;
    */&lt;br /&gt;
&lt;br /&gt;
    #ifndef ROTATOR_PINS_H_&lt;br /&gt;
    #define ROTATOR_PINS_H_&lt;br /&gt;
&lt;br /&gt;
    //#define M1IN1 10 ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1IN1 2 ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1IN2 5  ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1SF  7  ///&amp;lt; Motor 1 digital input, status flag for DC Motor Drivers&lt;br /&gt;
    #define M1FB  A1 ///&amp;lt; Motor 1 analog input, current/load feedback for DC Motor Drivers&lt;br /&gt;
&lt;br /&gt;
    #define M2IN1 3 ///&amp;lt; Motor 2 PWM pin&lt;br /&gt;
    #define M2IN2 6  ///&amp;lt; Motor 2 PWM pin&lt;br /&gt;
    #define M2SF  7 ///&amp;lt; Motor 2 digital input, status flag for DC Motor Drivers&lt;br /&gt;
    #define M2FB  A0 ///&amp;lt; Motor 2 analog input, current/load feedback for DC Motor Drivers&lt;br /&gt;
&lt;br /&gt;
    #define MOTOR_EN 8 ///&amp;lt; Digital output, to enable the motors&lt;br /&gt;
&lt;br /&gt;
    #define SW1 11 ///&amp;lt; Digital input, to read the status of end-stop for motor 1&lt;br /&gt;
    #define SW2 9 ///&amp;lt; Digital input, to read the status of end-stop for motor 2&lt;br /&gt;
&lt;br /&gt;
    #define RS485_DIR 2 ///&amp;lt; Digital output, to set the direction of RS485 communication&lt;br /&gt;
&lt;br /&gt;
    #define SDA_PIN 3 ///&amp;lt; I2C data pin&lt;br /&gt;
    #define SCL_PIN 4 ///&amp;lt; I2C clock pin&lt;br /&gt;
&lt;br /&gt;
    #define PIN12 12 ///&amp;lt; General purpose I/O pin&lt;br /&gt;
    #define PIN13 13 ///&amp;lt; General purpose I/O pin&lt;br /&gt;
    #define A2    A2 ///&amp;lt; General purpose I/O &amp;amp; analog pin&lt;br /&gt;
    #define A3    A3 ///&amp;lt; General purpose I/O &amp;amp; analog pin&lt;br /&gt;
&lt;br /&gt;
    #endif /* ROTATOR_PINS_H_ */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The next code edit will remove both the RS485 and watchdog elements from the easycomm.h code. This will allow the PC to talk directly to the Arduino and as such bypass the RPi. The edited code is below, note again the use of comments (//) to remove the lines&lt;br /&gt;
    /*!&lt;br /&gt;
    * @file easycomm.h&lt;br /&gt;
    *&lt;br /&gt;
    * It is a driver for easycomm 3 protocol as referred, in Hamlib.&lt;br /&gt;
    *&lt;br /&gt;
    * Licensed under the GPLv3&lt;br /&gt;
    *&lt;br /&gt;
    */&lt;br /&gt;
&lt;br /&gt;
    #ifndef LIBRARIES_EASYCOMM_H_&lt;br /&gt;
    #define LIBRARIES_EASYCOMM_H_&lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;Arduino.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;WString.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;avr/wdt.h&amp;gt;&lt;br /&gt;
    //#include &amp;quot;rs485.h&amp;quot;&lt;br /&gt;
    #include &amp;quot;rotator_pins.h&amp;quot;&lt;br /&gt;
    #include &amp;quot;globals.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    #define RS485_TX_TIME 9     ///&amp;lt; Delay &amp;quot;t&amp;quot;ms to write in serial for RS485 implementation&lt;br /&gt;
    #define BUFFER_SIZE   256   ///&amp;lt; Set the size of serial buffer&lt;br /&gt;
    #define BAUDRATE      19200 ///&amp;lt; Set the Baudrate of easycomm 3 protocol&lt;br /&gt;
&lt;br /&gt;
    //rs485 rs485(RS485_DIR, RS485_TX_TIME);&lt;br /&gt;
&lt;br /&gt;
    /**************************************************************************/&lt;br /&gt;
    /*!&lt;br /&gt;
        @brief    Class that functions for easycomm 3 implementation&lt;br /&gt;
    */&lt;br /&gt;
    /**************************************************************************/&lt;br /&gt;
    class easycomm {&lt;br /&gt;
    public:&lt;br /&gt;
&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        /*!&lt;br /&gt;
            @brief    Initialize the RS485 bus&lt;br /&gt;
        */&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        void easycomm_init() {&lt;br /&gt;
           // rs485.begin(BAUDRATE);&lt;br /&gt;
    	    Serial.begin(9600);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        /*!&lt;br /&gt;
            @brief    Get the commands from RS485 and response to the client&lt;br /&gt;
        */&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        void easycomm_proc() {&lt;br /&gt;
            char buffer[BUFFER_SIZE];&lt;br /&gt;
            char incomingByte;&lt;br /&gt;
            char *Data = buffer;&lt;br /&gt;
            char *rawData;&lt;br /&gt;
            static uint16_t BufferCnt = 0;&lt;br /&gt;
            char data[100];&lt;br /&gt;
            String str1, str2, str3, str4, str5, str6;&lt;br /&gt;
&lt;br /&gt;
            // Read from serial&lt;br /&gt;
            while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
                incomingByte = Serial.read();&lt;br /&gt;
&lt;br /&gt;
                // Read new data, '\n' means new pacakage&lt;br /&gt;
                if (incomingByte == '\n' || incomingByte == '\r') {&lt;br /&gt;
                    buffer[BufferCnt] = 0;&lt;br /&gt;
                    if (buffer[0] == 'A' &amp;amp;&amp;amp; buffer[1] == 'Z') {&lt;br /&gt;
                        if (buffer[2] == ' ' &amp;amp;&amp;amp; buffer[3] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                            buffer[4] == 'L') {&lt;br /&gt;
                            // Send current absolute position in deg&lt;br /&gt;
                            str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.input, 1);&lt;br /&gt;
                            str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                            str4 = String(control_el.input, 1);&lt;br /&gt;
                            str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            // Get the absolute position in deg for azimuth&lt;br /&gt;
                            rotator.control_mode = position;&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 2, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.setpoint = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                            // Get the absolute position in deg for elevation&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            if (rawData[0] == 'E' &amp;amp;&amp;amp; rawData[1] == 'L') {&lt;br /&gt;
                                strncpy(data, rawData + 2, 10);&lt;br /&gt;
                                if (isNumber(data)) {&lt;br /&gt;
                                    control_el.setpoint = atof(data);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'E' &amp;amp;&amp;amp; buffer[1] == 'L') {&lt;br /&gt;
                            // Get the absolute position in deg for elevation&lt;br /&gt;
                            rotator.control_mode = position;&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            if (rawData[0] == 'E' &amp;amp;&amp;amp; rawData[1] == 'L') {&lt;br /&gt;
                                strncpy(data, rawData + 2, 10);&lt;br /&gt;
                                if (isNumber(data)) {&lt;br /&gt;
                                    control_el.setpoint = atof(data);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'U') {&lt;br /&gt;
                        // Elevation increase speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_el.setpoint_speed = atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'D') {&lt;br /&gt;
                        // Elevation decrease speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_el.setpoint_speed = - atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'L') {&lt;br /&gt;
                        // Azimuth increase speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_az.setpoint_speed = atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'R') {&lt;br /&gt;
                        // Azimuth decrease speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_az.setpoint_speed = - atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'S' &amp;amp;&amp;amp; buffer[1] == 'A' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == ' ' &amp;amp;&amp;amp; buffer[3] == 'S' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[4] == 'E') {&lt;br /&gt;
                        // Stop Moving&lt;br /&gt;
                        rotator.control_mode = position;&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        control_az.setpoint = control_az.input;&lt;br /&gt;
                        control_el.setpoint = control_el.input;&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == 'S' &amp;amp;&amp;amp; buffer[3] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[4] == 'T') {&lt;br /&gt;
                        // Reset the rotator, go to home position&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        rotator.homing_flag = false;&lt;br /&gt;
                    } else if (buffer[0] == 'P' &amp;amp;&amp;amp; buffer[1] == 'A' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == 'R' &amp;amp;&amp;amp; buffer[3] == 'K' ) {&lt;br /&gt;
                        // Park the rotator&lt;br /&gt;
                        rotator.control_mode = position;&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        control_az.setpoint = rotator.park_az;&lt;br /&gt;
                        control_el.setpoint = rotator.park_el;&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'E') {&lt;br /&gt;
                        // Get the version if rotator controller&lt;br /&gt;
                        str1 = String(&amp;quot;VE&amp;quot;);&lt;br /&gt;
                        str2 = String(&amp;quot;SatNOGS-v2.2&amp;quot;);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '0') {&lt;br /&gt;
                        // Get the inside temperature&lt;br /&gt;
                        str1 = String(&amp;quot;IP0,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.inside_temperature, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '1') {&lt;br /&gt;
                        // Get the status of end-stop, azimuth&lt;br /&gt;
                        str1 = String(&amp;quot;IP1,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.switch_az, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '2') {&lt;br /&gt;
                        // Get the status of end-stop, elevation&lt;br /&gt;
                        str1 = String(&amp;quot;IP2,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.switch_el, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '3') {&lt;br /&gt;
                        // Get the current position of azimuth in deg&lt;br /&gt;
                        str1 = String(&amp;quot;IP3,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '4') {&lt;br /&gt;
                        // Get the current position of elevation in deg&lt;br /&gt;
                        str1 = String(&amp;quot;IP4,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.input, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '5') {&lt;br /&gt;
                        // Get the load of azimuth, in range of 0-1023&lt;br /&gt;
                        str1 = String(&amp;quot;IP5,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.load, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '6') {&lt;br /&gt;
                        // Get the load of elevation, in range of 0-1023&lt;br /&gt;
                        str1 = String(&amp;quot;IP6,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.load, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '7') {&lt;br /&gt;
                        // Get the speed of azimuth in deg/s&lt;br /&gt;
                        str1 = String(&amp;quot;IP7,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.speed, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '8') {&lt;br /&gt;
                        // Get the speed of elevation in deg/s&lt;br /&gt;
                        str1 = String(&amp;quot;IP8,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.speed, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'G' &amp;amp;&amp;amp; buffer[1] == 'S') {&lt;br /&gt;
                        // Get the status of rotator&lt;br /&gt;
                        str1 = String(&amp;quot;GS&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.rotator_status, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'G' &amp;amp;&amp;amp; buffer[1] == 'E') {&lt;br /&gt;
                        // Get the error of rotator&lt;br /&gt;
                        str1 = String(&amp;quot;GE&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.rotator_error, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if(buffer[0] == 'C' &amp;amp;&amp;amp; buffer[1] == 'R') {&lt;br /&gt;
                        // Get Configuration of rotator&lt;br /&gt;
                        if (buffer[3] == '1') {&lt;br /&gt;
                            // Get Kp Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;1,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.p, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '2') {&lt;br /&gt;
                            // Get Ki Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;2,&amp;quot;);&lt;br /&gt;
                             str2 = String(control_az.i, 2);&lt;br /&gt;
                             str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                             Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '3') {&lt;br /&gt;
                            // Get Kd Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;3,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.d, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '4') {&lt;br /&gt;
                            // Get Kp Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;4,&amp;quot;);&lt;br /&gt;
                             str2 = String(control_el.p, 2);&lt;br /&gt;
                             str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                             Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '5') {&lt;br /&gt;
                            // Get Ki Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;5,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_el.i, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '6') {&lt;br /&gt;
                            // Get Kd Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;6,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_el.d, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '7') {&lt;br /&gt;
                            // Get Azimuth park position&lt;br /&gt;
                            str1 = String(&amp;quot;7,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.park_az, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '8') {&lt;br /&gt;
                            // Get Elevation park position&lt;br /&gt;
                            str1 = String(&amp;quot;8,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.park_el, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '9') {&lt;br /&gt;
                            // Get control mode&lt;br /&gt;
                            str1 = String(&amp;quot;9,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.control_mode);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'C' &amp;amp;&amp;amp; buffer[1] == 'W') {&lt;br /&gt;
                        // Set Config&lt;br /&gt;
                        if (buffer[2] == '1') {&lt;br /&gt;
                            // Set Kp Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.p = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '2') {&lt;br /&gt;
                            // Set Ki Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.i = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '3') {&lt;br /&gt;
                            // Set Kd Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.d = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '4') {&lt;br /&gt;
                            // Set Kp Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.p = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '5') {&lt;br /&gt;
                            // Set Ki Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.i = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '6') {&lt;br /&gt;
                            // Set Kd Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.d = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        }  else if (buffer[2] == '7') {&lt;br /&gt;
                            // Set the Azimuth park position&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                rotator.park_az = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '8') {&lt;br /&gt;
                            // Set the Elevation park position&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                rotator.park_el = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'S'&lt;br /&gt;
                            &amp;amp;&amp;amp; buffer[2] == 'T') {&lt;br /&gt;
                        // Custom command to test the watchdog timer routine&lt;br /&gt;
                        while(1)&lt;br /&gt;
                            ;&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'B') {&lt;br /&gt;
                        // Custom command to reboot the uC&lt;br /&gt;
                        wdt_enable(WDTO_2S);&lt;br /&gt;
                        while(1);&lt;br /&gt;
                    }&lt;br /&gt;
                    // Reset the buffer an clean the serial buffer&lt;br /&gt;
                    BufferCnt = 0;&lt;br /&gt;
                    Serial.flush();&lt;br /&gt;
                } else {&lt;br /&gt;
                    // Fill the buffer with incoming data&lt;br /&gt;
                    buffer[BufferCnt] = incomingByte;&lt;br /&gt;
                    BufferCnt++;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    private:&lt;br /&gt;
        bool isNumber(char *input) {&lt;br /&gt;
            for (uint16_t i = 0; input[i] != '\0'; i++) {&lt;br /&gt;
                if (isalpha(input[i]))&lt;br /&gt;
                    return false;&lt;br /&gt;
            }&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    #endif /* LIBRARIES_EASYCOMM_H_ */&lt;br /&gt;
&lt;br /&gt;
===== Software to install =====&lt;br /&gt;
&lt;br /&gt;
Final pieces to the preparation work are to install a couple of pieces of software. firstly Hamlib. This will be used to communicate between GPredict and the Arduino. Secondly we will install the main prediction software, GPredict. We will not be going into detail about setup of GPredict but assume that you have followed the installation guide and had a play around with it so you can understand what it is and how it works.&lt;br /&gt;
&lt;br /&gt;
'''Install hamlib'''&lt;br /&gt;
&lt;br /&gt;
Download the software and follow the installation process. this may require you installing it with Administrator rights. using device manager find the port for the Arduino, for the purposes of this we will assume it is COM7&lt;br /&gt;
&lt;br /&gt;
Install Hamlib:  https://sourceforge.net/projects/hamlib/&lt;br /&gt;
&lt;br /&gt;
create a .bat file in the same folder as rotctld  (I found it in C:\Program Files (x86)\hamlib-w64-3.2\bin )&lt;br /&gt;
with the following (modify for your com port)&lt;br /&gt;
 rotctld -m 202 -r COM7 -s 9600 -T 127.0.0.1 -t 4533 -C timeout=500 -C retry=0 -vvvvvvvv &amp;gt; pause&lt;br /&gt;
&lt;br /&gt;
Download Gpredict  https://sourceforge.net/projects/gpredict/&lt;br /&gt;
&lt;br /&gt;
Edit...Preferences...Interfaces...Rotators...Add New&lt;br /&gt;
Name        host            port&lt;br /&gt;
Arduino    localhost     4533&lt;br /&gt;
&lt;br /&gt;
Start your .bat,   in the top right corner of Gpredict, click down arrow, then 'Antenna Control'&lt;br /&gt;
&lt;br /&gt;
...Clicking 'Engage'  should get the Rotator to start working.&lt;br /&gt;
&lt;br /&gt;
Once you have configured some satellites you can them select them and click 'Track'&lt;br /&gt;
&lt;br /&gt;
=== Testing ===&lt;br /&gt;
&lt;br /&gt;
=== Tweaks ===&lt;br /&gt;
There is a huge variety in parts that can get bought, here are a few tweaks that may be necessary.&lt;br /&gt;
&lt;br /&gt;
'''''Motors are turning the wrong way''''' - This may need the pins checking &lt;br /&gt;
&lt;br /&gt;
'''''It is only moving half the distance''''' - Change the gear ratio in the main sketch&lt;br /&gt;
&lt;br /&gt;
'''''The limit switches are not working''''' - Change the following code in the main sketch&lt;br /&gt;
 define DEFAULT_HOME_STATE LOW ///&amp;lt; Change to LOW according to Home sensor&lt;br /&gt;
&lt;br /&gt;
=== Operation ===&lt;br /&gt;
{{DEFAULTSORT:SatNOGS Arduino Uno CNC Shield Based Rotator Controller}}&lt;br /&gt;
__FORCETOC__&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=SatNOGS_Arduino_Uno/CNC_Shield_Based_Rotator_Controller&amp;diff=2649</id>
		<title>SatNOGS Arduino Uno/CNC Shield Based Rotator Controller</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=SatNOGS_Arduino_Uno/CNC_Shield_Based_Rotator_Controller&amp;diff=2649"/>
		<updated>2019-03-10T19:28:36Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: Edit to change language from post to wiki page.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:SatNOGS Arduino Uno CNC Shield Based Rotator Controller}}&lt;br /&gt;
&lt;br /&gt;
=== Controlling the rotator as a stand alone system using GPredict ===&lt;br /&gt;
The SatNOGS rotator is primarily designed to be used as a system component that is part of a SatNOGS ground station. There may be occasion when it is desirable to have a stand alone ground station that is removed from the SatNOGS network. This can be done using existing equipment but can also be simplified using off the shelf components.&lt;br /&gt;
&lt;br /&gt;
The following information is to connect your Rotator controller DIRECTLY TO A PC. If you'd like to still use it with the Raspberry Pi then you must keep the RS485 protocol in place.&lt;br /&gt;
&lt;br /&gt;
We will need slightly different hardware and modified software to achieve this, the main changes will be to remove the RS485 and watchdog parts of the firmware. We will be using the following items:&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
# SatNOGS Rotator V3.1 hardware&lt;br /&gt;
# Arduino Uno R3&lt;br /&gt;
# CNC Shield V3 with A4988 drivers&lt;br /&gt;
# NEMA 17 Stepper Motors&lt;br /&gt;
# 2x microswitches&lt;br /&gt;
# Suitable 12v power supply (The shield will accept between 12v and 36v)&lt;br /&gt;
# Cables to connect the Arduino to the PC&lt;br /&gt;
&lt;br /&gt;
==== Software ====&lt;br /&gt;
For the purposes of this article we will be using Windows software. The same result can be achieved with Linux or Mac OS but for clarity these options have been ignored for the time being. We will need:&lt;br /&gt;
# A copy of the Arduino IDE (version 1.8.5 has been used as part of this tutorial)&lt;br /&gt;
# GPredict&lt;br /&gt;
# Hamlib&lt;br /&gt;
# A text editor such as Notepad++ for a small script&lt;br /&gt;
&lt;br /&gt;
=== Method ===&lt;br /&gt;
&lt;br /&gt;
==== Hardware setup ====&lt;br /&gt;
We will not be using the custom SatNOGS PCB&lt;br /&gt;
&lt;br /&gt;
==== Software setup ====&lt;br /&gt;
We will need to modify two elements of the firmware, easycomm.h and rotator_pins.h. These changes are necessary to stop their being conflicts with the communication between boards and PC as well as re-assigning pins to match the CNC shield. We'll modify the rotator_pins.h first &lt;br /&gt;
&lt;br /&gt;
I'm not using the custom SatNOGS pcb. I'm using a standard Arduino Uno with a CNC shield with A4988's, which has GREATLY simplified the project as they're all off the shelf, preassembled, inexpensive components... The Uno, stepper drivers, stepper motors, and shield came to about $60CAD on Amazon Prime, and electronically everything was working within an hour of the parts showing up.&lt;br /&gt;
In order to do this I've made a few tweaks to the code to take advantage of parts I already have laying around...&lt;br /&gt;
I'm using:&lt;br /&gt;
Arduino Uno R3 clone&lt;br /&gt;
Arduino CNC Shield V3 with 4x A4988's (only 2 in use) https://www.amazon.ca/gp/product/B016O7TD6O/ref=ppx_yo_dt_b_asin_title_o00__o00_s00?ie=UTF8&amp;amp;psc=1&lt;br /&gt;
Nema 17 Stepper Motors&lt;br /&gt;
https://www.amazon.ca/gp/product/B06ZXQXD9X/ref=ppx_yo_dt_b_asin_title_o01__o00_s00?ie=UTF8&amp;amp;th=1&lt;br /&gt;
Gpredict on Windows 10 PC&lt;br /&gt;
Rotctl&lt;br /&gt;
          &lt;br /&gt;
Currently I've modified easycomms.h to use Serial communications instead of RS485, which lets you connect the arduino to the pc directly without any adapter cables or modifications.  I plan on adding the SatNOGS Pi Groundstation at a later time, my primary goal is to track satellites to enable capturing of HRPT.&lt;br /&gt;
&lt;br /&gt;
I also had to modify the rotator_pins.h library to fix a few of the pinouts which changed when I used the CNC shield.&lt;br /&gt;
&lt;br /&gt;
Here's the pinout thats working  for me at the moment. &lt;br /&gt;
    /*!&lt;br /&gt;
    * @file rotator_pins.h&lt;br /&gt;
    *&lt;br /&gt;
    * It is a header file for pin mapping.&lt;br /&gt;
    *&lt;br /&gt;
    * Licensed under the GPLv3&lt;br /&gt;
    *&lt;br /&gt;
    */&lt;br /&gt;
&lt;br /&gt;
    #ifndef ROTATOR_PINS_H_&lt;br /&gt;
    #define ROTATOR_PINS_H_&lt;br /&gt;
&lt;br /&gt;
    //#define M1IN1 10 ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1IN1 2 ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1IN2 5  ///&amp;lt; Motor 1 PWM pin&lt;br /&gt;
    #define M1SF  7  ///&amp;lt; Motor 1 digital input, status flag for DC Motor Drivers&lt;br /&gt;
    #define M1FB  A1 ///&amp;lt; Motor 1 analog input, current/load feedback for DC Motor Drivers&lt;br /&gt;
&lt;br /&gt;
    #define M2IN1 3 ///&amp;lt; Motor 2 PWM pin&lt;br /&gt;
    #define M2IN2 6  ///&amp;lt; Motor 2 PWM pin&lt;br /&gt;
    #define M2SF  7 ///&amp;lt; Motor 2 digital input, status flag for DC Motor Drivers&lt;br /&gt;
    #define M2FB  A0 ///&amp;lt; Motor 2 analog input, current/load feedback for DC Motor Drivers&lt;br /&gt;
&lt;br /&gt;
    #define MOTOR_EN 8 ///&amp;lt; Digital output, to enable the motors&lt;br /&gt;
&lt;br /&gt;
    #define SW1 11 ///&amp;lt; Digital input, to read the status of end-stop for motor 1&lt;br /&gt;
    #define SW2 9 ///&amp;lt; Digital input, to read the status of end-stop for motor 2&lt;br /&gt;
&lt;br /&gt;
    #define RS485_DIR 2 ///&amp;lt; Digital output, to set the direction of RS485 communication&lt;br /&gt;
&lt;br /&gt;
    #define SDA_PIN 3 ///&amp;lt; I2C data pin&lt;br /&gt;
    #define SCL_PIN 4 ///&amp;lt; I2C clock pin&lt;br /&gt;
&lt;br /&gt;
    #define PIN12 12 ///&amp;lt; General purpose I/O pin&lt;br /&gt;
    #define PIN13 13 ///&amp;lt; General purpose I/O pin&lt;br /&gt;
    #define A2    A2 ///&amp;lt; General purpose I/O &amp;amp; analog pin&lt;br /&gt;
    #define A3    A3 ///&amp;lt; General purpose I/O &amp;amp; analog pin&lt;br /&gt;
&lt;br /&gt;
    #endif /* ROTATOR_PINS_H_ */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This will  setup the arduino to talk directly to the PC and bypass the Pi completely..... I can connect the Arduino directly to my PC and control it via Gpredict.&lt;br /&gt;
&lt;br /&gt;
I did this by editing the easycomm.h file.  I basically removed every call to the RS485 library (which allows communications between the Pi and the Arduino directly) and replaced each 'rs485'  with 'Serial'  instead.... &lt;br /&gt;
&lt;br /&gt;
here's the edited easycomm.h file so that you can use the arduino sketch directly with gpredict and a PC.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /*!&lt;br /&gt;
    * @file easycomm.h&lt;br /&gt;
    *&lt;br /&gt;
    * It is a driver for easycomm 3 protocol as referred, in Hamlib.&lt;br /&gt;
    *&lt;br /&gt;
    * Licensed under the GPLv3&lt;br /&gt;
    *&lt;br /&gt;
    */&lt;br /&gt;
&lt;br /&gt;
    #ifndef LIBRARIES_EASYCOMM_H_&lt;br /&gt;
    #define LIBRARIES_EASYCOMM_H_&lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;Arduino.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;WString.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;avr/wdt.h&amp;gt;&lt;br /&gt;
    //#include &amp;quot;rs485.h&amp;quot;&lt;br /&gt;
    #include &amp;quot;rotator_pins.h&amp;quot;&lt;br /&gt;
    #include &amp;quot;globals.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    #define RS485_TX_TIME 9     ///&amp;lt; Delay &amp;quot;t&amp;quot;ms to write in serial for RS485 implementation&lt;br /&gt;
    #define BUFFER_SIZE   256   ///&amp;lt; Set the size of serial buffer&lt;br /&gt;
    #define BAUDRATE      19200 ///&amp;lt; Set the Baudrate of easycomm 3 protocol&lt;br /&gt;
&lt;br /&gt;
    //rs485 rs485(RS485_DIR, RS485_TX_TIME);&lt;br /&gt;
&lt;br /&gt;
    /**************************************************************************/&lt;br /&gt;
    /*!&lt;br /&gt;
        @brief    Class that functions for easycomm 3 implementation&lt;br /&gt;
    */&lt;br /&gt;
    /**************************************************************************/&lt;br /&gt;
    class easycomm {&lt;br /&gt;
    public:&lt;br /&gt;
&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        /*!&lt;br /&gt;
            @brief    Initialize the RS485 bus&lt;br /&gt;
        */&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        void easycomm_init() {&lt;br /&gt;
           // rs485.begin(BAUDRATE);&lt;br /&gt;
    	    Serial.begin(9600);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        /*!&lt;br /&gt;
            @brief    Get the commands from RS485 and response to the client&lt;br /&gt;
        */&lt;br /&gt;
        /**************************************************************************/&lt;br /&gt;
        void easycomm_proc() {&lt;br /&gt;
            char buffer[BUFFER_SIZE];&lt;br /&gt;
            char incomingByte;&lt;br /&gt;
            char *Data = buffer;&lt;br /&gt;
            char *rawData;&lt;br /&gt;
            static uint16_t BufferCnt = 0;&lt;br /&gt;
            char data[100];&lt;br /&gt;
            String str1, str2, str3, str4, str5, str6;&lt;br /&gt;
&lt;br /&gt;
            // Read from serial&lt;br /&gt;
            while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
                incomingByte = Serial.read();&lt;br /&gt;
&lt;br /&gt;
                // Read new data, '\n' means new pacakage&lt;br /&gt;
                if (incomingByte == '\n' || incomingByte == '\r') {&lt;br /&gt;
                    buffer[BufferCnt] = 0;&lt;br /&gt;
                    if (buffer[0] == 'A' &amp;amp;&amp;amp; buffer[1] == 'Z') {&lt;br /&gt;
                        if (buffer[2] == ' ' &amp;amp;&amp;amp; buffer[3] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                            buffer[4] == 'L') {&lt;br /&gt;
                            // Send current absolute position in deg&lt;br /&gt;
                            str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.input, 1);&lt;br /&gt;
                            str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                            str4 = String(control_el.input, 1);&lt;br /&gt;
                            str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        } else {&lt;br /&gt;
                            // Get the absolute position in deg for azimuth&lt;br /&gt;
                            rotator.control_mode = position;&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 2, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.setpoint = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                            // Get the absolute position in deg for elevation&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            if (rawData[0] == 'E' &amp;amp;&amp;amp; rawData[1] == 'L') {&lt;br /&gt;
                                strncpy(data, rawData + 2, 10);&lt;br /&gt;
                                if (isNumber(data)) {&lt;br /&gt;
                                    control_el.setpoint = atof(data);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'E' &amp;amp;&amp;amp; buffer[1] == 'L') {&lt;br /&gt;
                            // Get the absolute position in deg for elevation&lt;br /&gt;
                            rotator.control_mode = position;&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot; &amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            if (rawData[0] == 'E' &amp;amp;&amp;amp; rawData[1] == 'L') {&lt;br /&gt;
                                strncpy(data, rawData + 2, 10);&lt;br /&gt;
                                if (isNumber(data)) {&lt;br /&gt;
                                    control_el.setpoint = atof(data);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'U') {&lt;br /&gt;
                        // Elevation increase speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_el.setpoint_speed = atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'D') {&lt;br /&gt;
                        // Elevation decrease speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_el.setpoint_speed = - atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'L') {&lt;br /&gt;
                        // Azimuth increase speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_az.setpoint_speed = atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'R') {&lt;br /&gt;
                        // Azimuth decrease speed in mdeg/s&lt;br /&gt;
                        rotator.control_mode = speed;&lt;br /&gt;
                        strncpy(data, Data + 2, 10);&lt;br /&gt;
                        if (isNumber(data)) {&lt;br /&gt;
                            // Convert to deg/s&lt;br /&gt;
                            control_az.setpoint_speed = - atof(data) / 1000;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'S' &amp;amp;&amp;amp; buffer[1] == 'A' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == ' ' &amp;amp;&amp;amp; buffer[3] == 'S' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[4] == 'E') {&lt;br /&gt;
                        // Stop Moving&lt;br /&gt;
                        rotator.control_mode = position;&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        control_az.setpoint = control_az.input;&lt;br /&gt;
                        control_el.setpoint = control_el.input;&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == 'S' &amp;amp;&amp;amp; buffer[3] == 'E' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[4] == 'T') {&lt;br /&gt;
                        // Reset the rotator, go to home position&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        rotator.homing_flag = false;&lt;br /&gt;
                    } else if (buffer[0] == 'P' &amp;amp;&amp;amp; buffer[1] == 'A' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == 'R' &amp;amp;&amp;amp; buffer[3] == 'K' ) {&lt;br /&gt;
                        // Park the rotator&lt;br /&gt;
                        rotator.control_mode = position;&lt;br /&gt;
                        str1 = String(&amp;quot;AZ&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 1);&lt;br /&gt;
                        str3 = String(&amp;quot; EL&amp;quot;);&lt;br /&gt;
                        str4 = String(control_el.input, 1);&lt;br /&gt;
                        str5 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3 + str4 + str5);&lt;br /&gt;
                        control_az.setpoint = rotator.park_az;&lt;br /&gt;
                        control_el.setpoint = rotator.park_el;&lt;br /&gt;
                    } else if (buffer[0] == 'V' &amp;amp;&amp;amp; buffer[1] == 'E') {&lt;br /&gt;
                        // Get the version if rotator controller&lt;br /&gt;
                        str1 = String(&amp;quot;VE&amp;quot;);&lt;br /&gt;
                        str2 = String(&amp;quot;SatNOGS-v2.2&amp;quot;);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '0') {&lt;br /&gt;
                        // Get the inside temperature&lt;br /&gt;
                        str1 = String(&amp;quot;IP0,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.inside_temperature, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '1') {&lt;br /&gt;
                        // Get the status of end-stop, azimuth&lt;br /&gt;
                        str1 = String(&amp;quot;IP1,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.switch_az, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '2') {&lt;br /&gt;
                        // Get the status of end-stop, elevation&lt;br /&gt;
                        str1 = String(&amp;quot;IP2,&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.switch_el, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '3') {&lt;br /&gt;
                        // Get the current position of azimuth in deg&lt;br /&gt;
                        str1 = String(&amp;quot;IP3,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.input, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '4') {&lt;br /&gt;
                        // Get the current position of elevation in deg&lt;br /&gt;
                        str1 = String(&amp;quot;IP4,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.input, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '5') {&lt;br /&gt;
                        // Get the load of azimuth, in range of 0-1023&lt;br /&gt;
                        str1 = String(&amp;quot;IP5,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.load, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '6') {&lt;br /&gt;
                        // Get the load of elevation, in range of 0-1023&lt;br /&gt;
                        str1 = String(&amp;quot;IP6,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.load, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '7') {&lt;br /&gt;
                        // Get the speed of azimuth in deg/s&lt;br /&gt;
                        str1 = String(&amp;quot;IP7,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_az.speed, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'I' &amp;amp;&amp;amp; buffer[1] == 'P' &amp;amp;&amp;amp;&lt;br /&gt;
                               buffer[2] == '8') {&lt;br /&gt;
                        // Get the speed of elevation in deg/s&lt;br /&gt;
                        str1 = String(&amp;quot;IP8,&amp;quot;);&lt;br /&gt;
                        str2 = String(control_el.speed, 2);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'G' &amp;amp;&amp;amp; buffer[1] == 'S') {&lt;br /&gt;
                        // Get the status of rotator&lt;br /&gt;
                        str1 = String(&amp;quot;GS&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.rotator_status, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if (buffer[0] == 'G' &amp;amp;&amp;amp; buffer[1] == 'E') {&lt;br /&gt;
                        // Get the error of rotator&lt;br /&gt;
                        str1 = String(&amp;quot;GE&amp;quot;);&lt;br /&gt;
                        str2 = String(rotator.rotator_error, DEC);&lt;br /&gt;
                        str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                        Serial.print(str1 + str2 + str3);&lt;br /&gt;
                    } else if(buffer[0] == 'C' &amp;amp;&amp;amp; buffer[1] == 'R') {&lt;br /&gt;
                        // Get Configuration of rotator&lt;br /&gt;
                        if (buffer[3] == '1') {&lt;br /&gt;
                            // Get Kp Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;1,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.p, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '2') {&lt;br /&gt;
                            // Get Ki Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;2,&amp;quot;);&lt;br /&gt;
                             str2 = String(control_az.i, 2);&lt;br /&gt;
                             str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                             Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '3') {&lt;br /&gt;
                            // Get Kd Azimuth gain&lt;br /&gt;
                            str1 = String(&amp;quot;3,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_az.d, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '4') {&lt;br /&gt;
                            // Get Kp Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;4,&amp;quot;);&lt;br /&gt;
                             str2 = String(control_el.p, 2);&lt;br /&gt;
                             str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                             Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '5') {&lt;br /&gt;
                            // Get Ki Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;5,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_el.i, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '6') {&lt;br /&gt;
                            // Get Kd Elevation gain&lt;br /&gt;
                            str1 = String(&amp;quot;6,&amp;quot;);&lt;br /&gt;
                            str2 = String(control_el.d, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '7') {&lt;br /&gt;
                            // Get Azimuth park position&lt;br /&gt;
                            str1 = String(&amp;quot;7,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.park_az, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '8') {&lt;br /&gt;
                            // Get Elevation park position&lt;br /&gt;
                            str1 = String(&amp;quot;8,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.park_el, 2);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        } else if (buffer[3] == '9') {&lt;br /&gt;
                            // Get control mode&lt;br /&gt;
                            str1 = String(&amp;quot;9,&amp;quot;);&lt;br /&gt;
                            str2 = String(rotator.control_mode);&lt;br /&gt;
                            str3 = String(&amp;quot;\n&amp;quot;);&lt;br /&gt;
                            Serial.print(str1 + str2 + str3);&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'C' &amp;amp;&amp;amp; buffer[1] == 'W') {&lt;br /&gt;
                        // Set Config&lt;br /&gt;
                        if (buffer[2] == '1') {&lt;br /&gt;
                            // Set Kp Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.p = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '2') {&lt;br /&gt;
                            // Set Ki Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.i = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '3') {&lt;br /&gt;
                            // Set Kd Azimuth gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_az.d = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '4') {&lt;br /&gt;
                            // Set Kp Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.p = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '5') {&lt;br /&gt;
                            // Set Ki Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.i = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '6') {&lt;br /&gt;
                            // Set Kd Elevation gain&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                control_el.d = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        }  else if (buffer[2] == '7') {&lt;br /&gt;
                            // Set the Azimuth park position&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                rotator.park_az = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        } else if (buffer[2] == '8') {&lt;br /&gt;
                            // Set the Elevation park position&lt;br /&gt;
                            rawData = strtok_r(Data, &amp;quot;,&amp;quot;, &amp;amp;Data);&lt;br /&gt;
                            strncpy(data, rawData + 4, 10);&lt;br /&gt;
                            if (isNumber(data)) {&lt;br /&gt;
                                rotator.park_el = atof(data);&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'S'&lt;br /&gt;
                            &amp;amp;&amp;amp; buffer[2] == 'T') {&lt;br /&gt;
                        // Custom command to test the watchdog timer routine&lt;br /&gt;
                        while(1)&lt;br /&gt;
                            ;&lt;br /&gt;
                    } else if (buffer[0] == 'R' &amp;amp;&amp;amp; buffer[1] == 'B') {&lt;br /&gt;
                        // Custom command to reboot the uC&lt;br /&gt;
                        wdt_enable(WDTO_2S);&lt;br /&gt;
                        while(1);&lt;br /&gt;
                    }&lt;br /&gt;
                    // Reset the buffer an clean the serial buffer&lt;br /&gt;
                    BufferCnt = 0;&lt;br /&gt;
                    Serial.flush();&lt;br /&gt;
                } else {&lt;br /&gt;
                    // Fill the buffer with incoming data&lt;br /&gt;
                    buffer[BufferCnt] = incomingByte;&lt;br /&gt;
                    BufferCnt++;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    private:&lt;br /&gt;
        bool isNumber(char *input) {&lt;br /&gt;
            for (uint16_t i = 0; input[i] != '\0'; i++) {&lt;br /&gt;
                if (isalpha(input[i]))&lt;br /&gt;
                    return false;&lt;br /&gt;
            }&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    #endif /* LIBRARIES_EASYCOMM_H_ */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Other things I had to do to make my modified rotator work properly:&lt;br /&gt;
&lt;br /&gt;
reverse the direction of the elevation axis. This was accomplished by swapping two of the wires going to the servo motor (swap the wires going to one of the coils)&lt;br /&gt;
&lt;br /&gt;
At first, it was only moving half as far as each command (if i asked for 180 rotation, it would do 90, if i asked for 80 elevation, it would do 40). Changing the Gear Ratio to 108 from the default 54 fixed this… I’m not sure if this was the proper way to do it, but it seems to work well. I have a feeling my microstepping jumpers might not be set the same as in the sketch (I have all my jumpers in to enable the highest microstepping). You could change the microsteps in the sketch, but there seems to be a lot of other variables which rely on it and might need to be modified to make that change? It seemed easier to just double the gear ratio, and it behaves as expected now? I might tweak that.&lt;br /&gt;
#define RATIO 108 ///&amp;lt; Gear ratio of rotator gear box default 54&lt;br /&gt;
&lt;br /&gt;
Azimuth Stepper Driver/motor connected to Y port on CNC Board&lt;br /&gt;
&lt;br /&gt;
Elevation Stepper Driver/motor connected to X port on CNC Board&lt;br /&gt;
&lt;br /&gt;
The End stop switch for elevation is connected to the X end stop on the CNC board (+ or -)&lt;br /&gt;
&lt;br /&gt;
The End stop switch for azimuth is connected to the Z end stop on the CNC board (+ or -)&lt;br /&gt;
&lt;br /&gt;
I also had to change the default home state from HIGH to LOW&lt;br /&gt;
#define DEFAULT_HOME_STATE LOW ///&amp;lt; Change to LOW according to Home sensor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 I had to comment out all of the watchdog lines as well. I think it’s checking for communication between the Pi and Arduino.&lt;br /&gt;
&lt;br /&gt;
just do a search for ‘wdt’ and add // before all the wdt lines and comment them out.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
How I start the Rotator software on my PC:&lt;br /&gt;
&lt;br /&gt;
Install Hamlib:  https://sourceforge.net/projects/hamlib/&lt;br /&gt;
&lt;br /&gt;
Figure out which COM port your Arduino is (Mine is COM7)&lt;br /&gt;
&lt;br /&gt;
create a .bat file in the same folder as rotctld  (I found it in C:\Program Files (x86)\hamlib-w64-3.2\bin )&lt;br /&gt;
with the following (modify for your com port)&lt;br /&gt;
&lt;br /&gt;
&amp;gt; rotctld -m 202 -r COM7 -s 9600 -T 127.0.0.1 -t 4533 -C timeout=500 -C retry=0 -vvvvvvvv&lt;br /&gt;
&amp;gt; pause&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download Gpredict  https://sourceforge.net/projects/gpredict/&lt;br /&gt;
&lt;br /&gt;
Edit...Preferences...Interfaces...Rotators...Add New&lt;br /&gt;
Name        host            port&lt;br /&gt;
Arduino    localhost     4533&lt;br /&gt;
&lt;br /&gt;
Start your .bat,   in the top right corner of Gpredict, click down arrow, then 'Antenna Control'&lt;br /&gt;
&lt;br /&gt;
...Clicking 'Engage'  should get the Rotator to start working.&lt;br /&gt;
&lt;br /&gt;
Once you have configured some satellites you can them select them and click 'Track'&lt;br /&gt;
&lt;br /&gt;
=== Testing ===&lt;br /&gt;
&lt;br /&gt;
=== Tweaks ===&lt;br /&gt;
&lt;br /&gt;
=== Operation ===&lt;br /&gt;
{{DEFAULTSORT:SatNOGS Arduino Uno CNC Shield Based Rotator Controller}}&lt;br /&gt;
__FORCETOC__&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.satnogs.org/index.php?title=SatNOGS_Rotator_v3&amp;diff=2648</id>
		<title>SatNOGS Rotator v3</title>
		<link rel="alternate" type="text/html" href="https://wiki.satnogs.org/index.php?title=SatNOGS_Rotator_v3&amp;diff=2648"/>
		<updated>2019-03-10T19:06:32Z</updated>

		<summary type="html">&lt;p&gt;G7kse1: /* Rotator Controller */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Rotator&lt;br /&gt;
|Rotator-Name=SatNOGS Rotator v3&lt;br /&gt;
|image=V3.jpg&lt;br /&gt;
|type= Az/El&lt;br /&gt;
|cost=~220 USD&lt;br /&gt;
|status= Beta&lt;br /&gt;
|latest-release= https://gitlab.com/librespacefoundation/satnogs/satnogs-rotator/tags/v3.1-pre-release&lt;br /&gt;
|latest-release-name= v3.1&lt;br /&gt;
|source-repo= https://gitlab.com/librespacefoundation/satnogs/satnogs-rotator/&lt;br /&gt;
|documentation= [https://ohai.satnogs.org/project/satnogs-rotator-v3-mechanical-assembly/hardware/ v3.0.1] [https://wiki.satnogs.org/SatNOGS_Rotator_v3#Build_Sequence v3.1]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Intro ==&lt;br /&gt;
&lt;br /&gt;
v3 marks a major re-haul of the SatNOGS Rotator design, with learnings from [[SatNOGS Rotator v2|v2]] applied. You can see a lot of the thinking and background research that was conducted prior to v3 development in this [https://community.satnogs.org/t/satnogs-rotator-version-3/226 thread]. Also in this wiki page you can also find a &amp;quot;How to build the rotator&amp;quot;, mechanical analysis and all documentation about the [https://gitlab.com/librespacefoundation/satnogs/satnogs-rotator SatNOGS rotator].&lt;br /&gt;
&lt;br /&gt;
Also in this [https://www.ethercalc.org/v3specs list] is presented different rotators, either commercial or DIY builds.&lt;br /&gt;
&lt;br /&gt;
==Specifications==&lt;br /&gt;
&lt;br /&gt;
{| {{table}}&lt;br /&gt;
| style=&amp;quot;background:#f0f0f0;&amp;quot; align=&amp;quot;center&amp;quot; |&lt;br /&gt;
| style=&amp;quot;background:#f0f0f0;&amp;quot; align=&amp;quot;center&amp;quot; |'''SatNOGS v3 Rotator'''&lt;br /&gt;
|-&lt;br /&gt;
| Plastic Parts || 15&lt;br /&gt;
|-&lt;br /&gt;
| Non Printed Parts || 38&lt;br /&gt;
|-&lt;br /&gt;
| Cost||~ $220&lt;br /&gt;
|-&lt;br /&gt;
| Controller Electronics|| [[SatNOGS Rotator Controller]]&lt;br /&gt;
|-&lt;br /&gt;
| Type||AZ/EL (possible X/Y)&lt;br /&gt;
|-&lt;br /&gt;
| Motors||2x NEMA 17 Stepper or 2x DC Motors&lt;br /&gt;
|-&lt;br /&gt;
| Frame Material|| Aluminum T-slot 20x20&lt;br /&gt;
|-&lt;br /&gt;
| Speed (deg/sec) || 7&lt;br /&gt;
|-&lt;br /&gt;
| Torque (Nm) || ?, ~30&lt;br /&gt;
|-&lt;br /&gt;
| Brake Torque (Nm) || ?&lt;br /&gt;
|-&lt;br /&gt;
| Dimensions (mm) || 280x140x140 (AZ/EL)&lt;br /&gt;
|-&lt;br /&gt;
| Weight (kg) || ~5&lt;br /&gt;
| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Design Goals ====&lt;br /&gt;
Considering the specifications as detailed in the [https://wiki.satnogs.org/SatNOGS_Rotator_v3#Mechanical_Analysis_.5BWIP.5D Mechanical Analysis], we would also like for the 3rd version of SatNOGS rotator to be:&lt;br /&gt;
&lt;br /&gt;
* inexpensive (less than €300, if possible)&lt;br /&gt;
* lightweight and portable (~6Kg, size:~300x~150x~150mm)&lt;br /&gt;
* rigid and durable&lt;br /&gt;
* easy to build and fix (try to use easily available materials)&lt;br /&gt;
* weatherproof&lt;br /&gt;
* electromagnetically shielded, so that noise in reception is reduced&lt;br /&gt;
* accurate (&amp;lt;1deg, backlash reduction and use of encoders at the axis)&lt;br /&gt;
&lt;br /&gt;
== Sourcing ==&lt;br /&gt;
&lt;br /&gt;
'''3d Printing at a Fab Lab or your local hackerspace:''' If you don't have your own 3d printer, then a local Fab Lab or hackerspace may be able to do it for you. Fab Labs and hackerspaces are places that have invested in the machinery and you can take the designs to them. Generally they need .stl files to import into the software that runs the machines, but this should be discussed with the Fab Lab or hackerspace. You then pay for the material, time or a combination of the two for each of the parts or any other agreement in place.&lt;br /&gt;
&lt;br /&gt;
* [http://www.fabfoundation.org/fab-labs FabLabs]&lt;br /&gt;
* [https://wiki.hackerspaces.org/List_of_Hacker_Spaces List of hacker spaces]&lt;br /&gt;
&lt;br /&gt;
Most people building the rotator have had success builds with simple ABS material for the 3D printing parts.&lt;br /&gt;
&lt;br /&gt;
'''T Slot''' - If you don't want to cut the pieces yourself, then you may be able to find a supplier that will do this for you.   ([http://www.kjnltd.co.uk/ Here's one in the United Kingdom].)&lt;br /&gt;
&lt;br /&gt;
Hidden corner connectors - AliExpress gave the cheapest supplier&lt;br /&gt;
&lt;br /&gt;
A good US source is [http://us.misumi-ec.com/ MISUMI-USA]; they will also cut to length.  MISUMI has several other global locations [https://www.misumi-ec.com].&lt;br /&gt;
&lt;br /&gt;
Beware, the 20-series T-slot from [https://8020.net/ 80/20 Inc.] in the US has slots that are only 5.2mm wide.  The hidden corner connectors from e.g. AliExpress '''will not fit'''.&lt;br /&gt;
&lt;br /&gt;
'''Stepper Motors''' - eBay&lt;br /&gt;
&lt;br /&gt;
'''Belts''' - eBay&lt;br /&gt;
&lt;br /&gt;
'''Fixings / Pipe''' - eBay&lt;br /&gt;
&lt;br /&gt;
==== Vendors Table ====&lt;br /&gt;
&lt;br /&gt;
Like the [https://reprap.org/wiki/RepRap_Buyers%27_Guide RepRap Buyers' Guide wiki], feel free to populate the table. &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Vendor&lt;br /&gt;
! Location&lt;br /&gt;
! Parts &lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| [https://www.pololu.com/ pololu]&lt;br /&gt;
| USA, Worldwide &lt;br /&gt;
| Motors, electronics&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [http://mouser.com/ mouser]&lt;br /&gt;
| Worldwide &lt;br /&gt;
| Motors, electronics&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [https://www.ebay.com/ ebay]&lt;br /&gt;
| Worldwide &lt;br /&gt;
| Motors, electronics, Fasteners, T-Slots, pulleys, Tubes&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [https://www.aliexpress.com/ aliexpress]&lt;br /&gt;
| Worldwide &lt;br /&gt;
| Motors, electronics, Fasteners, T-Slots, pulleys, Tubes&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [https://grobotronics.com/ grobotronics]&lt;br /&gt;
| GR, EU&lt;br /&gt;
| Motors, electronics, Fasteners, T-Slots, pulleys&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [https://www.motedis.com/shop/index.php motedis]&lt;br /&gt;
| DE, EU&lt;br /&gt;
| T-Slots, Tubes&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [https://uk.misumi-ec.com/ Misumi]&lt;br /&gt;
| Worldwide&lt;br /&gt;
| T-Slots, Tubes, Fasteners, Pulleys&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [https://www.omc-stepperonline.com/ omc-stepperonline]&lt;br /&gt;
| Worldwide&lt;br /&gt;
| Stepper motors&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [https://www.fastenal.ca/ fastenal]&lt;br /&gt;
| USA&lt;br /&gt;
| Fasteners&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [https://www.mcmaster.com/ mcmaster]&lt;br /&gt;
| USA&lt;br /&gt;
| Fasteners&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.rs-online.com/ rs]&lt;br /&gt;
| Worldwide&lt;br /&gt;
| Electronics, fasteners, motors&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [https://8020.net/ 80/20]&lt;br /&gt;
| USA&lt;br /&gt;
| T-Slots&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [https://www.pcbway.com/ pcbway]&lt;br /&gt;
| CN&lt;br /&gt;
| PCB fabrication&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [https://www.servocity.com/ servocity]&lt;br /&gt;
| USA&lt;br /&gt;
| Motors, T-slots, fasteners&lt;br /&gt;
| Most of parts are not metric&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Build Sequence ==&lt;br /&gt;
&lt;br /&gt;
==== Tools &amp;amp; Consumables ====&lt;br /&gt;
Here are presented tools and consumables about part fabrication, port-processing and assembly process.&lt;br /&gt;
Most of the tools are available in every hackerspace, makerspaces, FabLabs etc. &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tool/Consumable&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| Drill bits&lt;br /&gt;
| 2mm for aluminum, 3mm, 4mm and 5mm for plastic&lt;br /&gt;
|-&lt;br /&gt;
| Drill driver&lt;br /&gt;
| For aluminum tube drill hole, 3D printed part&lt;br /&gt;
|-&lt;br /&gt;
| Sandpaper&lt;br /&gt;
| 80(dry), 120(dry), 240(dry) and 1000(wet) grit&lt;br /&gt;
|-&lt;br /&gt;
| Acetone&lt;br /&gt;
| For acetone vapor bath&lt;br /&gt;
|-&lt;br /&gt;
| Hacksaw&lt;br /&gt;
| For aluminum Tube&lt;br /&gt;
|-&lt;br /&gt;
| Square File&lt;br /&gt;
| For worm axis, for use on steel&lt;br /&gt;
|-&lt;br /&gt;
| Precision Knife&lt;br /&gt;
| For general use, especially in 3d-Printed parts&lt;br /&gt;
|-&lt;br /&gt;
| Caliper&lt;br /&gt;
| Measuring Range 0-150mm&lt;br /&gt;
|-&lt;br /&gt;
| Combination Wrenches&lt;br /&gt;
| 5.5mm, 7mm and 8mm&lt;br /&gt;
|-&lt;br /&gt;
| Thread-locker&lt;br /&gt;
| Like Loctite 271&lt;br /&gt;
|-&lt;br /&gt;
| Cyano acrylic glue&lt;br /&gt;
| Like Loctite 401&lt;br /&gt;
|-&lt;br /&gt;
| Screw driver&lt;br /&gt;
| Number 1 Phillips&lt;br /&gt;
|-&lt;br /&gt;
| Heat Gun&lt;br /&gt;
| For Heat-shrinkables or use a lighter&lt;br /&gt;
|-&lt;br /&gt;
| Ball-End L-Keys&lt;br /&gt;
| Hex 1.5mm, 2mm, 2.5mm, and 3mm&lt;br /&gt;
|-&lt;br /&gt;
| Soldering iron and consumables&lt;br /&gt;
| For cables&lt;br /&gt;
|-&lt;br /&gt;
| Wire Cutter&lt;br /&gt;
| For cables&lt;br /&gt;
|-&lt;br /&gt;
| Long-Nose Plier&lt;br /&gt;
| General purpose&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Parts ====&lt;br /&gt;
Make sure you have all parts, according to [https://gitlab.com/librespacefoundation/satnogs/satnogs-rotator/blob/master/rotator-bom.ods BOM].&lt;br /&gt;
&lt;br /&gt;
Most of the parts could be fabricated by a FDM 3D-printer. Some parts have only 2D geometry so could be&lt;br /&gt;
fabricated by a laser cutter. Other parts have modifications of common(hardware) parts like threaded rods or&lt;br /&gt;
aluminum pipes. Also you could find a lot of guides for [https://www.3dhubs.com/knowledge-base/post-processing-fdm-printed-parts post processing for FDM printed parts].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200&amp;quot; heights=&amp;quot;200&amp;quot; perrow=&amp;quot;4&amp;quot;&amp;gt;&lt;br /&gt;
File:C1001.png|C1001, Aluminum Tube 6063 OD40mm TH1.5mm L240mm, 2 variants -1 and -3&lt;br /&gt;
File:C1010-3.png|C1010-3, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material&lt;br /&gt;
File:C1011-3.png|C1011-3, laser cut in 3mm Acrylic Sheet or in FDM-3Dprinter with same fabrication parameters as C1010-3&lt;br /&gt;
File:C1020-1.png|C1020-1, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material, [http://sinkhacks.com/building-acetone-vapor-bath-smoothing-3d-printed-parts/ Smoothing the part with acetone vapor bath]&lt;br /&gt;
File:C1021-1.png|C1021-1, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material, [http://sinkhacks.com/building-acetone-vapor-bath-smoothing-3d-printed-parts/ Smoothing the part with acetone vapor bath], [https://community.libre.space/t/version-3-1-stepper-varient-with-v2-controller/1430/5 Imperial variant], [https://community.libre.space/t/help-to-buy-metric-tubing-for-v3-rotator/784/6 tool that helps to build imperial part]&lt;br /&gt;
File:C1022-3.png|C1022-3, laser cut in 3mm Acrylic Sheet or in FDM-3Dprinter with same fabrication parameters as C1010-3&lt;br /&gt;
File:C1030-1.png|C1030-1, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material&lt;br /&gt;
File:C1040-1.png|C1040-1, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material, [https://community.libre.space/t/version-3-1-stepper-varient-with-v2-controller/1430/5 Imperial variant], [https://community.libre.space/t/help-to-buy-metric-tubing-for-v3-rotator/784/6 tool that helps to build imperial part]&lt;br /&gt;
File:C1041-1.png|C1041-1, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material, [https://community.libre.space/t/version-3-1-stepper-varient-with-v2-controller/1430/5 Imperial variant], [https://community.libre.space/t/help-to-buy-metric-tubing-for-v3-rotator/784/6 tool that helps to build imperial part]&lt;br /&gt;
File:C1042-1.png|C1042-1, laser cut in 3mm Acrylic Sheet or in FDM-3Dprinter with same fabrication parameters as C1010-3&lt;br /&gt;
File:C1043-1.png|C1043-1, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], Support material, Brim Width: 2 mm&lt;br /&gt;
File:C1050.png|C1050, Aluminum Profile 20x20 B-type slot 6, 2 variants -1 and -5&lt;br /&gt;
File:C1060-1.png|C1060-1, M5 Threaded rod A2 stainless steel(304)&lt;br /&gt;
File:C1061.png|C1061, 2 variants -5 and -6, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material&lt;br /&gt;
File:C1062-1.png|C1062-1, It is recommended to build in laser sintering like Shapeways with White Versatile Plastic (cost ~10€) or like C1030-1 and [http://sinkhacks.com/building-acetone-vapor-bath-smoothing-3d-printed-parts/ Smoothing the part with acetone vapor bath]&lt;br /&gt;
File:C1070-1.png|C1070-1, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material&lt;br /&gt;
File:C1071-1.png|C1071-1, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material&lt;br /&gt;
File:C1072-1.png|C1072-1, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material&lt;br /&gt;
File:C1083-1.png|C1083-1, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material&lt;br /&gt;
File:C1080-3 2.png|C1080-3, Cover Box bottom part, galvanized steel sheet, thickness 0.5mm&lt;br /&gt;
File:C1081-3 2.png|C1081-3, Cover Box top part, galvanized steel sheet, thickness 0.5mm&lt;br /&gt;
File:C1082-5.png|C1082-5, Cover Box side part, galvanized steel sheet, thickness 0.5mm&lt;br /&gt;
File:C1084-1.png|C1084-1, FDM-3Dprinted, Material: ABS, Layer height: 0.4 mm, Perimeters: 2, Top/bottom solid layers: 3, Fill density: 20%, Fill pattern: Honeycomb, Fan speed: [35, 100], No support material&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Assembly ====&lt;br /&gt;
Follow the [https://ohai.satnogs.org/project/satnogs-rotator-v3-mechanical-assembly/hardware/ instructions for mechanical assembly] and also you can [https://www.youtube.com/watch?v=D6P9HK23Gmo watch timelapse]&lt;br /&gt;
Also, exploded views and instructions are present here.&lt;br /&gt;
&lt;br /&gt;
{{Message|&lt;br /&gt;
Prior to Step 8, the rotary encoders must be ready and prior to Step 11 the motor must be mounted in A1070-1. For the rotary encoder assembly look at the next section [https://wiki.satnogs.org/SatNOGS_Rotator_v3#Rotator_Controller Rotator_Controller].}}&lt;br /&gt;
&lt;br /&gt;
Some notes for assembly:&lt;br /&gt;
* Resolve collision between of end-stop arm and C1042-1 end-stop mount, [https://community.libre.space/t/rotator-3-1-end-stop-switch-mounting/3463 community post]&lt;br /&gt;
* [https://community.libre.space/t/rotator-3-1-worm-gear-issues/1858/7 Running the worm gear] and [https://community.libre.space/t/rotator-3-1-worm-gear-issues/1858/9 lapping the worm gear] to get gear box running smooth&lt;br /&gt;
* [https://community.libre.space/t/stepper-motor-bolts-v3-1/3388 Collision between bolts and motor], this issue can be created by using wrong M4 screws(H1100-5) and washers(H1110-1)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;180&amp;quot; heights=&amp;quot;180&amp;quot; perrow=&amp;quot;4&amp;quot;&amp;gt;&lt;br /&gt;
File:A1010-1.png|Step 1, Prepare the assembly of worm gear&lt;br /&gt;
File:A1011.png|Step 2, Prepare the assembly of worm gear mount, 2 variants -1 and -2 (mirror)&lt;br /&gt;
File:A1020-1.png|Step 3, Prepare the assembly of shaft collar for worm wheel&lt;br /&gt;
File:A1033-1.png|Step 4, Prepare the encoder gear&lt;br /&gt;
File:A1070-1.png|Step 5, Prepare the Motor mount&lt;br /&gt;
File:A1060-1.png|Step 6, In case of DC motor configuration&lt;br /&gt;
File:A1031-1.png|Step 7, Bearing side without encoder and end-stop mounts&lt;br /&gt;
File:A1032-1.png|Step 8, Bearing side with encoder and end-stop mounts&lt;br /&gt;
File:A1030.png|Step 9, Prepare symmetric and asymmetric axis, 2 variants -1 and -3&lt;br /&gt;
File:A1001-3.png|Step 10, Frame with worm gear mount and A1001-1 assembly&lt;br /&gt;
File:A1040.png|Step 11, Rotator module 2 Variants -1 and -3, symmetric and asymetric  [[:File:Tip for Step 11 (A1040) -- Note 10 - use of M5 Nuts to attach Drill.jpg|(Assembly Tip - Note 10:Jam two M5 nuts together at end of shaft to easily run gearbox manually)]]&lt;br /&gt;
File:A1050-1.png|Step 12, Final step of Antenna Rotator&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Rotator Controller ====&lt;br /&gt;
The default way of controlling the rotator is to use the [[SatNOGS Rotator Controller]].This works for both stepper motor and DC motor set ups (Note: If you are uing the [https://wiki.satnogs.org/SatNOGS_Rotator_Controller#Encoders the rotary encoders] these will need to be set up). An alternative is to use the [[SatNOGS_Arduino_Uno/CNC_Shield_Based_Rotator_Controller]], whih has been used as a stand alone set up for use with GPredict. &lt;br /&gt;
&lt;br /&gt;
==== Cover Box - Cabling ====&lt;br /&gt;
Prepare the cover box and install it to antenna rotator with rotator controller and cables.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200&amp;quot; heights=&amp;quot;200&amp;quot; perrow=&amp;quot;4&amp;quot;&amp;gt;&lt;br /&gt;
File:Cover_box_1.JPG| Put the C1080-3 with screws M4 L10 DIN912, C1084-1 and washers M4 DIN125 to the azimuth module. The screw with the Phillips Rounded Head Screws For Sheet Metal, M3,5 X 6,5, DIN 7981,INOX A2, C1082-5 to the C1080-3 and put the C1083-1. Note screw only the middle screw.&lt;br /&gt;
File:Power_cable_1.JPG| The power - data cable must be passed inside the azimuth axis. This solution is tested [https://network.satnogs.org/stations/200/ in station 200] without problem.&lt;br /&gt;
File:Power_cable_2.JPG| In the other side of power cable must be installed a connector with  4 terminals and waterproof like [https://grobotronics.com/connector-sp-4-pin-male.html Weipu - SP1310/P4I]. Also it is needed to have the female connector for cable that connected to the client. For cheaper solution use a bigger cable to connect the rotator with client and power source.&lt;br /&gt;
File:Other_cables_2.JPG|The 3 CAT5e UTP cables are 2x sensors (encoders - end stops) 1x power and data (RS-485). For color code use [https://en.wikipedia.org/wiki/Power_over_Ethernet#Pinouts 802.3af Standards A and B] from the power sourcing equipment perspective.&lt;br /&gt;
File:Other_cables_3.JPG|The other cables are for DC motor or stepper motors. In each side of the CAT5e UTP cables must be put a Heat-shrinkable asreferred in [https://gitlab.com/librespacefoundation/satnogs/satnogs-rotator/blob/master/rotator-bom.ods BOM]. Also a Heat-shrinkable must be putin the cable gland in rotator controller for motor cables.&lt;br /&gt;
File:Other_cables_1.JPG|Pass all the cables though the hole in the bottom of C1080-3 &lt;br /&gt;
File:Motor_ferrite_bead.JPG|Add ferrite beads for motor cables, dimensions L25mm and OD 13mm&lt;br /&gt;
File:Velcro_for_controller_1.JPG|Add velcro to mount the rotator controller outside the box. Velcro tape specifications: Heavy duty, stick on, max 7Kg, 50mm x 100mm. The tape might be used to mount [https://wiki.satnogs.org/No_rotator client box]  in the rotator.&lt;br /&gt;
File:Rotator_controller_1.JPG| Cabling management inside the rotator controller. The controller is mounted to the rotator by using a tape as mentioned previously.&lt;br /&gt;
File:Rotator controller 2.JPG| Cabling management outside the rotator controller&lt;br /&gt;
File:Testing_1.JPG| The rotator is ready for testing, before the final step do not put the C1081-3, in order to most of components must be accessible&lt;br /&gt;
File:Testing 2.JPG| The final step. If everything is working properly, must be put the C1081-3 by using sheet metal screws as mentioned previously. In this step if the holes of C1081-3 are not aligned with the holes of the other two parts, C1082-5 and C1080-3, drill new holes and screw them, take a look in [https://gitlab.com/librespacefoundation/satnogs/satnogs-rotator/issues/73 issue 73]. Put stickers!!!!!!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Testing ====&lt;br /&gt;
You are ready! Proceed with [https://wiki.satnogs.org/SatNOGS_Rotator_Controller#Troubleshooting_hints testing].&lt;br /&gt;
&lt;br /&gt;
==== Heading Calibration ====&lt;br /&gt;
The heading calibration is a manual process:&lt;br /&gt;
&lt;br /&gt;
* Power the rotator, it starts moving in order to find the home position, to find the end-stops&lt;br /&gt;
* Remove the power from the rotator, the rotator is in home position&lt;br /&gt;
* Install the rotator to vertical axis by using U-Bolt clamps&lt;br /&gt;
* The azimuth axis it must be heading to the North, this is achieved by using a compass (e.g. from smart phone)&lt;br /&gt;
* Secure the rotator in the vertical axis&lt;br /&gt;
* Install the elevation axis with the same process, now the zero elevation is achieved by using a pocket level&lt;br /&gt;
* Secure the elevation axis&lt;br /&gt;
* In the case of wrong rotation:&lt;br /&gt;
** For stepper motors swap a pair of two stepper motor cables ([https://gitlab.com/librespacefoundation/satnogs/satnogs-rotator-firmware/issues/15 it exists an open issue to be done by a command])&lt;br /&gt;
** For DC motors, [https://gitlab.com/librespacefoundation/satnogs/satnogs-rotator-firmware/commit/961fb696536e35642f2b7064cc3c64676ebebb17 change the sign of encoder reading], it is a hacky method but it would be resolved by [https://gitlab.com/librespacefoundation/satnogs/satnogs-rotator-firmware/issues/15 this issue]&lt;br /&gt;
&lt;br /&gt;
== Mechanical Analysis [WIP] ==&lt;br /&gt;
&lt;br /&gt;
==== Brake Torque ====&lt;br /&gt;
The greatest force the tracker needs to withstand is the force created by strong wind. The worst case is when one antenna is elevated at 90 degs, facing the direction of the wind. We based our calculations on an [http://k7nv.com/notebook/topics/windload.html article] found online after comparing it to others. We “translated” the second table in metric (because we don’t understand imperial and because we needed same units system in our calculations)&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Wind Zone(km/h)&lt;br /&gt;
! Height (m) &lt;br /&gt;
! Pressure(N/m^2)&lt;br /&gt;
|-&lt;br /&gt;
| EIA-222-C&lt;br /&gt;
| 160&lt;br /&gt;
| N/A&lt;br /&gt;
| 1280&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| EIA-222-F &lt;br /&gt;
| 128&lt;br /&gt;
| 14&lt;br /&gt;
| 1260&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| EIA-222-F&lt;br /&gt;
| 128&lt;br /&gt;
| 21&lt;br /&gt;
| 1390&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| EIA-222-F &lt;br /&gt;
| 128&lt;br /&gt;
| 30&lt;br /&gt;
| 1500&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| UBC'97&lt;br /&gt;
| 128&lt;br /&gt;
| 14&lt;br /&gt;
| 1290&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| UBC'97&lt;br /&gt;
| 128&lt;br /&gt;
| 21&lt;br /&gt;
| 1160&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| UBC'97&lt;br /&gt;
| 128&lt;br /&gt;
| 21&lt;br /&gt;
| 1390&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| UBC'97&lt;br /&gt;
| 128&lt;br /&gt;
| 30&lt;br /&gt;
| 1260&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| UBC'97&lt;br /&gt;
| 128&lt;br /&gt;
| 42&lt;br /&gt;
| 990&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| UBC'97&lt;br /&gt;
| 128&lt;br /&gt;
| 42&lt;br /&gt;
| 1360&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Generic Formula &lt;br /&gt;
| 150&lt;br /&gt;
| N/A&lt;br /&gt;
| 1270&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
and we applied the worst case model (EIA-222-F) in 3 different antennas: in the biggest one of our designs, and in two others, for which we obtained data from [http://download.qrz.ru/pub/hamradio/antenna/rotators/G-800SA_1000SA.pdf yaesu G800 rotator manual at page 3]. We assumed that antennas are mounted in 1m away from the azimuth axis. For our antenna with 2m length (actual, not wavelength), made by 2cm square tube, the generated torque was ≈600Kg*cm. For the 144MHz 10-elements Yagi from the article is ≈6000Kg*cm and for the third 430MHz, 12-elements Yagi is ≈1800Kg*cm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Moment of inertia ====&lt;br /&gt;
Now for the moment of inertia: (for all installation methods we assumed that antennas are counterbalanced in the elevation axis) the worst case scenario here is to use two 3kg (our designs are less than 1kg) back mounted yagis with 3kg counterbalances both mounted in 0.75m away from azimuth axis. The torque you need in order to accelerate this system from ω=0deg/s angular velocity to ω=5deg/s (the math about angular velocity is below) in one second is about 60kg*cm.&lt;br /&gt;
&lt;br /&gt;
Note: we suppose that the mass of antennas is near to the altitude axis, so the torque of this axis that is needed to accelerate is approximately 0.&lt;br /&gt;
&lt;br /&gt;
* M1: torque of Azimuth axis&lt;br /&gt;
* L: length of center of mass of antennas from azimuth axis (0.75m)&lt;br /&gt;
* m: mass of antennas and of counterweight (3kg + 3kg = 6kg)&lt;br /&gt;
* I: moment inertia&lt;br /&gt;
* a: angular acceleration of azimuth axis 5deg/s^2&lt;br /&gt;
* I = I1 + I2 = m*L^2 + m*L^2 = 2*m*L^2 = 6.75 kg*m^2&lt;br /&gt;
* M1 = I*a = 6.75kgm^2 * 0.087rad/s^2 = 0.58 Nm = 5.8 kgm = 58 kgcm&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Angular velocity ====&lt;br /&gt;
(How well do you remember trigonometry?)For the angular velocity max needed in altitude axis the things are straightforward. The closer is the satellite the larger the velocity. According to the wikipedia article about LEO, the lowest height limit is 160 km and the speed unit to orbit earth in this altitude is 7,8 km/s. As a result, maximum velocity in ALT axis is 2,8 deg/s. In ALT AZ rotator design there is a well known limitation: the closer something passes near zenith the biggest gets the velocity of the AZ axis. Therefore, we have analyzed this problem to figure out the optimal velocity and how high we are allowed to track a target in relation to AZ velocity. The picture below illustrates a ground station B which tracks a satellite Γ in X degrees altitude. The satellite velocity at this point is vertical to the screen (page) plane.&lt;br /&gt;
&lt;br /&gt;
[[File:Anglular_velocity.png|thumb|center|800x420px|alt=|Angular Velocity]]&lt;br /&gt;
&lt;br /&gt;
The equations that lead to maximum altitude at which we can track in relation to AZ angular velocity are&lt;br /&gt;
* ω : angular velocity of AZ DOF in rad/s&lt;br /&gt;
* H = ΑΕ + ΕΓ : Minimum Height of LEO, 160 km&lt;br /&gt;
* R = ΑΕ : Radius of Earth, 6500 km&lt;br /&gt;
* u : linear velocity of satellite that rotates in 160km height is 7.8 km/s&lt;br /&gt;
* ΒΔ = u / ω : ΒΔ in km&lt;br /&gt;
* α = atan(ΒΔ / R)&lt;br /&gt;
* δ = π - α&lt;br /&gt;
* γ = asin( sqrt(R^2+ΒΔ^2) * sin(δ) / (H+R) )&lt;br /&gt;
* ά = π - δ - γ&lt;br /&gt;
* ΓΔ = (H+R) * sin(ά) / sin(δ)&lt;br /&gt;
* χ = atan(ΓΔ / ΒΔ)&lt;br /&gt;
&lt;br /&gt;
Below you can see the plot of the equations mentioned above, where horizontal axis represents angular velocity (ω) in deg/s and vertical axis shows the max track altitude (χ) for lower bound of LEO.&lt;br /&gt;
&lt;br /&gt;
[[File:Anglular_velocity_plot.png|thumb|center|800x420px|alt=|Angular Velocity Plot]]&lt;br /&gt;
&lt;br /&gt;
After studying this diagram, we came up to the conclusion that an angular velocity of 5 deg/s is adequate. For this decision, we took into consideration the main lobe of antenna (Δ3db) which in most situations is about 20 deg.&lt;br /&gt;
&lt;br /&gt;
==== Pulleys/Belts/Gearing ====&lt;br /&gt;
Horizontal distance between pulleys (P1, P2) is 58mm.&lt;br /&gt;
Vertical distance between pulleys (P1, P2) is w = 9.5mm.&lt;br /&gt;
&lt;br /&gt;
Pulleys and Belt are GT2, 2mm pitch. &lt;br /&gt;
Belt width, 6mm. &lt;br /&gt;
Belt thickness, 1.38mm (0.76 tooth). &lt;br /&gt;
&lt;br /&gt;
Wrap angle in both pulleys is larger than 60deg. &lt;br /&gt;
At least 6 teeth in contact with the pulley at any given time. &lt;br /&gt;
In practice that means you want a minimum of a 12 tooth pulley, and usually try to get at least 18 teeth. &lt;br /&gt;
&lt;br /&gt;
Outer Diameter of pulleys:&lt;br /&gt;
&lt;br /&gt;
P(T) | OD(mm) &amp;lt;br /&amp;gt;&lt;br /&gt;
16   | 10.2 &amp;lt;br /&amp;gt;&lt;br /&gt;
20   | 12.7 &amp;lt;br /&amp;gt;&lt;br /&gt;
36   | 22.9 &amp;lt;br /&amp;gt;&lt;br /&gt;
40   | 25.5 &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Belt calculation (according to calculator):&lt;br /&gt;
&lt;br /&gt;
Ratio    | P1(T)   | P2(T)   | Belt(T) | L(mm)  &amp;lt;br /&amp;gt;&lt;br /&gt;
2.25|16|36|85/86|58.65/59.66  &amp;lt;br /&amp;gt;&lt;br /&gt;
1.8|20|36|86/87/88|57.78/58.78/59.78  &amp;lt;br /&amp;gt;&lt;br /&gt;
2.5|16|40|87/88|58.5/59.5 &amp;lt;br /&amp;gt;&lt;br /&gt;
2|20|40|89/90|58.65/59.66 &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Motor Maximun no-load speed, 200RPM = 1200deg/s &lt;br /&gt;
Motor Maximum stall-torue, 1.2Nm &lt;br /&gt;
&lt;br /&gt;
[[File:Motor_perfomance_graph.png|thumb|center|800x420px|alt=|Angular Velocity]]&lt;br /&gt;
&lt;br /&gt;
Position of idler do not care, or min 1.3*P1, max 1.5*P1 (for 20T, ~16mm/~20mm).&lt;br /&gt;
&lt;br /&gt;
Belt gear selection:&lt;br /&gt;
* 20/36 with 1.8 ratio and 86T/172mm belt without idler&lt;br /&gt;
* 20/40 with 2 ratio and 90T/190mm belt with idler&lt;br /&gt;
&lt;br /&gt;
To calculate Deflection force, (page T-31, sdp - design-guidelines)&lt;br /&gt;
* Y = 2.05, Tst = 1.3kg&lt;br /&gt;
* span length, t = 57.64mm&lt;br /&gt;
* Belt pitch length, L = 180mm&lt;br /&gt;
* Fd,min = &lt;br /&gt;
* Fd,max = &lt;br /&gt;
* 2.8kg Working Tension [shapeoko - Belts and Pulleys](https://www.shapeoko.com/wiki/index.php/Belts_and_Pulleys#Tensile_Cord_Materials)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   P3  &amp;lt;br /&amp;gt;&lt;br /&gt;
  /  \  &amp;lt;br /&amp;gt;&lt;br /&gt;
 P1  P2  &amp;lt;br /&amp;gt;&lt;br /&gt;
     |  &amp;lt;br /&amp;gt;&lt;br /&gt;
     P4-P5  &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Determination of design load &lt;br /&gt;
According to perfomance graph of DC motor, the optimal output power is Tm = 0.6Nm  with efficiency of 0.2 and 100RPM = 600deg/s. &lt;br /&gt;
Select a service factor of 1.5 (service factors between 1.5 and 2.0 are generally recommended when&lt;br /&gt;
designing small pitch synchronous drives). &lt;br /&gt;
Tpeak = SF*Tm = 1.5*0.6 = 0.9Nm &lt;br /&gt;
&lt;br /&gt;
* Choice of belt pitch&lt;br /&gt;
Due to backslash and accuracy in both directions of movements and volume constrains, we choose GT2, pitch 2mm.&lt;br /&gt;
&lt;br /&gt;
* Check belt pitch selection based on individual graphs&lt;br /&gt;
Due to Tpeak = 0.9Nm No-load speed,(Speed of fastest shaft) = 100RPM = 600deg/s &lt;br /&gt;
GT2 pitch 2mm belt is the better solution for our application. &lt;br /&gt;
&lt;br /&gt;
* Determine speed ratio&lt;br /&gt;
Speed ratio 1.8-2.25 according to specification of output rotation speed of 5deg/s.&lt;br /&gt;
&lt;br /&gt;
* Check belt speed&lt;br /&gt;
V(m/s) = 0.0000524 x pulley PD (mm) x pulley rpm = 0.066548m/s &lt;br /&gt;
Belt speeds up to 6,500 fpm (33.02 m/s) do not require special pulleys. &lt;br /&gt;
&lt;br /&gt;
* Determine belt length&lt;br /&gt;
Table 'Belt calculation (according to calculator)'&lt;br /&gt;
Teeth in mesh: 9&lt;br /&gt;
&lt;br /&gt;
* Determine the belt width&lt;br /&gt;
From Table 43 &lt;br /&gt;
torque = 0.17Nm &lt;br /&gt;
Length Correction Factor = 0.9 &lt;br /&gt;
width multiplier = 1.00 &lt;br /&gt;
torque*Length Correction Factor*width multiplier = 0.17*0.9*1.00 = 0.153Nm &lt;br /&gt;
Teeth in mesh: 9 &lt;br /&gt;
Tpeak = 0.9Nm, so belt width is nice for our application &lt;br /&gt;
&lt;br /&gt;
* Check the number of teeth in mesh&lt;br /&gt;
Teeth in mesh: 9 according to calculator &lt;br /&gt;
&lt;br /&gt;
* Determine proper belt installation tension&lt;br /&gt;
SECTION 10, on page T50, look at 'To calculate Deflection force, (page T-31, sdp - design-guidelines)' &lt;br /&gt;
* Y = 2.05, Tst = 0.812*DQ/d + mS^2 = 12.8lb + 0 = 5.8kg &lt;br /&gt;
* DQ = Tpeak = 0.9Nm = 7.9lb-in &lt;br /&gt;
* d = 12.7mm = 0.5in &lt;br /&gt;
* S = (0.5*100/3.82)/1000 = 0.0131ft/min &lt;br /&gt;
* m = 0.039 &lt;br /&gt;
* span length, t = sqrt(CD^2 - (PD-pd/2)^2) = 57.64mm &lt;br /&gt;
* Belt pitch length, L = 180mm &lt;br /&gt;
* t/L = 0.32 &lt;br /&gt;
* Fd,min = 0.8lb = 0.36kg &lt;br /&gt;
* Fd,max = 0.9lb = 0.41kg &lt;br /&gt;
&lt;br /&gt;
* Safety factor 1.5&lt;br /&gt;
&lt;br /&gt;
* P2 timing pulley torque - Maximum radial load of timing belt ball bearing 625zz&lt;br /&gt;
Tpeak = 0.9Nm &lt;br /&gt;
TorqueP2 = 2*0.9Nm = 1.8Nm, PDp2 = 25.5mm &lt;br /&gt;
Radial static load of 625ZZ is 0.38kN &lt;br /&gt;
T-39&lt;br /&gt;
&lt;br /&gt;
* Maximum thrust load of timing belt ball bearing 625zz&lt;br /&gt;
&lt;br /&gt;
* Maximum radial and thrust load of output ball bearings 6008zz&lt;br /&gt;
Calculate or evaluate correct loads for deep groove ball bearings&lt;br /&gt;
radial static load = 11.6kN &lt;br /&gt;
thrust static load = 0.7*11.6kN = 8.12kN &lt;br /&gt;
This type of construction permits the bearings to support relatively high thrust load in either direction. &lt;br /&gt;
In fact the thrust load capacity is about 70% of the radial load capacity. A ball bearing primarily  designed &lt;br /&gt;
to support radial load can also support high thrust load; because only few balls carry the radial load, &lt;br /&gt;
whereas all the balls can withstand the thrust load. &lt;br /&gt;
&lt;br /&gt;
* Maximum self-locking or back-drivable torque of gear box (according to more weak component)&lt;br /&gt;
It necessary to achieve [specs](https://community.libre.space/t/satnogs-rotator-version-3/226), 60Nm (6Kg in 1 meter)&lt;br /&gt;
&lt;br /&gt;
* Nominal torque of drivable torque of gear box (according to more weak component) and maximum rotational speed of gear box &lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* [https://sdp-si.com/eStore/CenterDistanceDesigner sdp distance calculator]&lt;br /&gt;
* [http://www.ebay.com/itm/2GT-Timing-Belt-L-172-232-240-244-640-810-GT2-Belts-closed-loop-5pcs-lot-/221977955532?var=&amp;amp;hash=item33aeeacccc:m:me5GvSt_amrm6RWT03Ut4JA belt GT2-6mm wide, 172mm]&lt;br /&gt;
* [https://www.ebay.com/itm/2GT-GT2-synchronous-Timing-belt-Perimeter-98-194mm-width-6-9mm-Cogged-close-loop/222574382655?ssPageName=STRK%3AMEBIDX%3AIT&amp;amp;var=521434616407&amp;amp;_trksid=p2060353.m2749.l2649 belt GT2-6mm wide, 180mm]&lt;br /&gt;
* [http://www.ebay.com/itm/5pcs-Timing-Pulley-GT2-Idler-16-20T-gear-Bearing-Reprap-6mm-Belt-3-5mm-Bore-3D-/132195520937?var=&amp;amp;hash=item1ec77791a9:m:mljSYBViBlKOgXr3Gy-u0Tg idler pulley, no-teeth-ID3mm-OD18mm]&lt;br /&gt;
* [http://www.brecoflex.com/products/pulleys/design-guidelines/ brecoflex - design-guidelines]&lt;br /&gt;
* [http://www.shreegeeimpex.com/TECH_DATA_PAG/idlers_ten.htm shreegeeimpex - design-guidelines]&lt;br /&gt;
* [http://www.sdp-si.com/PDFS/Technical-Section-Timing.pdf sdp - design-guidelines]&lt;br /&gt;
&lt;br /&gt;
==== Motor Specification ====&lt;br /&gt;
&lt;br /&gt;
General Specification about motors. The voltage and current consumption also it depends from the motor controller which is (maybe) different&lt;br /&gt;
from [https://wiki.satnogs.org/SatNOGS_Rotator_Controller SatNOGS Rotator Controller].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Specification&lt;br /&gt;
! Value&lt;br /&gt;
|-&lt;br /&gt;
| Min-Max Stall Torque (Nm)&lt;br /&gt;
| 0.4 - 1.5&lt;br /&gt;
|-&lt;br /&gt;
| Min-Max Speed (RPM)&lt;br /&gt;
| 100 - 200&lt;br /&gt;
|-&lt;br /&gt;
| Size (mm) (LxWxH)&lt;br /&gt;
| 47x42x64&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200&amp;quot; heights=&amp;quot;200&amp;quot; perrow=&amp;quot;4&amp;quot;&amp;gt;&lt;br /&gt;
File:Motor mount dimensions.png|Motor mount dimensions&lt;br /&gt;
File:Max motor height.png|Maximum Motor Height&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Worm Gear Box Calculations ====&lt;br /&gt;
&lt;br /&gt;
* Gear ratio: i12 = 30&lt;br /&gt;
* Angle between axis of gears: δ = 90 deg&lt;br /&gt;
* Number of threads in worm: If i12 &amp;gt;= 30 then z1 = 1&lt;br /&gt;
* Number of teeth in worm wheel: z2 = i12*z1 = 30&lt;br /&gt;
* Center distance: initial case a = 45.5 mm&lt;br /&gt;
* Worm reference diameter: AGMA d01&amp;gt;= 11.5*(a/25.4)^0.875 = 19.15 mm, so d01 = 19.5mm&lt;br /&gt;
* Worm wheel reference: d02 = 2*a - d01 = 71.5 mm&lt;br /&gt;
* Axial module: ms = d02/z2 = 2.38 , so ms = 2.5&lt;br /&gt;
Recalculate d02, a with new axial module&lt;br /&gt;
* d02 = z2*ms = 75mm, a = (d02+d01)/2 = 47.25mm&lt;br /&gt;
* Axial pitch: ts = π*ms = 7.854mm&lt;br /&gt;
* Reference lead angle: γ0 = atan(d02/(i12*d01)) = 7.3 deg&lt;br /&gt;
* Worm tip diameter: dk1 = d01 + 2*hk = 24.5mm&lt;br /&gt;
** Worm teeth reference addendum in axial section: hk = hk* *ms = 2.5mm&lt;br /&gt;
** Worm tooth reference addendum coefficient: hk* = 1&lt;br /&gt;
* Worm root diameter: df1 = d01 - 2*hf = 13.5mm&lt;br /&gt;
** Worm tooth reference dedendum: hf = hf* _ms = 1.2_ms = 3mm&lt;br /&gt;
** Dedendum coefficient: hf* = 1.2&lt;br /&gt;
* Worm length: L = 2.5_ms_sqrt(z2+2) = 35.36mm&lt;br /&gt;
* Worm tooth thickness: smx1 = smx1* * ts = 3.927mm&lt;br /&gt;
** Tooth thickness coefficient: smx1* = 0.5&lt;br /&gt;
* Normal pressure angle: aon = 20 deg&lt;br /&gt;
* Worm wheel throat diameter: dk2 = d02+2*hk = 80mm&lt;br /&gt;
* Worm wheel root diameter: df2 = d02 - 2*hf = 69mm&lt;br /&gt;
* Worm wheel outside diameter: de2 = dk2 + 2*mx = 83.5mm&lt;br /&gt;
** Worm wheel tooth external addendum: mx = n*ms, 0.4&amp;lt;=n&amp;lt;=1.5&lt;br /&gt;
* Effective worm wheel face width: b2H,max = sqrt((2_a - df2)^2 - (2_a - de2)^2) = 23mm&lt;br /&gt;
&lt;br /&gt;
[[Category:Rotator]]&lt;/div&gt;</summary>
		<author><name>G7kse1</name></author>
		
	</entry>
</feed>