Skip to content

Commit 92f37b9

Browse files
author
Stefano Bertelli
committed
fix: add help pages
1 parent 9089554 commit 92f37b9

54 files changed

Lines changed: 1104 additions & 47 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![Discord](https://img.shields.io/discord/1386014070632878100?style=social)](https://discord.gg/EDtgj7Yayr) [![Shop at Provvedo](https://img.shields.io/badge/Shop-Provvedo-blue?logo=shopify&style=flat-square)](https://www.provvedo.com/shop)
44

5-
A **Kivy-based Digital Read-Out (DRO) and single-axis controller UI** for rotary tables and similar devices, designed to run on Raspberry Pi or desktop environments (Windows, macOS, Linux). Interfaces via RS-485 with a dedicated STM32-based control board.
5+
A **Kivy-based Digital Read-Out (DRO) and single-axis controller UI** for rotary tables and similar devices, designed to run on Raspberry Pi or desktop environments (Windows, macOS, Linux). Interfaces via RS-485/Modbus RTU with a dedicated STM32-based control board.
66

77
🛒 **Purchase all boards from our shop:** [Provvedo Shop](https://www.provvedo.com/shop)
88

@@ -11,25 +11,30 @@ A **Kivy-based Digital Read-Out (DRO) and single-axis controller UI** for rotary
1111
## 🚀 Features
1212

1313
* Responsive touch-capable UI built with **Kivy**
14-
* Communicates over **RS-485** with an STM32 controller for stepper/encoder control ([github.com][1])
15-
* Works on Raspberry Pi 3/4, Windows, macOS, and Linux
16-
* Runs headless on Pi using the custom **OSPI** OS with pre-installed RCP ([github.com][1])
14+
* Communicates over **RS-485 Modbus RTU** with an STM32 controller ([rotary-controller-f4](https://github.com/bartei/rotary-controller-f4))
15+
* **Configurable axes** — add/remove axes, assign hardware scale inputs, apply transforms (identity, scaling, weighted sum, angle cos/sin)
16+
* **Electronic Lead Screw (ELS)** mode for synchronized threading and power feed on manual lathes
17+
* **Sync mode** with configurable gear ratios for spindle-synchronized movement
18+
* **Circle pattern calculator** for bolt hole patterns
19+
* Customizable display: fonts, colors, digit formats (metric/imperial/angle)
20+
* **Contextual help** — info button on every setting field with documentation and examples
21+
* Works on Raspberry Pi 3/4/5, Windows, macOS, and Linux
22+
* Runs headless on Pi using the custom **OSPI** OS with pre-installed RCP ([ospi](https://github.com/bartei/ospi))
1723

1824
---
1925

2026
## 🎯 Requirements
2127

2228
* **Hardware**
2329

24-
* Rotary controller board (STM32 firmware from `bartei/rotary-controller-f4`)
30+
* Rotary controller board (STM32 firmware from [rotary-controller-f4](https://github.com/bartei/rotary-controller-f4))
2531
* RS-485 interface (e.g. via Power Hat)
26-
* Raspberry Pi 3/4 for Pi deployments
32+
* Raspberry Pi 3/4/5 for Pi deployments
2733

2834
* **Software**
2935

30-
* Python 3.8+
31-
* `uv` virtual environment manager
32-
* `kivy`, `pyserial`, and other dependencies from `pyproject.toml`
36+
* Python 3.10+
37+
* [`uv`](https://docs.astral.sh/uv/) package manager
3338

3439
---
3540

@@ -50,19 +55,24 @@ Install `uv` (Linux/macOS):
5055
curl -LsSf https://astral.sh/uv/install.sh | sh
5156
```
5257

53-
For Windows, follow instructions on the \[Astral uv docs].
58+
For Windows, see the [uv installation docs](https://docs.astral.sh/uv/getting-started/installation/).
5459

55-
### 3. Create & Sync Virtual Environment
60+
### 3. Install Dependencies
5661

5762
```bash
58-
uv venv # creates .venv/
59-
uv sync # installs required dependencies
63+
uv sync
6064
```
6165

6266
### 4. Run the App
6367

6468
```bash
65-
uv run python ./rcp/main.py
69+
uv run python -m rcp.main
70+
```
71+
72+
### 5. Run Tests
73+
74+
```bash
75+
uv run pytest
6676
```
6777

6878
---
@@ -71,9 +81,9 @@ uv run python ./rcp/main.py
7181

7282
### Windows/macOS/Linux
7383

74-
* Use Python >=3.8
75-
* Virtual environment recommended via `uv`
76-
* Ensure `pyserial` can access your RS-485 adapter (permissions on Linux/macOS)
84+
* Python >= 3.10
85+
* Virtual environment managed automatically by `uv`
86+
* Ensure your RS-485 adapter is accessible (check serial port permissions on Linux/macOS)
7787

7888
### Raspberry Pi & OSPI
7989

@@ -98,18 +108,47 @@ uv run python ./rcp/main.py
98108

99109
---
100110

111+
## 📂 Project Structure
112+
113+
```
114+
rcp/
115+
├── main.py # Entry point (asyncio + Kivy event loop)
116+
├── app.py # MainApp class
117+
├── feeds.py # Feed/thread pitch configurations
118+
├── help/ # Contextual help documents (markdown)
119+
├── components/ # UI layer
120+
│ ├── home/ # Home screen (coordbar, servobar, elsbar, statusbar)
121+
│ ├── screens/ # Full-screen views (setup, scale, servo, formats, etc.)
122+
│ ├── widgets/ # Reusable form widgets with help button support
123+
│ ├── popups/ # Modal dialogs (keypad, help, feeds table, etc.)
124+
│ ├── toolbars/ # Toolbar buttons
125+
│ └── plot/ # Plot/visualization
126+
├── dispatchers/ # Event dispatchers and state management
127+
│ ├── saving_dispatcher.py # Auto-persisting properties to YAML
128+
│ ├── formats.py # Display format settings
129+
│ ├── circle_pattern.py # Circle pattern calculator
130+
│ └── board.py # Board/device event dispatcher
131+
└── utils/ # Hardware communication layer
132+
├── communication.py # ConnectionManager (Modbus RTU)
133+
├── base_device.py # C typedef parser and register I/O
134+
└── devices.py # Device type definitions
135+
```
136+
137+
---
138+
101139
## 🛠️ Troubleshooting
102140

103141
* **Serial issues**: Verify RS-485 wiring, correct serial port, and permissions
104-
* **Service failures (Pi)**: Check `journalctl` logs and Kivy log files, check the /var/log folder for OSPI release
142+
* **Service failures (Pi)**: Check `journalctl` logs and Kivy log files under `/var/log/`
143+
* **Display issues**: Adjust font size and display format in the Formats setup screen
105144

106145
---
107146

108147
## 📚 References & Related Projects
109148

110-
* **Firmware & hardware:** \[rotary-controller-f4] ([github.com][3])
111-
* **PCB design & BOM:** \[rotary-controller-pcb] ([github.com][4])
112-
* **OSPI OS with pre-installed RCP:** \[ospi] ([github.com][2])
149+
* **Firmware & hardware:** [rotary-controller-f4](https://github.com/bartei/rotary-controller-f4)
150+
* **PCB design & BOM:** [rotary-controller-pcb](https://github.com/bartei/rotary-controller-pcb)
151+
* **OSPI OS with pre-installed RCP:** [ospi](https://github.com/bartei/ospi)
113152

114153
---
115154

@@ -131,21 +170,10 @@ Contributions are welcome! Please:
131170

132171
## 🏆 Support
133172

134-
Join our Discord community for support, collaboration, and updates.
173+
Join our [Discord community](https://discord.gg/EDtgj7Yayr) for support, collaboration, and updates.
135174

136175
---
137176

138177
## 📄 License
139178

140-
Licensed under MIT. See `LICENSE` for full terms.
141-
142-
---
143-
144-
*README last updated: June 23, 2025*
145-
146-
---
147-
148-
[1]: https://github.com/bartei/rotary-controller-python"
149-
[2]: https://github.com/bartei/ospi"
150-
[3]: https://github.com/bartei/rotary-controller-f4"
151-
[4]: https://github.com/bartei/rotary-controller-pcb"
179+
Licensed under MIT. See `LICENSE` for full terms.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<HelpPopup>:
2+
size_hint: 0.85, 0.85
3+
auto_dismiss: True
4+
5+
BoxLayout:
6+
orientation: "vertical"
7+
padding: 10
8+
spacing: 8
9+
10+
ScrollView:
11+
do_scroll_x: False
12+
do_scroll_y: True
13+
14+
Label:
15+
text: root.help_text
16+
size_hint_y: None
17+
height: self.texture_size[1] + 20
18+
text_size: self.width, None
19+
font_size: 16
20+
halign: "left"
21+
valign: "top"
22+
markup: False
23+
24+
Button:
25+
size_hint_y: None
26+
height: 50
27+
text: "Close"
28+
on_release: root.dismiss()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from kivy.logger import Logger
2+
from kivy.properties import StringProperty
3+
from kivy.uix.modalview import ModalView
4+
5+
from rcp.utils.kv_loader import load_kv
6+
7+
log = Logger.getChild(__name__)
8+
load_kv(__file__)
9+
10+
11+
class HelpPopup(ModalView):
12+
help_text = StringProperty("")
13+
14+
@staticmethod
15+
def show_help(help_file: str):
16+
if not help_file:
17+
return
18+
from rcp.app import MainApp
19+
app = MainApp.get_running_app()
20+
text = app.load_help(help_file)
21+
popup = HelpPopup(help_text=text)
22+
popup.open()

rcp/components/screens/axis_screen.kv

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@
2424
StringItem:
2525
name: "Axis Name"
2626
value: root.axis.axis_name if root.axis else "?"
27+
help_file: "axis_name.md"
2728
on_value: root.axis.axis_name = self.value
2829
BooleanItem:
2930
name: "Spindle Mode"
3031
value: root.axis.spindleMode if root.axis else False
32+
help_file: "spindle_mode.md"
3133
on_value: root.axis.spindleMode = self.value
3234

3335
TitleItem:
@@ -36,11 +38,13 @@
3638
name: "Sync Ratio Numerator"
3739
value: root.axis.syncRatioNum if root.axis else 360
3840
integer: True
41+
help_file: "sync_ratio.md"
3942
on_value: root.axis.syncRatioNum = int(self.value)
4043
NumberItem:
4144
name: "Sync Ratio Denominator"
4245
value: root.axis.syncRatioDen if root.axis else 100
4346
integer: True
47+
help_file: "sync_ratio.md"
4448
on_value: root.axis.syncRatioDen = int(self.value)
4549

4650
TitleItem:
@@ -49,12 +53,14 @@
4953
name: "Transform Type"
5054
value: root.transform_type_label
5155
options: ["Identity", "Scaling", "Weighted Sum", "Angle Cos", "Angle Sin"]
56+
help_file: "transform_type.md"
5257
on_value: root.transform_type_label = self.value
5358

5459
DropDownItem:
5560
name: "Scale Input"
5661
options: root.input_0_options
5762
value: root.input_0
63+
help_file: "scale_input.md"
5864
on_value: root.input_0 = self.value
5965

6066
# Scaling params
@@ -63,12 +69,14 @@
6369
name: "Weight Numerator"
6470
value: root.weight_num
6571
integer: True
72+
help_file: "weights.md"
6673
on_value: root.weight_num = int(self.value)
6774
NumberItem:
6875
disabled: root.transform_type_label not in ["Scaling", "Weighted Sum"]
6976
name: "Weight Denominator"
7077
value: root.weight_den
7178
integer: True
79+
help_file: "weights.md"
7280
on_value: root.weight_den = int(self.value)
7381

7482
# Weighted Sum second input
@@ -77,25 +85,29 @@
7785
name: "Second Scale Input"
7886
options: root.input_1_options
7987
value: root.input_1
88+
help_file: "scale_input.md"
8089
on_value: root.input_1 = self.value
8190
NumberItem:
8291
disabled: root.transform_type_label != "Weighted Sum"
8392
name: "Second Weight Numerator"
8493
value: root.weight_1_num
8594
integer: True
95+
help_file: "weights.md"
8696
on_value: root.weight_1_num = int(self.value)
8797
NumberItem:
8898
disabled: root.transform_type_label != "Weighted Sum"
8999
name: "Second Weight Denominator"
90100
value: root.weight_1_den
91101
integer: True
102+
help_file: "weights.md"
92103
on_value: root.weight_1_den = int(self.value)
93104

94105
# Angle params
95106
NumberItem:
96107
disabled: root.transform_type_label not in ["Angle Cos", "Angle Sin"]
97108
name: "Angle (degrees)"
98109
value: root.angle_degrees
110+
help_file: "angle_degrees.md"
99111
on_value: root.angle_degrees = self.value
100112

101113
BoxLayout:

rcp/components/screens/els_setup_screen.kv

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,15 @@
2323
DropDownItem:
2424
id: spindle_dropdown
2525
name: "Spindle Axis"
26+
help_file: "els_axis_roles.md"
2627
on_value: root.on_spindle_selected(self, self.value)
2728
DropDownItem:
2829
id: z_dropdown
2930
name: "Saddle Axis (Z)"
31+
help_file: "els_axis_roles.md"
3032
on_value: root.on_z_selected(self, self.value)
3133
DropDownItem:
3234
id: x_dropdown
3335
name: "Cross Slide Axis (X)"
36+
help_file: "els_axis_roles.md"
3437
on_value: root.on_x_selected(self, self.value)

0 commit comments

Comments
 (0)