hi ive been trying to get a script to work with webserver here is the code i start the web server with sudo python3 app.py
import subprocess
from flask import Flask, render_template, request
import os # Import os for path checking
app = Flask(__name__)
# --- Pololu Maestro Configuration ---
# IMPORTANT:
# 1. Verify this path matches where you unzipped and compiled UscCmd on your Pi.
# You can double-check with: ls /home/neil/Desktop/maestro-linux/UscCmd
USCCMD_PATH = "/home/neil/Desktop/maestro-linux/UscCmd"
# 2. This MUST match your Maestro's actual device serial number.
# You can find it by running: sudo /home/neil/Desktop/maestro-linux/UscCmd --list
# It's usually the number after '#'. Your specific ID is "00467001".
MAESTRO_DEVICE_ID = "00467001"
# --- HTML Template Content (for templates/index.html) ---
# You'll need to create a directory named 'templates' in the same folder as app.py
# and create a file named 'index.html' inside it.
HTML_CONTENT = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Maestro Control</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f4f4f4; }
.container { max-width: 600px; margin: auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
h1 { text-align: center; color: #333; }
.button-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; margin-top: 30px; }
button {
width: 100%;
padding: 15px 20px;
font-size: 1.1em;
color: white;
background-color: #007bff;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.2s ease-in-out, transform 0.1s ease-in-out;
}
button:hover { background-color: #0056b3; transform: translateY(-2px); }
button:active { background-color: #004085; transform: translateY(0); }
.status-message {
margin-top: 25px;
padding: 15px;
border-radius: 5px;
background-color: #e2e3e5;
color: #333;
border: 1px solid #d6d8db;
word-wrap: break-word;
white-space: pre-wrap; /* Preserve whitespace and line breaks */
}
.status-success { background-color: #d4edda; color: #155724; border-color: #c3e6cb; }
.status-error { background-color: #f8d7da; color: #721c24; border-color: #f5c6cb; }
</style>
</head>
<body>
<div class="container">
<h1>Maestro Control Interface</h1>
<div class="button-grid">
<button onclick="triggerSequence('0')">Sequence 1 (Script 0)</button>
<button onclick="triggerSequence('1')">Sequence 2 (Script 1 - Empty)</button>
</div>
<div id="status" class="status-message">Ready.</div>
</div>
<script>
async function triggerSequence(sequenceId) {
const statusDiv = document.getElementById('status');
statusDiv.className = 'status-message'; // Reset class
statusDiv.innerText = 'Sending command...';
try {
const response = await fetch('/trigger', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `sequence_id=${sequenceId}`
});
const data = await response.text();
if (response.ok) {
statusDiv.className = 'status-message status-success';
statusDiv.innerText = `Success: ${data}`;
} else {
statusDiv.className = 'status-message status-error';
statusDiv.innerText = `Error: ${data}`;
}
} catch (error) {
statusDiv.className = 'status-message status-error';
statusDiv.innerText = `Network or fetch error: ${error.message}`;
console.error('Fetch error:', error);
}
}
</script>
</body>
</html>
"""
# --- End of HTML Template Content ---
# Create templates directory and index.html file if they don't exist
def create_html_template():
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
os.makedirs(template_dir, exist_ok=True)
html_file_path = os.path.join(template_dir, 'index.html')
if not os.path.exists(html_file_path):
with open(html_file_path, 'w') as f:
f.write(HTML_CONTENT)
print(f"Created {html_file_path}")
def run_usc_command(command_args):
"""
Executes a UscCmd command and returns its output.
This function includes the --device flag to ensure the correct Maestro is targeted.
"""
# Check if UscCmd executable exists
if not os.path.exists(USCCMD_PATH) or not os.access(USCCMD_PATH, os.X_OK):
return f"Error: UscCmd not found or not executable at {USCCMD_PATH}. Please check the path and permissions.", False
# Construct the full command
cmd = [USCCMD_PATH, "--device", MAESTRO_DEVICE_ID] + command_args
print(f"Executing Maestro command: {' '.join(cmd)}")
try:
# It's good practice to stop any currently running script before starting a new one.
# This prevents potential conflicts if a script was left running.
# Ensure --stop also uses the --device flag.
stop_cmd = [USCCMD_PATH, "--device", MAESTRO_DEVICE_ID, "--stop"]
subprocess.run(stop_cmd, check=True, capture_output=True, text=True)
print("Stopped any active Maestro script.")
# Execute the main command (e.g., --sub 0)
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
print("Maestro command output:")
print(result.stdout)
if result.stderr:
print("Maestro command error output (stderr):")
print(result.stderr)
# Check for error indicators in stdout (UscCmd often prints errors to stdout)
if "ERROR" in result.stdout.upper() or "FAILED" in result.stdout.upper():
return f"Maestro reported errors: {result.stdout}", False
return result.stdout.strip(), True
except subprocess.CalledProcessError as e:
# This handles cases where UscCmd returns a non-zero exit code
print(f"ERROR executing Maestro command (CalledProcessError): {e}")
print(f"Stdout: {e.stdout}")
print(f"Stderr: {e.stderr}")
return f"Error executing command: {e.stderr or e.stdout}", False
except Exception as e:
# Catch any other unexpected errors
print(f"An unexpected error occurred: {e}")
return f"An unexpected error occurred: {e}", False
@app.route('/')
def index():
# Ensure the HTML template is created when the app starts or is accessed
create_html_template()
return render_template('index.html')
@app.route('/trigger', methods=['POST'])
def trigger_sequence():
sequence_id = request.form.get('sequence_id')
if sequence_id is None:
return "Error: Missing sequence_id", 400
print(f"Received web request: Triggering Maestro Sequence (Subroutine) {sequence_id}")
# Map sequence_id to the appropriate Maestro subroutine call
if sequence_id == '0':
output, success = run_usc_command(["--sub", "0"])
elif sequence_id == '1':
# Subroutine 1 is currently empty in your Maestro script, but the command is valid.
output, success = run_usc_command(["--sub", "1"])
# You can add more 'elif' blocks here for _sub2, _sub3, etc.
# elif sequence_id == '2':
# output, success = run_usc_command(["--sub", "2"])
else:
return "Invalid sequence ID", 400
if success:
return output, 200
else:
# For HTTP 500, the Flask client might not show the full message automatically
# but it helps in debugging. The JS will also catch this.
return output, 500
if __name__ == '__main__':
# When running the Flask app on a Raspberry Pi that accesses USB devices,
# you often need root privileges, or you need to set up udev rules.
# Running with 'sudo python3 app.py' is the common quick start method.
# For a more permanent solution, consider a udev rule:
# 1. Find vendor/product ID: lsusb (e.g., 1ffb:0089 for Pololu Micro Maestro)
# 2. Create /etc/udev/rules.d/50-pololu.rules with content:
# SUBSYSTEM=="usb", ATTR{idVendor}=="1ffb", ATTR{idProduct}=="0089", MODE="0666"
# 3. sudo udevadm control --reload-rules && sudo udevadm trigger
# 4. Unplug/replug Maestro. Then you might not need sudo for app.py
app.run(host='0.0.0.0', port=5000, debug=False)
this is the script i have on the micro maestro board # Subroutine 0: Moves Servo 0 through a range
_sub0:
6000 0 servo # Move servo 0 to center (quarter-microseconds)
1000 delay # Wait 1 second (milliseconds)
4000 0 servo # Move servo 0 to position 4000
1000 delay # Wait 1 second
8000 0 servo # Move servo 0 to position 8000
1000 delay # Wait 1 second
6000 0 servo # Move servo 0 back to center
return # Return from this subroutine
but i cant get any movement from servos they work ok when in command centre on pc with sliders and sequences
i can run this command with ssh /home/neil/Desktop/maestro-linux/UscCmd --servo 0,8000
and servo moves any help thanks